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_V10
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 //write without size 00190 void SSH1106::writeText_format(char column, char page, const char *font_address, const char *text) 00191 { 00192 char str[40]; 00193 int n; 00194 n = sprintf(str,text); 00195 SSH1106::writeText(column, page, font_address, str, n); 00196 } 00197 00198 void SSH1106::writeText(char column, char page, const char *font_address, const char *text, const uint8_t size) 00199 { 00200 // Position of character data in memory array 00201 uint16_t pos_array; 00202 // temporary column, page address, and column_cnt are used 00203 // to stay inside display area 00204 uint8_t i,y, column_cnt = 0; 00205 uint8_t count = 0; 00206 00207 // font information, needed for calculation 00208 uint8_t start_code, last_code, width, page_height, bytes_p_char; 00209 00210 uint8_t *txtbuffer; 00211 00212 start_code = font_address[2]; // get first defined character 00213 last_code = font_address[3]; // get last defined character 00214 width = font_address[4]; // width in pixel of one char 6 00215 page_height = font_address[6]; // page count per char 00216 bytes_p_char = font_address[7]; // bytes per char 00217 00218 _lcd_cs->write(0); // Enable SPI 00219 _lcd_cd->write(1); // Data mode 00220 00221 if(page_height + page > LCDPAGES) //stay inside display area 00222 page_height = LCDPAGES - page; 00223 00224 // The string is displayed character after character. If the font has more then one page, 00225 // the top page is printed first, then the next page and so on 00226 for(y = 0; y < page_height; y++) { 00227 txtbuffer = &_lcdbuffer[page*LCDWIDTH + column]; 00228 column_cnt = 0; // clear column_cnt start point 00229 i = 0; 00230 while(( i < size) && ((column_cnt + column) < LCDWIDTH)) { 00231 if(text[i] < start_code || (uint8_t)text[i] > last_code) //make sure data is valid 00232 i++; 00233 else { 00234 // calculate position of ASCII character in font array 00235 // bytes for header + (ASCII - startcode) * bytes per char) 00236 pos_array = 8 + (uint8_t)(text[i++] - start_code) * bytes_p_char; 00237 00238 // get the dot pattern for the part of the char to print 00239 pos_array += y*width; 00240 00241 // stay inside display area 00242 if((column_cnt + width + column) > LCDWIDTH) 00243 column_cnt = LCDWIDTH-width; 00244 00245 // copy character data to buffer 00246 memcpy (txtbuffer+column_cnt,font_address+pos_array,width); 00247 } 00248 00249 column_cnt += width; 00250 } 00251 SSH1106::setCursor(column,page); // set start position x and y 00252 00253 do { 00254 _lcd->write(txtbuffer[count]); 00255 count++; 00256 } while ((count <= column_cnt)); 00257 } 00258 00259 _lcd_cs->write(1); // Disable SPI 00260 00261 } 00262 00263 void SSH1106::drawBitmap(const char *data) 00264 { 00265 int cnt = 0; 00266 _lcd_cs->write(0); 00267 _lcd_cd->write(1); 00268 SSH1106::setCursor(0,0); 00269 for(int row=0; row<LCDPAGES; row++) { 00270 SSH1106::setCursor(0, row); 00271 for(int column=0; column<LCDWIDTH; column++) { 00272 _lcd->write(data[cnt]); 00273 cnt++; 00274 } 00275 } 00276 _lcd_cs->write(1); 00277 } 00278 00279 void SSH1106::drawLineHor(char posx, char posy, char height, char width) 00280 { 00281 char page, offset, offset2; 00282 char buffer[2] = {0xFF, 0xFF}; 00283 00284 _lcd_cs->write(0); 00285 _lcd_cd->write(1); 00286 00287 if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area 00288 00289 page = posy/8; 00290 offset = posy - (page*8); 00291 buffer[0] = buffer[0] >> (8-height); 00292 buffer[0] = buffer[0] << offset; 00293 00294 if((offset + height) > 8) { 00295 offset2 = ((offset+height)-8); 00296 buffer[1] = buffer[1] - (0xFF << (offset2)); 00297 } 00298 00299 SSH1106::setCursor(posx, page); 00300 00301 for(int i=0; i<width; i++) _lcd->write(buffer[0]); 00302 00303 if(buffer[1] != 0xFF && (page+1) < 8) { // only write if line takes up > 1 page & keep inside display area 00304 SSH1106::setCursor(posx, (page+1)); 00305 for(int i=0; i<width; i++) _lcd->write(buffer[1]); 00306 } 00307 _lcd_cs->write(1); 00308 } 00309 00310 void SSH1106::drawLineVert(char posx, char posy, char height, char width) 00311 { 00312 char page, pagecount, offset, offset2; 00313 00314 _lcd_cs->write(0); 00315 _lcd_cd->write(1); 00316 00317 page = posy/8; 00318 pagecount = height/8; 00319 offset2 = height - (pagecount*8); 00320 00321 SSH1106::setCursor(posx, page); 00322 for(int i=0; i<width; i++) _lcd->write((0xFF>>offset)); 00323 00324 for(; pagecount > 1; pagecount--) { 00325 page++; 00326 SSH1106::setCursor(posx, page); 00327 for(int i=0; i<width; i++) _lcd->write(0xFF); 00328 } 00329 00330 SSH1106::setCursor(posx, (page+1)); 00331 for(int i=0; i<width; i++) _lcd->write((0xFF<<offset2)); 00332 00333 _lcd_cs->write(1); 00334 } 00335 00336 void SSH1106::clearBuffer(void) 00337 { 00338 for(int i=0; i<(LCDWIDTH*LCDPAGES); i++) buff[i] = 0; 00339 } 00340 00341 void SSH1106::update(void) 00342 { 00343 int cnt = 0; 00344 _lcd_cs->write(0); 00345 _lcd_cd->write(1); 00346 SSH1106::setCursor(0,0); 00347 for(int row=0; row<LCDPAGES; row++) { 00348 SSH1106::setCursor(0, row); 00349 for(int column=0; column<LCDWIDTH; column++) { 00350 _lcd->write(buff[cnt]); 00351 cnt++; 00352 } 00353 } 00354 _lcd_cs->write(1); 00355 } 00356 00357 void SSH1106::drawbufferLineHor(char posx, char posy, char height, char width) 00358 { 00359 char page, offset, offset2; 00360 int cursor; 00361 char buffer[2] = {0xFF, 0xFF}; 00362 00363 if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area 00364 00365 page = posy/LCDPAGES; 00366 offset = posy - (page*LCDPAGES); 00367 buffer[0] = buffer[0] >> (8-height); 00368 buffer[0] = buffer[0] << offset; 00369 00370 if((offset + height) > 8) { 00371 offset2 = ((offset+height)-8); 00372 buffer[1] = buffer[1] - (0xFF << (offset2)); 00373 } 00374 00375 cursor = posx + (page*LCDWIDTH); 00376 00377 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= buffer[0]; 00378 00379 if(buffer[1] != 0xFF && (page+1) < LCDPAGES) { // only write if line takes up > 1 page & keep inside display area 00380 for(int i=0; i<width; i++) SSH1106::buff[cursor+i+LCDWIDTH] |= buffer[1]; 00381 } 00382 } 00383 00384 void SSH1106::drawbufferLineVert(char posx, char posy, char height, char width) 00385 { 00386 char page, pagecount, offset, offset2; 00387 int cursor; 00388 00389 page = posy/LCDPAGES; 00390 pagecount = height/LCDPAGES; 00391 offset2 = height - (pagecount*LCDPAGES); 00392 cursor = posx + (page*LCDWIDTH); // LCDWIDTH 00393 00394 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= (0xFF>>offset); 00395 00396 for(; pagecount > 1; pagecount--) { 00397 page++; 00398 cursor += LCDWIDTH; 00399 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= 0xFF; 00400 } 00401 00402 cursor += LCDWIDTH; 00403 for(int i=0; i<width; i++) SSH1106::buff[cursor+i] |= (0xFF >> offset2); 00404 }
Generated on Thu Jul 14 2022 10:49:14 by
1.7.2