Derived work demoing the Crystalfontz CHARACTER LCD MODULE

Dependencies:   mbed

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