rongyu lou / SSH1106-alan

Dependents:   CarPakingSystem_V13

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SSH1106.cpp Source File

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 }