A simple library for SSH1106 controlled GLCDs
Diff: SSH1106.cpp
- Revision:
- 0:3cd0a11a2f91
- Child:
- 1:ac9efaadd666
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SSH1106.cpp Mon Dec 19 15:02:30 2016 +0000 @@ -0,0 +1,197 @@ +/** + * This is a simple library for SSH1106 controlled graphic LCD's. + * Written for a cheap 1.3" OLED GLCD + * See http://www.dx.com/p/open-smart-1-8-128-64-lcd-display-breakout-module-w-blue-backlit-444694 + * + * Written by: Erik van de Coevering + * With thanks to Tim Barr from whom I've reused some code + * Use this code in whatever way you like, as long as it stays free of charge! + */ + +#include "SSH1106.h" + +SSH1106::SSH1106(SPI &lcd, DigitalOut &lcd_cs, DigitalOut &lcd_cd, DigitalOut &lcd_rst) +{ + _lcd = &lcd; + _lcd_cs = &lcd_cs; + _lcd_cd = &lcd_cd; + _lcd_rst = &lcd_rst; +} + +void SSH1106::init() +{ + _lcd_cs->write(1); + _lcd->frequency(24000000); // Abusing SPI to save some time.. Try a lower freq if this doesn't work + _lcd->format(8,3); + _lcd_cs->write(0); // enable SPI + _lcd_cd->write(0); // COMMAND mode + + _lcd_rst->write(0); + wait_ms(100); + _lcd_rst->write(1); + + wait_ms(50); + + _lcd->write(0xAE); // Display off + _lcd->write(0x02); // Set lower column address + _lcd->write(0x10); // Set higher column address + _lcd->write(0x40); // Set display start line + _lcd->write(0xB0); // Set page address + _lcd->write(0x81); // Set contrast to + _lcd->write(0x80); // 128 + _lcd->write(0xA1); // Segment remap + _lcd->write(0xA6); // Inverse: normal (A7 = inverse) + _lcd->write(0xA8); // Multiplex ratio + _lcd->write(0x3F); // Duty = 1/32 + _lcd->write(0xAD); // Charge pump enable + _lcd->write(0x8B); // External VCC + _lcd->write(0x33); // VPP: 9v + _lcd->write(0xC8); // Com scan direction + _lcd->write(0xD3); // Display offset + _lcd->write(0x00); // 0x20 + _lcd->write(0xD5); // Osc division + _lcd->write(0x80); + _lcd->write(0xD9); // Pre-charge period + _lcd->write(0x1F); // 0x22 + _lcd->write(0xDA); // Set com pins + _lcd->write(0x12); + _lcd->write(0xDB); // Set vcomh + _lcd->write(0x40); + _lcd->write(0xAF); // Display ON + _lcd_cs->write(1); + _lcd_cd->write(1); + +} + +void SSH1106::setContrast(char contrast) +{ + _lcd_cs->write(0); // enable SPI + _lcd_cd->write(0); // command mode + _lcd->write(0x81); // command to set contrast + _lcd->write(contrast); // set contrast + _lcd_cs->write(1); + _lcd_cd->write(1); + } + +void SSH1106::setCursor(char column, char line) +{ + int i, j; + column = column+2; // column+4 + + i=(column&0xF0)>>4; + j=column&0x0F; + _lcd_cd->write(0); + _lcd->write(0xb0+line); + _lcd->write(0x10+i); + _lcd->write(j); + _lcd_cd->write(1); +} + +void SSH1106::clear() +{ + _lcd_cs->write(0); + _lcd_cd->write(1); + + for(unsigned short j = 0; j < 8; j++) { + SSH1106::setCursor(0, j); + for(unsigned short i = 0; i < 128 ; i++) { + _lcd->write(0x00); + } + } + + SSH1106::setCursor(0, 0); + + _lcd_cs->write(1); +} + +void SSH1106::writeText2d(char column, char page, const char font_address[96][8], const char *text, int size) +{ + _lcd_cs->write(0); + SSH1106::setCursor(column, page); + for(int i=0; i<size; i++) { + for(int a=0; a<8; a++) { + _lcd->write((font_address[(text[i]-32)][a])); + } + } + _lcd_cs->write(1); +} + +void SSH1106::writeText(char column, char page, const char *font_address, const char *text, const uint8_t size) +{ + // Position of character data in memory array + uint16_t pos_array; + // temporary column, page address, and column_cnt are used + // to stay inside display area + uint8_t i,y, column_cnt = 0; + uint8_t count = 0; + + // font information, needed for calculation + uint8_t start_code, last_code, width, page_height, bytes_p_char; + + uint8_t *txtbuffer; + + start_code = font_address[2]; // get first defined character + last_code = font_address[3]; // get last defined character + width = font_address[4]; // width in pixel of one char + page_height = font_address[6]; // page count per char + bytes_p_char = font_address[7]; // bytes per char + + _lcd_cs->write(0); // Enable SPI + _lcd_cd->write(1); // Data mode + + if(page_height + page > LCDPAGES) //stay inside display area + page_height = LCDPAGES - page; + + // The string is displayed character after character. If the font has more then one page, + // the top page is printed first, then the next page and so on + for(y = 0; y < page_height; y++) { + txtbuffer = &_lcdbuffer[page*LCDWIDTH + column]; + column_cnt = 0; // clear column_cnt start point + i = 0; + while(( i < size) && ((column_cnt + column) < LCDWIDTH)) { + if(text[i] < start_code || (uint8_t)text[i] > last_code) //make sure data is valid + i++; + else { + // calculate position of ASCII character in font array + // bytes for header + (ASCII - startcode) * bytes per char) + pos_array = 8 + (uint8_t)(text[i++] - start_code) * bytes_p_char; + + // get the dot pattern for the part of the char to print + pos_array += y*width; + + // stay inside display area + if((column_cnt + width + column) > LCDWIDTH) + column_cnt = LCDWIDTH-width; + + // copy character data to buffer + memcpy (txtbuffer+column_cnt,font_address+pos_array,width); + } + + column_cnt += width; + } + SSH1106::setCursor(column,page); // set start position x and y + + do { + _lcd->write(txtbuffer[count]); + count++; + } while ((count <= column_cnt)); + } + + _lcd_cs->write(1); // Disable SPI + +} + +void SSH1106::drawBitmap(const char *data) +{ + int cnt = 0; + _lcd_cs->write(0); + _lcd_cd->write(1); + SSH1106::setCursor(0,0); + for(int row=0; row<8; row++) { + SSH1106::setCursor(0, row); + for(int column=0; column<128; column++) { + _lcd->write(data[cnt]); + cnt++; + } + } +} \ No newline at end of file