/* * Arduino library to drive an LCD display that uses a Toshiba T6A34 controller chip * Based on the structure of the standard LiquidCrystal.cpp routines for the Hitachi HD44780 chip * The T6A34 commands are basically the same as the HD44780, so this is usable as a replacement * for the LiquidCrystal library, but compatibility hasn't been extensively tested. * * Thanks to the authors of the standard LiquidCrystal.cpp HD44780 library. * Author Tony Wills * Licensed CC-BY-SA * * 20181119 Initial release version 1.00 * 20181120 Ver 1.10 added LED control * 20181217 Ver 1.11 fixed createChar() to direct data input back to screen ram * see http://www.arduino.scorchingbay.nz (or an archive.org copy) for more information */ #include "LiquidCrystal_t6a34.h" #include #include #include #include #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #endif // When the display is reset, it is configured as follows: // // 1. Display clear // 2. Function set: // BL = 1; Blink mode is all pixels on // N = 0; 1-line display // F = 0; 5x7 dot character font // 3. Entry mode set: // I/D = 1; Increment by 1 // S = 0; No shift // 4. Display on/off control: // D = 0; Display off // C = 0; Cursor off // B = 0; Blinking off // LiquidCrystal::LiquidCrystal(uint8_t data_in, uint8_t data_out, uint8_t clk) { init(data_in, data_out, clk); } LiquidCrystal::LiquidCrystal(uint8_t data_in, uint8_t clk) { init(data_in, 255, clk); } void LiquidCrystal::init(uint8_t data_in, uint8_t data_out, uint8_t clk) { _sid_pin = data_in; _sod_pin = data_out; _sclk_pin = clk; digitalWrite(_sid_pin, HIGH); //set high before enabling as output pinMode(_sid_pin, OUTPUT); //delayMicroseconds(2); //ensure data settled as high before enabling clock so don't get random start bits //for (int i=0; i<1000; i++) {}; digitalWrite(_sclk_pin, HIGH); //set high before enabling as output pinMode(_sclk_pin, OUTPUT); //setup clock for t6a34 lcd chip Timer1.initialize(period); //initialize timer1 Timer1.pwm(_sclk_pin, duty); //setup pwm on _sclk_pin, 50% duty cycle Timer1.start(); //delay(2000); if (_sod_pin != 255) { pinMode(_sod_pin, INPUT); } _displayfunction = LCD_BLINKMODE | LCD_1LINE | LCD_5x7DOTS; command(LCD_FUNCTIONSET | _displayfunction); } void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { if (lines > 1) { _displayfunction |= LCD_2LINE; } _numlines = lines; _currline = 0; // for some 1 line displays you can select a 10 pixel high font if ((dotsize != 0) && (lines == 1)) { _displayfunction |= LCD_5x10DOTS; } // set # lines, font size, etc. command(LCD_FUNCTIONSET | _displayfunction); // turn the display on with no cursor or blinking default _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; display(); // clear it off clear(); // Initialize to default text direction (for romance languages) _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; // set the entry mode command(LCD_ENTRYMODESET | _displaymode); } /********** high level commands, for the user! */ void LiquidCrystal::clear() { command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero delayMicroseconds(clear_delay); // this command takes a long time! } void LiquidCrystal::home() { command(LCD_RETURNHOME); // set cursor position to zero delayMicroseconds(home_delay); // this command takes a long time! } void LiquidCrystal::setCursor(uint8_t col, uint8_t row) { int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; if ( row > _numlines ) { row = _numlines-1; // we count rows starting w/0 } command(LCD_SETDDRAMADDR | (col + row_offsets[row])); } // Turn the display on/off (quickly) void LiquidCrystal::noDisplay() { _displaycontrol &= ~LCD_DISPLAYON; command(LCD_DISPLAYCONTROL | _displaycontrol); } void LiquidCrystal::display() { _displaycontrol |= LCD_DISPLAYON; command(LCD_DISPLAYCONTROL | _displaycontrol); } // Turns the underline cursor on/off void LiquidCrystal::noCursor() { _displaycontrol &= ~LCD_CURSORON; command(LCD_DISPLAYCONTROL | _displaycontrol); } void LiquidCrystal::cursor() { _displaycontrol |= LCD_CURSORON; command(LCD_DISPLAYCONTROL | _displaycontrol); } // Turn on and off the blinking cursor void LiquidCrystal::noBlink() { _displaycontrol &= ~LCD_BLINKON; command(LCD_DISPLAYCONTROL | _displaycontrol); } void LiquidCrystal::blink() { _displaycontrol |= LCD_BLINKON; command(LCD_DISPLAYCONTROL | _displaycontrol); } // These commands scroll the display without changing the RAM void LiquidCrystal::scrollDisplayLeft(void) { command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); } void LiquidCrystal::scrollDisplayRight(void) { command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); } // This is for text that flows Left to Right void LiquidCrystal::leftToRight(void) { _displaymode |= LCD_ENTRYLEFT; command(LCD_ENTRYMODESET | _displaymode); } // This is for text that flows Right to Left void LiquidCrystal::rightToLeft(void) { _displaymode &= ~LCD_ENTRYLEFT; command(LCD_ENTRYMODESET | _displaymode); } // This will 'right justify' text from the cursor void LiquidCrystal::autoscroll(void) { _displaymode |= LCD_ENTRYSHIFTINCREMENT; command(LCD_ENTRYMODESET | _displaymode); } // This will 'left justify' text from the cursor void LiquidCrystal::noAutoscroll(void) { _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; command(LCD_ENTRYMODESET | _displaymode); } // Allows us to fill the first 8 CGRAM locations // with custom characters void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) { location &= 0x7; // we only have 8 locations 0-7 command(LCD_SETCGRAMADDR | (location << 3)); for (int i=0; i<8; i++) { write(charmap[i]); } setCursor(0,0); // direct data input back to screen ram } /*********** mid level commands, for sending data/cmds */ inline void LiquidCrystal::command(uint8_t value) { send(value, IR_WRITE); delayMicroseconds(cmd_delay); } inline size_t LiquidCrystal::write(uint8_t value) { send(value, DR_WRITE); return 1; // assume sucess delayMicroseconds(cmd_delay); } void LiquidCrystal::setLeds(uint16_t value) { send((value & 0xFF), LER1_WRITE); send(((value >> 8) & 0xFF), LER2_WRITE); } /************ low level data pushing commands **********/ // write either command or data void LiquidCrystal::send(uint8_t value, uint8_t mode) { Timer1.disablePwm(_sclk_pin); //Turn off pwm clock so we can manually clock data //write start bits digitalWrite(_sid_pin, 0); //3 zero bits as start digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); //write rs bits digitalWrite(_sid_pin, mode & 0x01); //rs1 first digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); digitalWrite(_sid_pin, (mode >> 1) & 0x01); //rs2 second digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); //write the command/data byte for (int i = 0; i < 8; i++) { digitalWrite(_sid_pin, (value >> i) & 0x01); //lsb first digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); } //write out 3 explicit stop bits digitalWrite(_sid_pin, 1); //3 one bits as stop digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); digitalWrite(_sclk_pin, LOW); digitalWrite(_sclk_pin, HIGH); //turn on pwm clock to keep LCD alive Timer1.initialize(period); //initialize timer1 Timer1.pwm(_sclk_pin, duty); Timer1.start(); }