A simple library for SSH1106 controlled GLCDs
Embed:
(wiki syntax)
Show/hide line numbers
SSH1106.cpp
00001 /** 00002 * This is a simple library for SSH1106 controlled graphic LCD's. 00003 * Written for a cheap 1.3" OLED GLCD 00004 * See http://www.dx.com/p/open-smart-1-8-128-64-lcd-display-breakout-module-w-blue-backlit-444694 00005 * 00006 * Written by: Erik van de Coevering 00007 * With thanks to Tim Barr from whom I've reused some code 00008 * Use this code in whatever way you like, as long as it stays free of charge! 00009 */ 00010 00011 #include "SSH1106.h" 00012 00013 SSH1106::SSH1106(SPI &lcd, DigitalOut &lcd_cs, DigitalOut &lcd_cd, DigitalOut &lcd_rst) 00014 { 00015 _lcd = &lcd; 00016 _lcd_cs = &lcd_cs; 00017 _lcd_cd = &lcd_cd; 00018 _lcd_rst = &lcd_rst; 00019 } 00020 00021 void SSH1106::init() 00022 { 00023 _lcd_cs->write(1); 00024 _lcd->frequency(24000000); // Abusing SPI to save some time.. Try a lower freq if this doesn't work 00025 _lcd->format(8,3); 00026 _lcd_cs->write(0); // enable SPI 00027 _lcd_cd->write(0); // COMMAND mode 00028 00029 _lcd_rst->write(0); 00030 wait_ms(100); 00031 _lcd_rst->write(1); 00032 00033 wait_ms(50); 00034 00035 _lcd->write(0xAE); // Display off 00036 _lcd->write(0x02); // Set lower column address 00037 _lcd->write(0x10); // Set higher column address 00038 _lcd->write(0x40); // Set display start line 00039 _lcd->write(0xB0); // Set page address 00040 _lcd->write(0x81); // Set contrast to 00041 _lcd->write(0x80); // 128 00042 _lcd->write(0xA1); // Segment remap 00043 _lcd->write(0xA6); // Inverse: normal (A7 = inverse) 00044 _lcd->write(0xA8); // Multiplex ratio 00045 _lcd->write(0x3F); // Duty = 1/32 00046 _lcd->write(0xAD); // Charge pump enable 00047 _lcd->write(0x8B); // External VCC 00048 _lcd->write(0x33); // VPP: 9v 00049 _lcd->write(0xC8); // Com scan direction 00050 _lcd->write(0xD3); // Display offset 00051 _lcd->write(0x00); // 0x20 00052 _lcd->write(0xD5); // Osc division 00053 _lcd->write(0x80); 00054 _lcd->write(0xD9); // Pre-charge period 00055 _lcd->write(0x1F); // 0x22 00056 _lcd->write(0xDA); // Set com pins 00057 _lcd->write(0x12); 00058 _lcd->write(0xDB); // Set vcomh 00059 _lcd->write(0x40); 00060 _lcd->write(0xAF); // Display ON 00061 _lcd_cs->write(1); 00062 _lcd_cd->write(1); 00063 } 00064 00065 void SSH1106::setContrast(char contrast) 00066 { 00067 _lcd_cs->write(0); // enable SPI 00068 _lcd_cd->write(0); // command mode 00069 _lcd->write(0x81); // command to set contrast 00070 _lcd->write(contrast); // set contrast 00071 _lcd_cs->write(1); 00072 _lcd_cd->write(1); 00073 } 00074 00075 void SSH1106::setCursor(char column, char line) 00076 { 00077 int i, j; 00078 column = column+2; // column+4 00079 00080 i=(column&0xF0)>>4; 00081 j=column&0x0F; 00082 _lcd_cd->write(0); 00083 _lcd->write(0xb0+line); 00084 _lcd->write(0x10+i); 00085 _lcd->write(j); 00086 _lcd_cd->write(1); 00087 } 00088 00089 void SSH1106::clear() 00090 { 00091 _lcd_cs->write(0); 00092 _lcd_cd->write(1); 00093 00094 for(unsigned short j = 0; j < LCDPAGES; j++) { 00095 SSH1106::setCursor(0, j); 00096 for(unsigned short i = 0; i < LCDWIDTH ; i++) { 00097 _lcd->write(0x00); 00098 } 00099 } 00100 00101 SSH1106::setCursor(0, 0); 00102 00103 _lcd_cs->write(1); 00104 } 00105 00106 void SSH1106::writeText2d(char column, char page, const char font_address[96][8], const char *text, int size) 00107 { 00108 _lcd_cs->write(0); 00109 SSH1106::setCursor(column, page); 00110 for(int i=0; i<size; i++) { 00111 for(int a=0; a<8; a++) { 00112 _lcd->write((font_address[(text[i]-32)][a])); 00113 } 00114 } 00115 _lcd_cs->write(1); 00116 } 00117 00118 void SSH1106::writeText(char column, char page, const char *font_address, const char *text, const uint8_t size) 00119 { 00120 // Position of character data in memory array 00121 uint16_t pos_array; 00122 // temporary column, page address, and column_cnt are used 00123 // to stay inside display area 00124 uint8_t i,y, column_cnt = 0; 00125 uint8_t count = 0; 00126 00127 // font information, needed for calculation 00128 uint8_t start_code, last_code, width, page_height, bytes_p_char; 00129 00130 uint8_t *txtbuffer; 00131 00132 start_code = font_address[2]; // get first defined character 00133 last_code = font_address[3]; // get last defined character 00134 width = font_address[4]; // width in pixel of one char 00135 page_height = font_address[6]; // page count per char 00136 bytes_p_char = font_address[7]; // bytes per char 00137 00138 _lcd_cs->write(0); // Enable SPI 00139 _lcd_cd->write(1); // Data mode 00140 00141 if(page_height + page > LCDPAGES) //stay inside display area 00142 page_height = LCDPAGES - page; 00143 00144 // The string is displayed character after character. If the font has more then one page, 00145 // the top page is printed first, then the next page and so on 00146 for(y = 0; y < page_height; y++) { 00147 txtbuffer = &_lcdbuffer[page*LCDWIDTH + column]; 00148 column_cnt = 0; // clear column_cnt start point 00149 i = 0; 00150 while(( i < size) && ((column_cnt + column) < LCDWIDTH)) { 00151 if(text[i] < start_code || (uint8_t)text[i] > last_code) //make sure data is valid 00152 i++; 00153 else { 00154 // calculate position of ASCII character in font array 00155 // bytes for header + (ASCII - startcode) * bytes per char) 00156 pos_array = 8 + (uint8_t)(text[i++] - start_code) * bytes_p_char; 00157 00158 // get the dot pattern for the part of the char to print 00159 pos_array += y*width; 00160 00161 // stay inside display area 00162 if((column_cnt + width + column) > LCDWIDTH) 00163 column_cnt = LCDWIDTH-width; 00164 00165 // copy character data to buffer 00166 memcpy (txtbuffer+column_cnt,font_address+pos_array,width); 00167 } 00168 00169 column_cnt += width; 00170 } 00171 SSH1106::setCursor(column,page); // set start position x and y 00172 00173 do { 00174 _lcd->write(txtbuffer[count]); 00175 count++; 00176 } while ((count <= column_cnt)); 00177 } 00178 00179 _lcd_cs->write(1); // Disable SPI 00180 00181 } 00182 00183 void SSH1106::drawBitmap(const char *data) 00184 { 00185 int cnt = 0; 00186 _lcd_cs->write(0); 00187 _lcd_cd->write(1); 00188 SSH1106::setCursor(0,0); 00189 for(int row=0; row<LCDPAGES; row++) { 00190 SSH1106::setCursor(0, row); 00191 for(int column=0; column<LCDWIDTH; column++) { 00192 _lcd->write(data[cnt]); 00193 cnt++; 00194 } 00195 } 00196 _lcd_cs->write(1); 00197 } 00198 00199 void SSH1106::drawLineHor(char posx, char posy, char height, char width) 00200 { 00201 char page, offset, offset2; 00202 char buffer[2] = {0xFF, 0xFF}; 00203 00204 _lcd_cs->write(0); 00205 _lcd_cd->write(1); 00206 00207 if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area 00208 00209 page = posy/8; 00210 offset = posy - (page*8); 00211 buffer[0] = buffer[0] >> (8-height); 00212 buffer[0] = buffer[0] << offset; 00213 00214 if((offset + height) > 8) { 00215 offset2 = ((offset+height)-8); 00216 buffer[1] = buffer[1] - (0xFF << (offset2)); 00217 } 00218 00219 SSH1106::setCursor(posx, page); 00220 00221 for(int i=0; i<width; i++) _lcd->write(buffer[0]); 00222 00223 if(buffer[1] != 0xFF && (page+1) < 8) { // only write if line takes up > 1 page & keep inside display area 00224 SSH1106::setCursor(posx, (page+1)); 00225 for(int i=0; i<width; i++) _lcd->write(buffer[1]); 00226 } 00227 _lcd_cs->write(1); 00228 } 00229 00230 void SSH1106::drawLineVert(char posx, char posy, char height, char width) 00231 { 00232 char page, pagecount, offset, offset2; 00233 00234 _lcd_cs->write(0); 00235 _lcd_cd->write(1); 00236 00237 page = posy/8; 00238 pagecount = height/8; 00239 offset2 = height - (pagecount*8); 00240 00241 SSH1106::setCursor(posx, page); 00242 for(int i=0; i<width; i++) _lcd->write((0xFF>>offset)); 00243 00244 for(; pagecount > 1; pagecount--) { 00245 page++; 00246 SSH1106::setCursor(posx, page); 00247 for(int i=0; i<width; i++) _lcd->write(0xFF); 00248 } 00249 00250 SSH1106::setCursor(posx, (page+1)); 00251 for(int i=0; i<width; i++) _lcd->write((0xFF<<offset2)); 00252 00253 _lcd_cs->write(1); 00254 } 00255 00256 void SSH1106::clearBuffer(void) 00257 { 00258 for(int i=0; i<(LCDWIDTH*LCDPAGES); i++) buff[i] = 0; 00259 } 00260 00261 void SSH1106::update(void) 00262 { 00263 int cnt = 0; 00264 _lcd_cs->write(0); 00265 _lcd_cd->write(1); 00266 SSH1106::setCursor(0,0); 00267 for(int row=0; row<LCDPAGES; row++) { 00268 SSH1106::setCursor(0, row); 00269 for(int column=0; column<LCDWIDTH; column++) { 00270 _lcd->write(buff[cnt]); 00271 cnt++; 00272 } 00273 } 00274 _lcd_cs->write(1); 00275 } 00276 00277 void SSH1106::drawbufferLineHor(char posx, char posy, char height, char width) 00278 { 00279 char page, offset, offset2; 00280 int cursor; 00281 char buffer[2] = {0xFF, 0xFF}; 00282 00283 if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area 00284 00285 page = posy/LCDPAGES; 00286 offset = posy - (page*LCDPAGES); 00287 buffer[0] = buffer[0] >> (8-height); 00288 buffer[0] = buffer[0] << offset; 00289 00290 if((offset + height) > 8) { 00291 offset2 = ((offset+height)-8); 00292 buffer[1] = buffer[1] - (0xFF << (offset2)); 00293 } 00294 00295 cursor = posx + (page*LCDWIDTH); 00296 00297 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= buffer[0]; 00298 00299 if(buffer[1] != 0xFF && (page+1) < LCDPAGES) { // only write if line takes up > 1 page & keep inside display area 00300 for(int i=0; i<width; i++) SSH1106::buff[cursor+i+LCDWIDTH] |= buffer[1]; 00301 } 00302 } 00303 00304 void SSH1106::drawbufferLineVert(char posx, char posy, char height, char width) 00305 { 00306 char page, pagecount, offset, offset2; 00307 int cursor; 00308 00309 page = posy/LCDPAGES; 00310 pagecount = height/LCDPAGES; 00311 offset2 = height - (pagecount*LCDPAGES); 00312 cursor = posx + (page*LCDWIDTH); // LCDWIDTH 00313 00314 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= (0xFF>>offset); 00315 00316 for(; pagecount > 1; pagecount--) { 00317 page++; 00318 cursor += LCDWIDTH; 00319 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= 0xFF; 00320 } 00321 00322 cursor += LCDWIDTH; 00323 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= (0xFF >> offset2); 00324 }
Generated on Wed Jul 20 2022 17:31:59 by 1.7.2