rongyu lou / SSH1106

Dependents:   CarPakingSystem_V10

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 //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 }