A simple library for SSH1106 controlled GLCDs
SSH1106.cpp@0:3cd0a11a2f91, 2016-12-19 (annotated)
- Committer:
- Anaesthetix
- Date:
- Mon Dec 19 15:02:30 2016 +0000
- Revision:
- 0:3cd0a11a2f91
- Child:
- 1:ac9efaadd666
-
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Anaesthetix | 0:3cd0a11a2f91 | 1 | /** |
Anaesthetix | 0:3cd0a11a2f91 | 2 | * This is a simple library for SSH1106 controlled graphic LCD's. |
Anaesthetix | 0:3cd0a11a2f91 | 3 | * Written for a cheap 1.3" OLED GLCD |
Anaesthetix | 0:3cd0a11a2f91 | 4 | * See http://www.dx.com/p/open-smart-1-8-128-64-lcd-display-breakout-module-w-blue-backlit-444694 |
Anaesthetix | 0:3cd0a11a2f91 | 5 | * |
Anaesthetix | 0:3cd0a11a2f91 | 6 | * Written by: Erik van de Coevering |
Anaesthetix | 0:3cd0a11a2f91 | 7 | * With thanks to Tim Barr from whom I've reused some code |
Anaesthetix | 0:3cd0a11a2f91 | 8 | * Use this code in whatever way you like, as long as it stays free of charge! |
Anaesthetix | 0:3cd0a11a2f91 | 9 | */ |
Anaesthetix | 0:3cd0a11a2f91 | 10 | |
Anaesthetix | 0:3cd0a11a2f91 | 11 | #include "SSH1106.h" |
Anaesthetix | 0:3cd0a11a2f91 | 12 | |
Anaesthetix | 0:3cd0a11a2f91 | 13 | SSH1106::SSH1106(SPI &lcd, DigitalOut &lcd_cs, DigitalOut &lcd_cd, DigitalOut &lcd_rst) |
Anaesthetix | 0:3cd0a11a2f91 | 14 | { |
Anaesthetix | 0:3cd0a11a2f91 | 15 | _lcd = &lcd; |
Anaesthetix | 0:3cd0a11a2f91 | 16 | _lcd_cs = &lcd_cs; |
Anaesthetix | 0:3cd0a11a2f91 | 17 | _lcd_cd = &lcd_cd; |
Anaesthetix | 0:3cd0a11a2f91 | 18 | _lcd_rst = &lcd_rst; |
Anaesthetix | 0:3cd0a11a2f91 | 19 | } |
Anaesthetix | 0:3cd0a11a2f91 | 20 | |
Anaesthetix | 0:3cd0a11a2f91 | 21 | void SSH1106::init() |
Anaesthetix | 0:3cd0a11a2f91 | 22 | { |
Anaesthetix | 0:3cd0a11a2f91 | 23 | _lcd_cs->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 24 | _lcd->frequency(24000000); // Abusing SPI to save some time.. Try a lower freq if this doesn't work |
Anaesthetix | 0:3cd0a11a2f91 | 25 | _lcd->format(8,3); |
Anaesthetix | 0:3cd0a11a2f91 | 26 | _lcd_cs->write(0); // enable SPI |
Anaesthetix | 0:3cd0a11a2f91 | 27 | _lcd_cd->write(0); // COMMAND mode |
Anaesthetix | 0:3cd0a11a2f91 | 28 | |
Anaesthetix | 0:3cd0a11a2f91 | 29 | _lcd_rst->write(0); |
Anaesthetix | 0:3cd0a11a2f91 | 30 | wait_ms(100); |
Anaesthetix | 0:3cd0a11a2f91 | 31 | _lcd_rst->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 32 | |
Anaesthetix | 0:3cd0a11a2f91 | 33 | wait_ms(50); |
Anaesthetix | 0:3cd0a11a2f91 | 34 | |
Anaesthetix | 0:3cd0a11a2f91 | 35 | _lcd->write(0xAE); // Display off |
Anaesthetix | 0:3cd0a11a2f91 | 36 | _lcd->write(0x02); // Set lower column address |
Anaesthetix | 0:3cd0a11a2f91 | 37 | _lcd->write(0x10); // Set higher column address |
Anaesthetix | 0:3cd0a11a2f91 | 38 | _lcd->write(0x40); // Set display start line |
Anaesthetix | 0:3cd0a11a2f91 | 39 | _lcd->write(0xB0); // Set page address |
Anaesthetix | 0:3cd0a11a2f91 | 40 | _lcd->write(0x81); // Set contrast to |
Anaesthetix | 0:3cd0a11a2f91 | 41 | _lcd->write(0x80); // 128 |
Anaesthetix | 0:3cd0a11a2f91 | 42 | _lcd->write(0xA1); // Segment remap |
Anaesthetix | 0:3cd0a11a2f91 | 43 | _lcd->write(0xA6); // Inverse: normal (A7 = inverse) |
Anaesthetix | 0:3cd0a11a2f91 | 44 | _lcd->write(0xA8); // Multiplex ratio |
Anaesthetix | 0:3cd0a11a2f91 | 45 | _lcd->write(0x3F); // Duty = 1/32 |
Anaesthetix | 0:3cd0a11a2f91 | 46 | _lcd->write(0xAD); // Charge pump enable |
Anaesthetix | 0:3cd0a11a2f91 | 47 | _lcd->write(0x8B); // External VCC |
Anaesthetix | 0:3cd0a11a2f91 | 48 | _lcd->write(0x33); // VPP: 9v |
Anaesthetix | 0:3cd0a11a2f91 | 49 | _lcd->write(0xC8); // Com scan direction |
Anaesthetix | 0:3cd0a11a2f91 | 50 | _lcd->write(0xD3); // Display offset |
Anaesthetix | 0:3cd0a11a2f91 | 51 | _lcd->write(0x00); // 0x20 |
Anaesthetix | 0:3cd0a11a2f91 | 52 | _lcd->write(0xD5); // Osc division |
Anaesthetix | 0:3cd0a11a2f91 | 53 | _lcd->write(0x80); |
Anaesthetix | 0:3cd0a11a2f91 | 54 | _lcd->write(0xD9); // Pre-charge period |
Anaesthetix | 0:3cd0a11a2f91 | 55 | _lcd->write(0x1F); // 0x22 |
Anaesthetix | 0:3cd0a11a2f91 | 56 | _lcd->write(0xDA); // Set com pins |
Anaesthetix | 0:3cd0a11a2f91 | 57 | _lcd->write(0x12); |
Anaesthetix | 0:3cd0a11a2f91 | 58 | _lcd->write(0xDB); // Set vcomh |
Anaesthetix | 0:3cd0a11a2f91 | 59 | _lcd->write(0x40); |
Anaesthetix | 0:3cd0a11a2f91 | 60 | _lcd->write(0xAF); // Display ON |
Anaesthetix | 0:3cd0a11a2f91 | 61 | _lcd_cs->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 62 | _lcd_cd->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 63 | |
Anaesthetix | 0:3cd0a11a2f91 | 64 | } |
Anaesthetix | 0:3cd0a11a2f91 | 65 | |
Anaesthetix | 0:3cd0a11a2f91 | 66 | void SSH1106::setContrast(char contrast) |
Anaesthetix | 0:3cd0a11a2f91 | 67 | { |
Anaesthetix | 0:3cd0a11a2f91 | 68 | _lcd_cs->write(0); // enable SPI |
Anaesthetix | 0:3cd0a11a2f91 | 69 | _lcd_cd->write(0); // command mode |
Anaesthetix | 0:3cd0a11a2f91 | 70 | _lcd->write(0x81); // command to set contrast |
Anaesthetix | 0:3cd0a11a2f91 | 71 | _lcd->write(contrast); // set contrast |
Anaesthetix | 0:3cd0a11a2f91 | 72 | _lcd_cs->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 73 | _lcd_cd->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 74 | } |
Anaesthetix | 0:3cd0a11a2f91 | 75 | |
Anaesthetix | 0:3cd0a11a2f91 | 76 | void SSH1106::setCursor(char column, char line) |
Anaesthetix | 0:3cd0a11a2f91 | 77 | { |
Anaesthetix | 0:3cd0a11a2f91 | 78 | int i, j; |
Anaesthetix | 0:3cd0a11a2f91 | 79 | column = column+2; // column+4 |
Anaesthetix | 0:3cd0a11a2f91 | 80 | |
Anaesthetix | 0:3cd0a11a2f91 | 81 | i=(column&0xF0)>>4; |
Anaesthetix | 0:3cd0a11a2f91 | 82 | j=column&0x0F; |
Anaesthetix | 0:3cd0a11a2f91 | 83 | _lcd_cd->write(0); |
Anaesthetix | 0:3cd0a11a2f91 | 84 | _lcd->write(0xb0+line); |
Anaesthetix | 0:3cd0a11a2f91 | 85 | _lcd->write(0x10+i); |
Anaesthetix | 0:3cd0a11a2f91 | 86 | _lcd->write(j); |
Anaesthetix | 0:3cd0a11a2f91 | 87 | _lcd_cd->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 88 | } |
Anaesthetix | 0:3cd0a11a2f91 | 89 | |
Anaesthetix | 0:3cd0a11a2f91 | 90 | void SSH1106::clear() |
Anaesthetix | 0:3cd0a11a2f91 | 91 | { |
Anaesthetix | 0:3cd0a11a2f91 | 92 | _lcd_cs->write(0); |
Anaesthetix | 0:3cd0a11a2f91 | 93 | _lcd_cd->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 94 | |
Anaesthetix | 0:3cd0a11a2f91 | 95 | for(unsigned short j = 0; j < 8; j++) { |
Anaesthetix | 0:3cd0a11a2f91 | 96 | SSH1106::setCursor(0, j); |
Anaesthetix | 0:3cd0a11a2f91 | 97 | for(unsigned short i = 0; i < 128 ; i++) { |
Anaesthetix | 0:3cd0a11a2f91 | 98 | _lcd->write(0x00); |
Anaesthetix | 0:3cd0a11a2f91 | 99 | } |
Anaesthetix | 0:3cd0a11a2f91 | 100 | } |
Anaesthetix | 0:3cd0a11a2f91 | 101 | |
Anaesthetix | 0:3cd0a11a2f91 | 102 | SSH1106::setCursor(0, 0); |
Anaesthetix | 0:3cd0a11a2f91 | 103 | |
Anaesthetix | 0:3cd0a11a2f91 | 104 | _lcd_cs->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 105 | } |
Anaesthetix | 0:3cd0a11a2f91 | 106 | |
Anaesthetix | 0:3cd0a11a2f91 | 107 | void SSH1106::writeText2d(char column, char page, const char font_address[96][8], const char *text, int size) |
Anaesthetix | 0:3cd0a11a2f91 | 108 | { |
Anaesthetix | 0:3cd0a11a2f91 | 109 | _lcd_cs->write(0); |
Anaesthetix | 0:3cd0a11a2f91 | 110 | SSH1106::setCursor(column, page); |
Anaesthetix | 0:3cd0a11a2f91 | 111 | for(int i=0; i<size; i++) { |
Anaesthetix | 0:3cd0a11a2f91 | 112 | for(int a=0; a<8; a++) { |
Anaesthetix | 0:3cd0a11a2f91 | 113 | _lcd->write((font_address[(text[i]-32)][a])); |
Anaesthetix | 0:3cd0a11a2f91 | 114 | } |
Anaesthetix | 0:3cd0a11a2f91 | 115 | } |
Anaesthetix | 0:3cd0a11a2f91 | 116 | _lcd_cs->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 117 | } |
Anaesthetix | 0:3cd0a11a2f91 | 118 | |
Anaesthetix | 0:3cd0a11a2f91 | 119 | void SSH1106::writeText(char column, char page, const char *font_address, const char *text, const uint8_t size) |
Anaesthetix | 0:3cd0a11a2f91 | 120 | { |
Anaesthetix | 0:3cd0a11a2f91 | 121 | // Position of character data in memory array |
Anaesthetix | 0:3cd0a11a2f91 | 122 | uint16_t pos_array; |
Anaesthetix | 0:3cd0a11a2f91 | 123 | // temporary column, page address, and column_cnt are used |
Anaesthetix | 0:3cd0a11a2f91 | 124 | // to stay inside display area |
Anaesthetix | 0:3cd0a11a2f91 | 125 | uint8_t i,y, column_cnt = 0; |
Anaesthetix | 0:3cd0a11a2f91 | 126 | uint8_t count = 0; |
Anaesthetix | 0:3cd0a11a2f91 | 127 | |
Anaesthetix | 0:3cd0a11a2f91 | 128 | // font information, needed for calculation |
Anaesthetix | 0:3cd0a11a2f91 | 129 | uint8_t start_code, last_code, width, page_height, bytes_p_char; |
Anaesthetix | 0:3cd0a11a2f91 | 130 | |
Anaesthetix | 0:3cd0a11a2f91 | 131 | uint8_t *txtbuffer; |
Anaesthetix | 0:3cd0a11a2f91 | 132 | |
Anaesthetix | 0:3cd0a11a2f91 | 133 | start_code = font_address[2]; // get first defined character |
Anaesthetix | 0:3cd0a11a2f91 | 134 | last_code = font_address[3]; // get last defined character |
Anaesthetix | 0:3cd0a11a2f91 | 135 | width = font_address[4]; // width in pixel of one char |
Anaesthetix | 0:3cd0a11a2f91 | 136 | page_height = font_address[6]; // page count per char |
Anaesthetix | 0:3cd0a11a2f91 | 137 | bytes_p_char = font_address[7]; // bytes per char |
Anaesthetix | 0:3cd0a11a2f91 | 138 | |
Anaesthetix | 0:3cd0a11a2f91 | 139 | _lcd_cs->write(0); // Enable SPI |
Anaesthetix | 0:3cd0a11a2f91 | 140 | _lcd_cd->write(1); // Data mode |
Anaesthetix | 0:3cd0a11a2f91 | 141 | |
Anaesthetix | 0:3cd0a11a2f91 | 142 | if(page_height + page > LCDPAGES) //stay inside display area |
Anaesthetix | 0:3cd0a11a2f91 | 143 | page_height = LCDPAGES - page; |
Anaesthetix | 0:3cd0a11a2f91 | 144 | |
Anaesthetix | 0:3cd0a11a2f91 | 145 | // The string is displayed character after character. If the font has more then one page, |
Anaesthetix | 0:3cd0a11a2f91 | 146 | // the top page is printed first, then the next page and so on |
Anaesthetix | 0:3cd0a11a2f91 | 147 | for(y = 0; y < page_height; y++) { |
Anaesthetix | 0:3cd0a11a2f91 | 148 | txtbuffer = &_lcdbuffer[page*LCDWIDTH + column]; |
Anaesthetix | 0:3cd0a11a2f91 | 149 | column_cnt = 0; // clear column_cnt start point |
Anaesthetix | 0:3cd0a11a2f91 | 150 | i = 0; |
Anaesthetix | 0:3cd0a11a2f91 | 151 | while(( i < size) && ((column_cnt + column) < LCDWIDTH)) { |
Anaesthetix | 0:3cd0a11a2f91 | 152 | if(text[i] < start_code || (uint8_t)text[i] > last_code) //make sure data is valid |
Anaesthetix | 0:3cd0a11a2f91 | 153 | i++; |
Anaesthetix | 0:3cd0a11a2f91 | 154 | else { |
Anaesthetix | 0:3cd0a11a2f91 | 155 | // calculate position of ASCII character in font array |
Anaesthetix | 0:3cd0a11a2f91 | 156 | // bytes for header + (ASCII - startcode) * bytes per char) |
Anaesthetix | 0:3cd0a11a2f91 | 157 | pos_array = 8 + (uint8_t)(text[i++] - start_code) * bytes_p_char; |
Anaesthetix | 0:3cd0a11a2f91 | 158 | |
Anaesthetix | 0:3cd0a11a2f91 | 159 | // get the dot pattern for the part of the char to print |
Anaesthetix | 0:3cd0a11a2f91 | 160 | pos_array += y*width; |
Anaesthetix | 0:3cd0a11a2f91 | 161 | |
Anaesthetix | 0:3cd0a11a2f91 | 162 | // stay inside display area |
Anaesthetix | 0:3cd0a11a2f91 | 163 | if((column_cnt + width + column) > LCDWIDTH) |
Anaesthetix | 0:3cd0a11a2f91 | 164 | column_cnt = LCDWIDTH-width; |
Anaesthetix | 0:3cd0a11a2f91 | 165 | |
Anaesthetix | 0:3cd0a11a2f91 | 166 | // copy character data to buffer |
Anaesthetix | 0:3cd0a11a2f91 | 167 | memcpy (txtbuffer+column_cnt,font_address+pos_array,width); |
Anaesthetix | 0:3cd0a11a2f91 | 168 | } |
Anaesthetix | 0:3cd0a11a2f91 | 169 | |
Anaesthetix | 0:3cd0a11a2f91 | 170 | column_cnt += width; |
Anaesthetix | 0:3cd0a11a2f91 | 171 | } |
Anaesthetix | 0:3cd0a11a2f91 | 172 | SSH1106::setCursor(column,page); // set start position x and y |
Anaesthetix | 0:3cd0a11a2f91 | 173 | |
Anaesthetix | 0:3cd0a11a2f91 | 174 | do { |
Anaesthetix | 0:3cd0a11a2f91 | 175 | _lcd->write(txtbuffer[count]); |
Anaesthetix | 0:3cd0a11a2f91 | 176 | count++; |
Anaesthetix | 0:3cd0a11a2f91 | 177 | } while ((count <= column_cnt)); |
Anaesthetix | 0:3cd0a11a2f91 | 178 | } |
Anaesthetix | 0:3cd0a11a2f91 | 179 | |
Anaesthetix | 0:3cd0a11a2f91 | 180 | _lcd_cs->write(1); // Disable SPI |
Anaesthetix | 0:3cd0a11a2f91 | 181 | |
Anaesthetix | 0:3cd0a11a2f91 | 182 | } |
Anaesthetix | 0:3cd0a11a2f91 | 183 | |
Anaesthetix | 0:3cd0a11a2f91 | 184 | void SSH1106::drawBitmap(const char *data) |
Anaesthetix | 0:3cd0a11a2f91 | 185 | { |
Anaesthetix | 0:3cd0a11a2f91 | 186 | int cnt = 0; |
Anaesthetix | 0:3cd0a11a2f91 | 187 | _lcd_cs->write(0); |
Anaesthetix | 0:3cd0a11a2f91 | 188 | _lcd_cd->write(1); |
Anaesthetix | 0:3cd0a11a2f91 | 189 | SSH1106::setCursor(0,0); |
Anaesthetix | 0:3cd0a11a2f91 | 190 | for(int row=0; row<8; row++) { |
Anaesthetix | 0:3cd0a11a2f91 | 191 | SSH1106::setCursor(0, row); |
Anaesthetix | 0:3cd0a11a2f91 | 192 | for(int column=0; column<128; column++) { |
Anaesthetix | 0:3cd0a11a2f91 | 193 | _lcd->write(data[cnt]); |
Anaesthetix | 0:3cd0a11a2f91 | 194 | cnt++; |
Anaesthetix | 0:3cd0a11a2f91 | 195 | } |
Anaesthetix | 0:3cd0a11a2f91 | 196 | } |
Anaesthetix | 0:3cd0a11a2f91 | 197 | } |