Matt Lesslaw
/
ST7066U_demo
Derived work demoing the Crystalfontz CHARACTER LCD MODULE
main.cpp
- Committer:
- lawless
- Date:
- 2012-07-09
- Revision:
- 0:a6f66204f651
File content as of revision 0:a6f66204f651:
/* Derived from http://mbed.org/users/JohnSchooling/programs/pwm_trinary_count_01/m9rhax * mbed demo: * Software PWM on the mbed LEDs. Counting in trinary using off, half bright and full on LEDs. * Smooth scrolling a graphic on a 16x2 LCD display (using ST7066U controller). * * 2012-05-09 John Schooling * In order to try and understand what's going on and to customise it later I changed the code into an ST7066U class */ #include "mbed.h" class ST7066U { private : DigitalOut *rs, *rw, *e, *db0, *db1, *db2, *db3, *db4, *db5, *db6, *db7; uint8_t lines_bit, font_bit; public : ST7066U () { rs = new DigitalOut(p5); rw = new DigitalOut(p6); e = new DigitalOut(p7); db0 = new DigitalOut(p8); db1 = new DigitalOut(p9); db2 = new DigitalOut(p10); db3 = new DigitalOut(p11); db4 = new DigitalOut(p12); db5 = new DigitalOut(p13); db6 = new DigitalOut(p14); db7 = new DigitalOut(p15); font_bit = 0; lines_bit = 0; wait(0.040); // LCD initialisation takes 40ms. } void rows(int l) { if(l == 1) lines_bit = 0; else if (l == 2) lines_bit = 8; instruction(32 | 16 | lines_bit | font_bit); } void font(int f) { if(f == 0) font_bit = 0; else if (f == 1) font_bit = 4; instruction(32 | 16 | lines_bit | font_bit); } void write(int c, int nrs) { int old_rs = rs->read(); // Should check Busy Flag here. rs->write(nrs); e->write(1); // E must be on for min 480ns then drop to zero. Trigger is on falling signal. db0->write(c & 1); db1->write(c>>1 & 1); db2->write(c>>2 & 1); db3->write(c>>3 & 1); db4->write(c>>4 & 1); db5->write(c>>5 & 1); db6->write(c>>6 & 1); db7->write(c>>7 & 1); // added extra wait state wait(0.000001); // Needed the equivalent of this on the Raspberry Pi. // Tdsw Data Setup Width time at least 80ns. No need for delay on slow processor. e->write(0); // = 0; // Strobe. // Th Data Hold time at least 10ns. No need for delay on slow processor. wait(0.000037); // Most instructions take 37us. May not need this delay if Busy Flag checked at top. rs->write(old_rs); } void data(uint8_t c) { write(c, 1); } void instruction(uint8_t c) { write(c, 0); } void clear(void) { instruction(1); wait(0.00152); // clear takes 1.52 ms. } void home(void) { instruction(2); wait(0.00152); // home takes 1.52 ms. } void str_at(const char *str, uint8_t x = 0, uint8_t y = 0) { uint8_t *c = (uint8_t *) str; ddram(y * 0x40 + x); for (uint8_t i = 0; i < 80 && (*c); i++) { // Will never write more than 80 chars. data(*c); c++; } } void row0(const char *str, uint8_t x = 0) { str_at(str, x, 0); } void row1(const char *str, uint8_t x = 0) { str_at(str, x, 1); } void str(const char *str) { str_at(str); } void on() { instruction(0x0C); // 0000 1DCB Display=1 Cursor=0 Blink=0 } void off() { instruction(0x08); // 0000 1DCB Display=0 Cursor=0 Blink=0 } void cgram(uint8_t a) { instruction(0x40 | a); } void ddram(uint8_t a) { instruction(0x80 | a); } }; /* Crystalfontz CFAH1602BTMIJT 16x2 LCD display. http://www.coolcomponents.co.uk/catalog/blue-16x2-display-p-151.html (also part of mbed starter kit). Sitronix ST7066U functions (compatible with Hitachi HD44780). CFAH1602BTMIJT_v1.0.pdf http://www.crystalfontz.com/controllers/ST7066U.pdf LCD initialisation takes 40ms. Instruction RS RW 7 6 5 4 3 2 1 0 Time (270kHz) Clear Display 0 0 0 0 0 0 0 0 0 1 1.52 ms Clear, Home, Entry Mode = Increment. Return Home 0 0 0 0 0 0 0 0 1 x 1.52 ms. Entry Mode Set 0 0 0 0 0 0 0 1 I S .037ms Increment cursor, Shift display (shift cursor). Display On/Off 0 0 0 0 0 0 1 D C P .037ms Display on, Cursor on, Position on. Cursor or Display Shift 0 0 0 0 0 1 D R x x .037ms Display shift (cursor shift), Right (left). Function Set 0 0 0 0 1 D N F x x .037ms Data interface 8 (4) bits, Number of lines 2 (1), Font 5x11 if 1 line (5x8). Set CGRAM address 0 0 0 1 A A A A A A .037ms Set 6 bit CGRAM address in address counter. Set DDRAM address 0 0 1 A A A A A A A .037ms Set 7 bit DDRAM address in address counter. Read Busy Flag and addr 0 1 F A A A A A A A .000ms Read Busy Flag and address counter. Write data to RAM 1 0 A A A A A A A A .037ms Write data to RAM (DDRAM or CGRAM). Must do Set address first. Read data from RAM 1 1 A A A A A A A A .037ms Read data from internal RAM (DDRAM or CGRAM). Must do Set address first. */ int face1[8][8] = { {0x01, 0x02, 0x04, 0x08, 0x13, 0x14, 0x14, 0x13} // Top left. , {0x1F, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x04} , {0x10, 0x08, 0x04, 0x02, 0x19, 0x05, 0x05, 0x19} , {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // Top right. , {0x10, 0x10, 0x12, 0x11, 0x09, 0x04, 0x02, 0x01} // Bottom left. , {0x04, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x1F} , {0x01, 0x01, 0x09, 0x11, 0x12, 0x04, 0x08, 0x10} , {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // Bottom right. }; int face2[8][8] = { {0x01, 0x06, 0x0C, 0x18, 0x30, 0x33, 0x36, 0x36} // Top left. , {0x3F, 0x00, 0x00, 0x00, 0x00, 0x21, 0x33, 0x33} , {0x20, 0x18, 0x0C, 0x06, 0x03, 0x33, 0x1B, 0x1B} , {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // Top right. , {0x33, 0x30, 0x33, 0x1B, 0x19, 0x0C, 0x06, 0x01} // Bottom left. , {0x21, 0x00, 0x00, 0x00, 0x21, 0x3F, 0x00, 0x3F} , {0x33, 0x03, 0x33, 0x36, 0x26, 0x0C, 0x18, 0x20} , {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // Bottom right. }; DigitalOut myled1(LED1); DigitalOut myled2(LED2); DigitalOut myled3(LED3); DigitalOut myled4(LED4); void scroll_face(ST7066U *lcd) { int pict[8][8]; memcpy(pict, face2, sizeof(pict)); lcd->cgram(0); for (int i = 0; i < 64; i++) { lcd->data((uint8_t)pict[i/8][i%8]); } // Display the graphic characters. lcd->ddram(0); lcd->data(3); // Top right of graphic. lcd->ddram(64); lcd->data(7); // Bottom right of graphic. for (int n = 0; n < 19; n++) { for (int k = 0; k < 6; k++) { // 6 bit Smooth scrolling avoiding jump between characters on display. lcd->cgram(0); for (int i = 63; i >= 0; i--) { if (i/8 == 0 || i/8 == 4) { pict[i/8][i%8] |= ((pict[i/8 +3][i%8] &1) << 6); // Put right hand low bit into bit 6. } else { pict[i/8][i%8] |= ((pict[i/8 -1][i%8] &1) << 6); // Put previous low bit into bit 6. } } for (int i = 0; i < 64; i++) { pict[i/8][i%8] >>= 1; // Scroll the character. lcd->data((uint8_t)pict[i/8][i%8]); // Write to LCD. } wait(0.1); } if(n >= 3) { // Graphic has moved on a whole character. Replace left characters with a space. lcd->ddram(n - 3); lcd->data(' '); lcd->ddram(64 + n - 3); lcd->data(' '); } // Set right side of graphic to correct characters. lcd->ddram(1 + n); lcd->data(n%4); lcd->ddram(64 + 1 + n); lcd->data(n%4 + 4); } } void scroll_bar(ST7066U *lcd) { // Scrolling vertical bar to clear the screen. // Bar is two lines (smoother scrolling and more visible than a single line). // There are six combinations for each of the available five bits. Avoids jump between characters on display. // Character number 7 is used for the graphic (0-5 are used by the face). Earlier version left face on screen. for (int i = 0; i < 6 * 17; i++) { // 6 positions for each of 17 characters. lcd->cgram(7 * 8); for (int j = 0; j < 8; j++) { lcd->data((3 << (5 - i%6)) >> 1); // Fill 8 bytes for vertical bar character in Character Generator RAM. } lcd->ddram(i / 6 - (i >= 6)); if (i >= 6) lcd->data(0x20); lcd->data(7); // Top row. lcd->ddram(64 + i / 6 - (i >= 6)); if (i >= 6) lcd->data(0x20); lcd->data(7); // Bottom row. wait(0.075); } } int main() { uint32_t a = 0; // Main PWM loop counter. uint16_t b; int16_t i; uint16_t e4[] = {0, 20, 256}; // LED brightness. char str[17]; // String for writing to the LCD display. ST7066U *lcd = new ST7066U(); lcd->clear(); lcd->rows(2); lcd->on(); lcd->row0("Bedtime", 4); lcd->row1("Counter", 4); // Flash display off/on a couple of times. for (int i = 0; i < 2; i++) { wait(0.5); lcd->off(); // 0000 1DCB Display=0 Cursor=0 Blink=0 wait(0.5); lcd->on(); // 0000 1DCB Display=1 Cursor=0 Blink=0 } wait(1); scroll_face(lcd); //scroll_bar(); // Trinary counting. // Use the mbed LEDs to display trinary values (using software PWM) to count from zero to 80 (trinary 2222). // LED brightness: off = 0, half bright = 1, full on = 2. i = 80; // Force next display value to be zero: (80 + 1) % 81. while (1) { if (a == 0) { // Counter expired: display the next value. i = (i + 1) % 81; // Write decimal and trinary. sprintf(str, "dec %2d tri %d%d%d%d", i, (i / 27) % 3, (i / 9) % 3, (i / 3) % 3, i % 3); lcd->row0(str); // Write hex and binary. sprintf(str, "0x%2.2X 0b0%d%d%d%d%d%d%d", i, i>>6&1, i>>5&1, i>>4&1, i>>3&1, i>>2&1, i>>1&1, i&1); lcd->row1(str); } b = a & 0xFF; // PWM for mbed LEDs. e4 contains the brightness for trit values 0, 1 and 2. myled4 = b < e4[ i % 3] ? 1 : 0; myled3 = b < e4[(i / 3) % 3] ? 1 : 0; myled2 = b < e4[(i / 9) % 3] ? 1 : 0; myled1 = b < e4[(i / 27) % 3] ? 1 : 0; a = (a + 1) & 0x7FFFF; // Loop counter. } }