|
| 1 | +/***********************************************************************| |
| 2 | +| TinyWSoftware i2c master library for ATtiny13 | |
| 3 | +| | |
| 4 | +| i2c_oled.ino (by Dhiru Kholia - VU3CER) | |
| 5 | +| | |
| 6 | +| Based on https://github.com/wagiminator/ATtiny13-TinyOLEDdemo (by | |
| 7 | +| Stefan Wagner - wagiminator) | |
| 8 | +| | |
| 9 | +| In this example we drive a 0.96" OLED Display Module over I2C. | |
| 10 | +| | |
| 11 | +| SERIAL REMINDER | |
| 12 | +| The baud rate is ignored on the ATtiny13 due to using a simplified | |
| 13 | +| serial. The baud rate used is dependent on the processor speed. | |
| 14 | +| Note that you can specify a custom baud rate if the following ones | |
| 15 | +| does not fit your application. | |
| 16 | +| | |
| 17 | +| THESE CLOCKS USES 115200 BAUD: THIS CLOCK USES 57600 BAUD: | |
| 18 | +| 20 MHz, 16 MHz, 9.6 MHz, 8 MHz 4.8 MHz | |
| 19 | +| THESE CLOCKS USES 19200 BAUD: THIS CLOCK USES 9600 BAUD: | |
| 20 | +| 1.2 MHz, 1 MHz 600 KHz | |
| 21 | +| | |
| 22 | +| If you get garbage output: | |
| 23 | +| 1. Check baud rate as above | |
| 24 | +| 2. Check if you have anything else connected to TX/RX like an LED | |
| 25 | +| 3. Check OSCCAL (see MicroCore OSCCAL tuner example) | |
| 26 | +|***********************************************************************/ |
| 27 | + |
| 28 | +#include <TinyWire.h> |
| 29 | + |
| 30 | +// We have to define which pins to use for SDA and SCL |
| 31 | +const uint8_t TinyWire::SCL = 3; |
| 32 | +const uint8_t TinyWire::SDA = 4; |
| 33 | + |
| 34 | +// Sets the i2c clock speed in [Hz] |
| 35 | +// Use MAX_SPEED for the highest possible clock speed |
| 36 | +const uint32_t TinyWire::FREQ = 100000; |
| 37 | + |
| 38 | +// OLED definitions |
| 39 | +#define OLED_ADDR 0x3C // OLED write address - for '0.96" OLED Display Module' |
| 40 | +#define OLED_CMD_MODE 0x00 // set command mode |
| 41 | +#define OLED_DAT_MODE 0x40 // set data mode |
| 42 | +#define OLED_INIT_LEN 14 // 12: no screen flip, 14: screen flip |
| 43 | + |
| 44 | +// OLED init settings |
| 45 | +const uint8_t OLED_INIT_CMD[] PROGMEM = { |
| 46 | + 0xA8, 0x1F, // set multiplex (HEIGHT-1): 0x1F for 128x32, 0x3F for 128x64 |
| 47 | + 0x22, 0x00, 0x03, // set min and max page |
| 48 | + 0x20, 0x00, // set horizontal memory addressing mode |
| 49 | + 0xDA, 0x02, // set COM pins hardware configuration to sequential |
| 50 | + 0x8D, 0x14, // enable charge pump |
| 51 | + 0xAF, // switch on OLED |
| 52 | + 0xA1, 0xC8 // flip the screen |
| 53 | +}; |
| 54 | + |
| 55 | +// standard ASCII 5x8 font (adapted from Neven Boyanov and Stephen Denne) |
| 56 | +const uint8_t OLED_FONT[] PROGMEM = { |
| 57 | + 0x00, 0x00, 0x00, 0x00, 0x00, // 0 |
| 58 | + 0x00, 0x00, 0x2f, 0x00, 0x00, // ! 1 |
| 59 | + 0x00, 0x07, 0x00, 0x07, 0x00, // " 2 |
| 60 | + 0x14, 0x7f, 0x14, 0x7f, 0x14, // # 3 |
| 61 | + 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $ 4 |
| 62 | + 0x62, 0x64, 0x08, 0x13, 0x23, // % 5 |
| 63 | + 0x36, 0x49, 0x55, 0x22, 0x50, // & 6 |
| 64 | + 0x00, 0x05, 0x03, 0x00, 0x00, // ' 7 |
| 65 | + 0x00, 0x1c, 0x22, 0x41, 0x00, // ( 8 |
| 66 | + 0x00, 0x41, 0x22, 0x1c, 0x00, // ) 9 |
| 67 | + 0x14, 0x08, 0x3E, 0x08, 0x14, // * 10 |
| 68 | + 0x08, 0x08, 0x3E, 0x08, 0x08, // + 11 |
| 69 | + 0x00, 0x00, 0xA0, 0x60, 0x00, // , 12 |
| 70 | + 0x08, 0x08, 0x08, 0x08, 0x08, // - 13 |
| 71 | + 0x00, 0x60, 0x60, 0x00, 0x00, // . 14 |
| 72 | + 0x20, 0x10, 0x08, 0x04, 0x02, // / 15 |
| 73 | + 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 16 |
| 74 | + 0x00, 0x42, 0x7F, 0x40, 0x00, // 1 17 |
| 75 | + 0x42, 0x61, 0x51, 0x49, 0x46, // 2 18 |
| 76 | + 0x21, 0x41, 0x45, 0x4B, 0x31, // 3 19 |
| 77 | + 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 20 |
| 78 | + 0x27, 0x45, 0x45, 0x45, 0x39, // 5 21 |
| 79 | + 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6 22 |
| 80 | + 0x01, 0x71, 0x09, 0x05, 0x03, // 7 23 |
| 81 | + 0x36, 0x49, 0x49, 0x49, 0x36, // 8 24 |
| 82 | + 0x06, 0x49, 0x49, 0x29, 0x1E, // 9 25 |
| 83 | + 0x00, 0x36, 0x36, 0x00, 0x00, // : 26 |
| 84 | + 0x00, 0x56, 0x36, 0x00, 0x00, // ; 27 |
| 85 | + 0x08, 0x14, 0x22, 0x41, 0x00, // < 28 |
| 86 | + 0x14, 0x14, 0x14, 0x14, 0x14, // = 29 |
| 87 | + 0x00, 0x41, 0x22, 0x14, 0x08, // > 30 |
| 88 | + 0x02, 0x01, 0x51, 0x09, 0x06, // ? 31 |
| 89 | + 0x32, 0x49, 0x59, 0x51, 0x3E, // @ 32 |
| 90 | + 0x7C, 0x12, 0x11, 0x12, 0x7C, // A 33 |
| 91 | + 0x7F, 0x49, 0x49, 0x49, 0x36, // B 34 |
| 92 | + 0x3E, 0x41, 0x41, 0x41, 0x22, // C 35 |
| 93 | + 0x7F, 0x41, 0x41, 0x22, 0x1C, // D 36 |
| 94 | + 0x7F, 0x49, 0x49, 0x49, 0x41, // E 37 |
| 95 | + 0x7F, 0x09, 0x09, 0x09, 0x01, // F 38 |
| 96 | + 0x3E, 0x41, 0x49, 0x49, 0x7A, // G 39 |
| 97 | + 0x7F, 0x08, 0x08, 0x08, 0x7F, // H 40 |
| 98 | + 0x00, 0x41, 0x7F, 0x41, 0x00, // I 41 |
| 99 | + 0x20, 0x40, 0x41, 0x3F, 0x01, // J 42 |
| 100 | + 0x7F, 0x08, 0x14, 0x22, 0x41, // K 43 |
| 101 | + 0x7F, 0x40, 0x40, 0x40, 0x40, // L 44 |
| 102 | + 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M 45 |
| 103 | + 0x7F, 0x04, 0x08, 0x10, 0x7F, // N 46 |
| 104 | + 0x3E, 0x41, 0x41, 0x41, 0x3E, // O 47 |
| 105 | + 0x7F, 0x09, 0x09, 0x09, 0x06, // P 48 |
| 106 | + 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q 49 |
| 107 | + 0x7F, 0x09, 0x19, 0x29, 0x46, // R 50 |
| 108 | + 0x46, 0x49, 0x49, 0x49, 0x31, // S 51 |
| 109 | + 0x01, 0x01, 0x7F, 0x01, 0x01, // T 52 |
| 110 | + 0x3F, 0x40, 0x40, 0x40, 0x3F, // U 53 |
| 111 | + 0x1F, 0x20, 0x40, 0x20, 0x1F, // V 54 |
| 112 | + 0x3F, 0x40, 0x38, 0x40, 0x3F, // W 55 |
| 113 | + 0x63, 0x14, 0x08, 0x14, 0x63, // X 56 |
| 114 | + 0x07, 0x08, 0x70, 0x08, 0x07, // Y 57 |
| 115 | + 0x61, 0x51, 0x49, 0x45, 0x43, // Z 58 |
| 116 | + 0x00, 0x7F, 0x41, 0x41, 0x00, // [ 59 |
| 117 | + 0x02, 0x04, 0x08, 0x10, 0x20, // \ 60 |
| 118 | + 0x00, 0x41, 0x41, 0x7F, 0x00, // ] 61 |
| 119 | + 0x04, 0x02, 0x01, 0x02, 0x04, // ^ 62 |
| 120 | + 0x40, 0x40, 0x40, 0x40, 0x40 // _ 63 |
| 121 | +}; |
| 122 | + |
| 123 | +// messages to print on OLED |
| 124 | +const char Message1[] PROGMEM = "HELLO WORLD! :)"; |
| 125 | + |
| 126 | +// OLED init function |
| 127 | +void OLED_init(void) { |
| 128 | + Wire.beginTransmission(OLED_ADDR); |
| 129 | + Wire.write(OLED_CMD_MODE); // set command mode |
| 130 | + for (uint8_t i = 0; i < OLED_INIT_LEN; i++) |
| 131 | + Wire.write(pgm_read_byte(&OLED_INIT_CMD[i])); // send the command bytes |
| 132 | + Wire.endTransmission(); // initialize I2C first |
| 133 | +} |
| 134 | + |
| 135 | +// OLED set vertical shift |
| 136 | +void OLED_shift(uint8_t ypos) { |
| 137 | + Wire.beginTransmission(OLED_ADDR); // start transmission to OLED |
| 138 | + Wire.write(OLED_CMD_MODE); // set command mode |
| 139 | + Wire.write(0xD3); // vertical shift command |
| 140 | + Wire.write(ypos); // set vertical shift value |
| 141 | + Wire.endTransmission(); // stop transmission |
| 142 | +} |
| 143 | + |
| 144 | +// OLED print a character |
| 145 | +void OLED_printC(char ch) { |
| 146 | + uint16_t offset = ch - 32; // calculate position of character in font array |
| 147 | + offset += offset << 2; // -> offset = (ch - 32) * 5 |
| 148 | + Wire.write(0x00); // print spacing between characters |
| 149 | + for (uint8_t i = 5; i; i--) Wire.write(pgm_read_byte(&OLED_FONT[offset++])); // print character |
| 150 | +} |
| 151 | + |
| 152 | +// OLED print a string from program memory |
| 153 | +void OLED_printP(const char* p) { |
| 154 | + Wire.beginTransmission(OLED_ADDR); // start transmission to OLED |
| 155 | + Wire.write(OLED_DAT_MODE); // set data mode |
| 156 | + char ch = pgm_read_byte(p); // read first character from program memory |
| 157 | + while (ch != 0) { // repeat until string terminator |
| 158 | + OLED_printC(ch); // print character on OLED |
| 159 | + ch = pgm_read_byte(++p); // read next character |
| 160 | + } |
| 161 | + Wire.endTransmission(); // stop transmission |
| 162 | +} |
| 163 | + |
| 164 | +// OLED set the cursor |
| 165 | +void OLED_cursor(uint8_t xpos, uint8_t ypos) { |
| 166 | + Wire.beginTransmission(OLED_ADDR); // start transmission to OLED |
| 167 | + Wire.write(OLED_CMD_MODE); // set command mode |
| 168 | + Wire.write(xpos & 0x0F); // set low nibble of start column |
| 169 | + Wire.write(0x10 | (xpos >> 4)); // set high nibble of start column |
| 170 | + Wire.write(0xB0 | (ypos & 0x07)); // set start page |
| 171 | + Wire.endTransmission(); // stop transmission |
| 172 | +} |
| 173 | + |
| 174 | +// OLED clear screen |
| 175 | +void OLED_clear(void) { |
| 176 | + OLED_cursor(0, 0); // set cursor at upper left corner |
| 177 | + Wire.beginTransmission(OLED_ADDR); // start transmission to OLED |
| 178 | + Wire.write(OLED_DAT_MODE); // set data mode |
| 179 | + for (uint16_t i = 512; i; i--) Wire.write(0x00); // clear the screen |
| 180 | + Wire.endTransmission(); // stop transmission |
| 181 | + OLED_shift(0); // reset vertical shift |
| 182 | +} |
| 183 | + |
| 184 | +void setup() |
| 185 | +{ |
| 186 | + // No baudrate to select. See header for details |
| 187 | + Serial.begin(); |
| 188 | + Serial.println(F("Check you OLED screen...")); |
| 189 | + OLED_init(); |
| 190 | +} |
| 191 | + |
| 192 | +void loop() |
| 193 | +{ |
| 194 | + while (1) { |
| 195 | + OLED_clear(); // clear screen |
| 196 | + OLED_cursor(0, 0); // set cursor position |
| 197 | + OLED_printP(Message1); // print message 1 |
| 198 | + delay(5000); |
| 199 | + } |
| 200 | +} |
0 commit comments