Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: CarPakingSystem_V13
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 SPI lcd(D4, NC, D3); // mosi, miso (nc), sclk 00013 DigitalOut cs(D15); // chip select (active low) 00014 DigitalOut cd(D14); // command/data (0=command, 1=data) 00015 DigitalOut rst(D10); // Reset (active low) 00016 00017 SSH1106 ssh1106(lcd, cs, cd, rst); 00018 SSH1106::SSH1106(SPI &lcd, DigitalOut &lcd_cs, DigitalOut &lcd_cd, DigitalOut &lcd_rst) 00019 { 00020 _lcd = &lcd; 00021 _lcd_cs = &lcd_cs; 00022 _lcd_cd = &lcd_cd; 00023 _lcd_rst = &lcd_rst; 00024 } 00025 00026 void SSH1106::init() 00027 { 00028 _lcd_cs->write(1); 00029 _lcd->frequency(24000000); // Abusing SPI to save some time.. Try a lower freq if this doesn't work 00030 _lcd->format(8,3); 00031 _lcd_cs->write(0); // enable SPI 00032 _lcd_cd->write(0); // COMMAND mode 00033 00034 _lcd_rst->write(0); 00035 //wait_ms(100); 00036 _lcd_rst->write(1); 00037 00038 //wait_ms(50); 00039 00040 _lcd->write(0xAE); // Display off 00041 _lcd->write(0x02); // Set lower column address 00042 _lcd->write(0x10); // Set higher column address 00043 _lcd->write(0x40); // Set display start line 00044 _lcd->write(0xB0); // Set page address 00045 _lcd->write(0x81); // Set contrast to 00046 _lcd->write(0x80); // 128 00047 _lcd->write(0xA1); // Segment remap 00048 _lcd->write(0xA6); // Inverse: normal (A7 = inverse) 00049 _lcd->write(0xA8); // Multiplex ratio 00050 _lcd->write(0x3F); // Duty = 1/32 00051 _lcd->write(0xAD); // Charge pump enable 00052 _lcd->write(0x8B); // External VCC 00053 _lcd->write(0x33); // VPP: 9v 00054 _lcd->write(0xC8); // Com scan direction 00055 _lcd->write(0xD3); // Display offset 00056 _lcd->write(0x00); // 0x20 00057 _lcd->write(0xD5); // Osc division 00058 _lcd->write(0x80); 00059 _lcd->write(0xD9); // Pre-charge period 00060 _lcd->write(0x1F); // 0x22 00061 _lcd->write(0xDA); // Set com pins 00062 _lcd->write(0x12); 00063 _lcd->write(0xDB); // Set vcomh 00064 _lcd->write(0x40); 00065 _lcd->write(0xAF); // Display ON 00066 _lcd_cs->write(1); 00067 _lcd_cd->write(1); 00068 } 00069 00070 void SSH1106::setContrast(char contrast) 00071 { 00072 _lcd_cs->write(0); // enable SPI 00073 _lcd_cd->write(0); // command mode 00074 _lcd->write(0x81); // command to set contrast 00075 _lcd->write(contrast); // set contrast 00076 _lcd_cs->write(1); 00077 _lcd_cd->write(1); 00078 } 00079 00080 void SSH1106::setCursor(char column, char line) 00081 { 00082 int i, j; 00083 column = column+2; // column+4 00084 00085 i=(column&0xF0)>>4; 00086 j=column&0x0F; 00087 _lcd_cd->write(0); 00088 _lcd->write(0xb0+line); 00089 _lcd->write(0x10+i); 00090 _lcd->write(j); 00091 _lcd_cd->write(1); 00092 } 00093 00094 00095 void SSH1106::clear_page(int column,int page) 00096 { 00097 _lcd_cs->write(0); 00098 _lcd_cd->write(1); 00099 00100 for(unsigned short j = page; j < LCDPAGES; j++) { 00101 SSH1106::setCursor(column, j); 00102 for(unsigned short i = column; i < LCDWIDTH ; i++) { 00103 _lcd->write(0x00); 00104 } 00105 } 00106 SSH1106::setCursor(0, 0); 00107 00108 _lcd_cs->write(1); 00109 } 00110 00111 //void SSH1106::clear_line(int column, int line) 00112 //{ 00113 // _lcd_cs->write(0); 00114 // _lcd_cd->write(1); 00115 // 00116 // for(unsigned short j = line; j < LCDPAGES; j++) { 00117 // SSH1106::setCursor(column, j); 00118 // for(unsigned short i = column; i < LCDWIDTH ; i++) { 00119 // _lcd->write(0x00); 00120 // } 00121 // } 00122 // SSH1106::setCursor(0, 0); 00123 // 00124 // _lcd_cs->write(1); 00125 // 00126 //} 00127 00128 void SSH1106::fillScreen() 00129 { 00130 _lcd_cs->write(0); 00131 _lcd_cd->write(1); 00132 00133 for(unsigned short j = 0; j < LCDPAGES; j++) { 00134 SSH1106::setCursor(0, j); 00135 for(unsigned short i = 0; i < LCDWIDTH ; i++) { 00136 _lcd->write(0xff); 00137 } 00138 } 00139 SSH1106::setCursor(0, 0); 00140 00141 _lcd_cs->write(1); 00142 } 00143 00144 void SSH1106::clear() 00145 { 00146 _lcd_cs->write(0); 00147 _lcd_cd->write(1); 00148 00149 for(unsigned short j = 0; j < LCDPAGES; j++) { 00150 SSH1106::setCursor(0, j); 00151 for(unsigned short i = 0; i < LCDWIDTH ; i++) { 00152 _lcd->write(0x00); 00153 } 00154 } 00155 SSH1106::setCursor(0, 0); 00156 00157 _lcd_cs->write(1); 00158 } 00159 00160 void SSH1106::writeText2d(char column, char page, const char font_address[96][8], const char *text, int size) 00161 { 00162 _lcd_cs->write(0); 00163 SSH1106::setCursor(column, page); 00164 for(int i=0; i<size; i++) { 00165 for(int a=0; a<8; a++) { 00166 _lcd->write((font_address[(text[i]-32)][a])); 00167 } 00168 } 00169 _lcd_cs->write(1); 00170 } 00171 00172 //write decimal without size 00173 void SSH1106::writeDec_format(char column, char page, const char *font_address, const int num) 00174 { 00175 char str[40]; 00176 int n; 00177 if((num+1)%10 != 0) //if there is a two bit decimal 00178 { 00179 n = sprintf(str,"%d",num); 00180 SSH1106::writeText(column, page, font_address, str, n); 00181 } 00182 else 00183 { 00184 n = sprintf(str," %d",num); 00185 SSH1106::writeText(column, page, font_address, str, n); 00186 } 00187 } 00188 00189 void SSH1106::writeTim_format(char column, char page, const char *font_address, const int num) 00190 { 00191 char str[40]; 00192 int n; 00193 if((num+1)%10 != 0) //if there is a two bit decimal 00194 { 00195 n = sprintf(str,"%d",num); 00196 SSH1106::writeText(column, page, font_address, str, n); 00197 } 00198 else 00199 { 00200 n = sprintf(str," %02d",num); 00201 SSH1106::writeText(column, page, font_address, str, n); 00202 } 00203 } 00204 00205 00206 //write without size 00207 void SSH1106::writeText_format(char column, char page, const char *font_address, const char *text) 00208 { 00209 char str[40]; 00210 int n; 00211 n = sprintf(str,text); 00212 SSH1106::writeText(column, page, font_address, str, n); 00213 } 00214 00215 void SSH1106::writeText(char column, char page, const char *font_address, const char *text, const uint8_t size) 00216 { 00217 // Position of character data in memory array 00218 uint16_t pos_array; 00219 // temporary column, page address, and column_cnt are used 00220 // to stay inside display area 00221 uint8_t i,y, column_cnt = 0; 00222 uint8_t count = 0; 00223 00224 // font information, needed for calculation 00225 uint8_t start_code, last_code, width, page_height, bytes_p_char; 00226 00227 uint8_t *txtbuffer; 00228 00229 start_code = font_address[2]; // get first defined character 00230 last_code = font_address[3]; // get last defined character 00231 width = font_address[4]; // width in pixel of one char 6 00232 page_height = font_address[6]; // page count per char 00233 bytes_p_char = font_address[7]; // bytes per char 00234 00235 _lcd_cs->write(0); // Enable SPI 00236 _lcd_cd->write(1); // Data mode 00237 00238 if(page_height + page > LCDPAGES) //stay inside display area 00239 page_height = LCDPAGES - page; 00240 00241 // The string is displayed character after character. If the font has more then one page, 00242 // the top page is printed first, then the next page and so on 00243 for(y = 0; y < page_height; y++) { 00244 txtbuffer = &_lcdbuffer[page*LCDWIDTH + column]; 00245 column_cnt = 0; // clear column_cnt start point 00246 i = 0; 00247 while(( i < size) && ((column_cnt + column) < LCDWIDTH)) { 00248 if(text[i] < start_code || (uint8_t)text[i] > last_code) //make sure data is valid 00249 i++; 00250 else { 00251 // calculate position of ASCII character in font array 00252 // bytes for header + (ASCII - startcode) * bytes per char) 00253 pos_array = 8 + (uint8_t)(text[i++] - start_code) * bytes_p_char; 00254 00255 // get the dot pattern for the part of the char to print 00256 pos_array += y*width; 00257 00258 // stay inside display area 00259 if((column_cnt + width + column) > LCDWIDTH) 00260 column_cnt = LCDWIDTH-width; 00261 00262 // copy character data to buffer 00263 memcpy (txtbuffer+column_cnt,font_address+pos_array,width); 00264 } 00265 00266 column_cnt += width; 00267 } 00268 SSH1106::setCursor(column,page); // set start position x and y 00269 00270 do { 00271 _lcd->write(txtbuffer[count]); 00272 count++; 00273 } while ((count <= column_cnt)); 00274 } 00275 00276 _lcd_cs->write(1); // Disable SPI 00277 00278 } 00279 00280 void SSH1106::drawBitmap(const char *data) 00281 { 00282 int cnt = 0; 00283 _lcd_cs->write(0); 00284 _lcd_cd->write(1); 00285 SSH1106::setCursor(0,0); 00286 for(int row=0; row<LCDPAGES; row++) { 00287 SSH1106::setCursor(0, row); 00288 for(int column=0; column<LCDWIDTH; column++) { 00289 _lcd->write(data[cnt]); 00290 cnt++; 00291 } 00292 } 00293 _lcd_cs->write(1); 00294 } 00295 00296 void SSH1106::drawLineHor(char posx, char posy, char height, char width) 00297 { 00298 char page, offset, offset2; 00299 char buffer[2] = {0xFF, 0xFF}; 00300 00301 _lcd_cs->write(0); 00302 _lcd_cd->write(1); 00303 00304 if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area 00305 00306 page = posy/8; 00307 offset = posy - (page*8); 00308 buffer[0] = buffer[0] >> (8-height); 00309 buffer[0] = buffer[0] << offset; 00310 00311 if((offset + height) > 8) { 00312 offset2 = ((offset+height)-8); 00313 buffer[1] = buffer[1] - (0xFF << (offset2)); 00314 } 00315 00316 SSH1106::setCursor(posx, page); 00317 00318 for(int i=0; i<width; i++) _lcd->write(buffer[0]); 00319 00320 if(buffer[1] != 0xFF && (page+1) < 8) { // only write if line takes up > 1 page & keep inside display area 00321 SSH1106::setCursor(posx, (page+1)); 00322 for(int i=0; i<width; i++) _lcd->write(buffer[1]); 00323 } 00324 _lcd_cs->write(1); 00325 } 00326 00327 void SSH1106::drawLineVert(char posx, char posy, char height, char width) 00328 { 00329 char page, pagecount, offset, offset2; 00330 00331 _lcd_cs->write(0); 00332 _lcd_cd->write(1); 00333 00334 page = posy/8; 00335 pagecount = height/8; 00336 offset2 = height - (pagecount*8); 00337 00338 SSH1106::setCursor(posx, page); 00339 for(int i=0; i<width; i++) _lcd->write((0xFF>>offset)); 00340 00341 for(; pagecount > 1; pagecount--) { 00342 page++; 00343 SSH1106::setCursor(posx, page); 00344 for(int i=0; i<width; i++) _lcd->write(0xFF); 00345 } 00346 00347 SSH1106::setCursor(posx, (page+1)); 00348 for(int i=0; i<width; i++) _lcd->write((0xFF<<offset2)); 00349 00350 _lcd_cs->write(1); 00351 } 00352 00353 void SSH1106::clearBuffer(void) 00354 { 00355 for(int i=0; i<(LCDWIDTH*LCDPAGES); i++) buff[i] = 0; 00356 } 00357 00358 void SSH1106::update(void) 00359 { 00360 int cnt = 0; 00361 _lcd_cs->write(0); 00362 _lcd_cd->write(1); 00363 SSH1106::setCursor(0,0); 00364 for(int row=0; row<LCDPAGES; row++) { 00365 SSH1106::setCursor(0, row); 00366 for(int column=0; column<LCDWIDTH; column++) { 00367 _lcd->write(buff[cnt]); 00368 cnt++; 00369 } 00370 } 00371 _lcd_cs->write(1); 00372 } 00373 00374 void SSH1106::drawbufferLineHor(char posx, char posy, char height, char width) 00375 { 00376 char page, offset, offset2; 00377 int cursor; 00378 char buffer[2] = {0xFF, 0xFF}; 00379 00380 if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area 00381 00382 page = posy/LCDPAGES; 00383 offset = posy - (page*LCDPAGES); 00384 buffer[0] = buffer[0] >> (8-height); 00385 buffer[0] = buffer[0] << offset; 00386 00387 if((offset + height) > 8) { 00388 offset2 = ((offset+height)-8); 00389 buffer[1] = buffer[1] - (0xFF << (offset2)); 00390 } 00391 00392 cursor = posx + (page*LCDWIDTH); 00393 00394 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= buffer[0]; 00395 00396 if(buffer[1] != 0xFF && (page+1) < LCDPAGES) { // only write if line takes up > 1 page & keep inside display area 00397 for(int i=0; i<width; i++) SSH1106::buff[cursor+i+LCDWIDTH] |= buffer[1]; 00398 } 00399 } 00400 00401 void SSH1106::drawbufferLineVert(char posx, char posy, char height, char width) 00402 { 00403 char page, pagecount, offset, offset2; 00404 int cursor; 00405 00406 page = posy/LCDPAGES; 00407 pagecount = height/LCDPAGES; 00408 offset2 = height - (pagecount*LCDPAGES); 00409 cursor = posx + (page*LCDWIDTH); // LCDWIDTH 00410 00411 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= (0xFF>>offset); 00412 00413 for(; pagecount > 1; pagecount--) { 00414 page++; 00415 cursor += LCDWIDTH; 00416 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= 0xFF; 00417 } 00418 00419 cursor += LCDWIDTH; 00420 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= (0xFF >> offset2); 00421 }
Generated on Sun Jul 24 2022 19:34:39 by
1.7.2