* 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 The code is not in a library but gives you what you need in one file to add the required code to your own library.
Diff: main.cpp
- Revision:
- 0:514531f6b9db
- Child:
- 1:f0561ba3d266
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed May 09 14:29:05 2012 +0000 @@ -0,0 +1,244 @@ +/* + * 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 + * + */ + +#include "mbed.h" + +#define LCD_RS_DATA 1 +#define LCD_RS_INST 0 + +/* + 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 lcd_rs(p5); +DigitalOut lcd_rw(p6); +DigitalOut lcd_e(p7); +DigitalOut lcd_db0(p8); +DigitalOut lcd_db1(p9); +DigitalOut lcd_db2(p10); +DigitalOut lcd_db3(p11); +DigitalOut lcd_db4(p12); +DigitalOut lcd_db5(p13); +DigitalOut lcd_db6(p14); +DigitalOut lcd_db7(p15); + + +DigitalOut myled1(LED1); +DigitalOut myled2(LED2); +DigitalOut myled3(LED3); +DigitalOut myled4(LED4); + + +void lcd_write(int c, int rs) { + int old_lcd_rs = lcd_rs; + // Should check Busy Flag here. + lcd_rs = rs; + lcd_e = 1; // E must be on for min 480ns then drop to zero. Trigger is on falling signal. + lcd_db0 = c & 1; + lcd_db1 = c>>1 & 1; + lcd_db2 = c>>2 & 1; + lcd_db3 = c>>3 & 1; + lcd_db4 = c>>4 & 1; + lcd_db5 = c>>5 & 1; + lcd_db6 = c>>6 & 1; + lcd_db7 = c>>7 & 1; + // Tdsw Data Setup Width time at least 80ns. No need for delay on slow processor. + lcd_e = 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. + lcd_rs = old_lcd_rs; +} + +void lcd_write_data(uint8_t c) { + lcd_write(c, LCD_RS_DATA); // Data +} +void lcd_write_inst(uint8_t c) { + lcd_write(c, LCD_RS_INST); // Instruction +} + +void lcd_clear(void) { + lcd_write_inst(1); // + wait(0.00152); // clear takes 1.52 ms. +} +void lcd_home(void) { + lcd_write_inst(2); // + wait(0.00152); // home takes 1.52 ms. +} + +void lcd_write_str(uint8_t *str, uint8_t x = 0, uint8_t y = 0) { + uint8_t *c = str; + lcd_write_inst(0x80 + y * 0x40 + x); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + for (uint8_t i = 0; i < 80 && (*c); i++) { // Will never write more than 80 chars. + lcd_write_data(*c); + c++; + } +} + +void scroll_face(void) { +int pict[8][8]; + memcpy(pict, face2, sizeof(pict)); + // Write the graphic characters to CGRAM. + lcd_write_inst(0x40); // 0 1 A A A A A A Set 6 bit CGRAM address in address counter + for (int i = 0; i < 64; i++) { + lcd_write_data((uint8_t)pict[i/8][i%8]); + } + // Display the graphic characters. + lcd_write_inst(0x80); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + lcd_write_data(3); // Top right of graphic. + lcd_write_inst(0xC0); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + lcd_write_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. + // Write the graphic characters to CGRAM. + lcd_write_inst(0x40); // 0 1 A A A A A A Set 6 bit CGRAM address in address counter + 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 previous low bit into bit 6. + } else { + pict[i/8][i%8] |= ((pict[i/8 -1][i%8] &1) << 6); // Put right hand end bit into bit 6. + } + } + for (int i = 0; i < 64; i++) { + pict[i/8][i%8] >>= 1; // Scroll the character. + lcd_write_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_write_inst(0x80 + n - 3); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + lcd_write_data(32); + lcd_write_inst(0xC0 + n - 3); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + lcd_write_data(32); + } + // Set right side of graphic to correct characters. + lcd_write_inst(0x81 + n); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + lcd_write_data(n%4); + lcd_write_inst(0xC1 + n); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + lcd_write_data(n%4 + 4); + } +} + +void scroll_bar(void) { + + // 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_write_inst(0x40 + 7 * 8); // 0 1 A A A A A A Set 6 bit CGRAM address in address counter + for (int j = 0; j < 8; j++) { + lcd_write_data((3 << (5 - i%6)) >> 1); // Fill 8 bytes for vertical bar character in Character Generator RAM. + } + lcd_write_inst(0x80 + i / 6 - (i >= 6)); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + if (i >= 6) lcd_write_data(0x20); + lcd_write_data(7); // Top row. + lcd_write_inst(0xC0 + i / 6 - (i >= 6)); // 1 A A A A A A A Set 7 bit DDRAM address in address counter + if (i >= 6) lcd_write_data(0x20); + lcd_write_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. + uint8_t str[17]; // String for writing to the LCD display. + + wait(0.040); // LCD initialisation takes 40ms. + lcd_clear(); + lcd_write_inst(0x0C); // 0000 1DCB Display=1 Cursor=0 Blink=0 + lcd_write_inst(0x38); // 001D NFxx Data interface 8 (4) bits, Number of lines 2 (1), Font 5x11 if 1 line (5x8) + + lcd_write_str((uint8_t *)"Trinary", 4, 0); + lcd_write_str((uint8_t *)"Counter", 4, 1); + + // Flash display off/on a couple of times. + for (int i = 0; i < 2; i++) { + wait(0.5); + lcd_write_inst(0x08); // 0000 1DCB Display=0 Cursor=0 Blink=0 + wait(0.5); + lcd_write_inst(0x0C); // 0000 1DCB Display=1 Cursor=0 Blink=0 + } + + wait(1); + scroll_face(); + //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((char *)str, "dec %2d tri %d%d%d%d", i, (i / 27) % 3, (i / 9) % 3, (i / 3) % 3, i % 3); + lcd_write_str(str); + // Write hex and binary. + sprintf((char *)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_write_str(str, 0, 1); + } + 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. + } +}