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.
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