diff --git a/examples/tinyLCD_I2C_Test/tinyLCD_I2C_Test.ino b/examples/tinyLCD_I2C_Test/tinyLCD_I2C_Test.ino new file mode 100644 index 0000000..d0184db --- /dev/null +++ b/examples/tinyLCD_I2C_Test/tinyLCD_I2C_Test.ino @@ -0,0 +1,28 @@ +#include +#include + +tinyLCD_I2C lcd(0x50,16,2); +float vdd; + +void setup() +{ + lcd.init(); // initialize the lcd + //lcd.backlight(); // not implemented yet + delay(1); + lcd.print("HELLO - WORLD!"); + delay(1200); + lcd.setCursor(0,1); + lcd.print("B-O-X-T-E-C-1-3"); + delay(1200); + lcd.showFirmware(); + delay(1500); + lcd.clear(); + lcd.print("Uptime now (us):"); +} + +void loop() { + lcd.setCursor(0,1); + lcd.print(millis()/1); + lcd.print(" us"); + delay(10); +} diff --git a/firmware/tinyLCD_I2C/tinyLCD_I2C.ino b/firmware/tinyLCD_I2C/tinyLCD_I2C.ino new file mode 100644 index 0000000..6391c16 --- /dev/null +++ b/firmware/tinyLCD_I2C/tinyLCD_I2C.ino @@ -0,0 +1,230 @@ +// $Id: tinyLCD_I2C.ino,v 1.13 2013-07-03 14:59:55 obiwan Exp $ + +#include +#include + +// Debug Mode +#define DBGME + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 +#define LCD_SETDIMENSION 0x9f +#define LCD_SETCURSOR 0x9e +#define LCD_SHOWFIRMWAREREVISION 0x9d + +// flags for backlight control +#define LCD_BACKLIGHT 0x81 +#define LCD_NOBACKLIGHT 0x80 + +// I2C address/buffersize +#define I2C_SLAVE_ADDRESS 0x50 +#define TWI_RX_BUFFER_SIZE ( 32 ) + +#define CONTRAST_PIN 2 + +// Timeout in us after which we close the buffer and write it out +#define CHARBUF_TIMEOUT 150 + +volatile uint8_t i2c_regs[] = +{ + 0xDE, + 0xAD, + 0xBE, + 0xEF, +}; +// Tracks the current register pointer position +volatile byte reg_position; +// buffer index for lcd.print strings +unsigned int buf_ix = 0; +// store time when the last char to print was received +unsigned long lastwrite = 0; +// char buffer for incoming strings +char bigbuffer[32]; +// more data expected +volatile byte data_expected = 0; + +// initialize the library with the numbers of the interface pins +// LiquidCrystal(rs, enable, d4, d5, d6, d7); +// Breadboard: +//LiquidCrystal lcd(0, 3, 7, 8, 9, 10); +// tinyLCD_I2C: +LiquidCrystal lcd(3, 1, 9, 8, 7, 5); + +void setup() { + TinyWireS.begin(I2C_SLAVE_ADDRESS); + TinyWireS.onReceive(receiveEvent); + //TinyWireS.onRequest(requestEvent); + analogWrite(CONTRAST_PIN, 10); + lcd.begin(16,2); + lcd.clear(); + //test_lcd(); +} + +void loop() { + if ( buf_ix > 0 && micros() - lastwrite > CHARBUF_TIMEOUT ) { + flush_buffer(); + } + TinyWireS_stop_check(); +} + + +// not used yet: +void requestEvent() +{ + TinyWireS.send(i2c_regs[reg_position]); + // Increment the reg position on each read, and loop back to zero + reg_position = (reg_position+1) % sizeof(i2c_regs); + lcd.setCursor(3, 1); + lcd.print("="); +} + +void receiveEvent(uint8_t howMany) { + //static int buf_ix = 0; + if (howMany < 1) + { + // Sanity-check + return; + } + + char cmd = TinyWireS.receive(); + // wait for a command + if ( cmd == 0 ) { + while (howMany < 1) { + tws_delay(1); + } + char rxbuffer = TinyWireS.receive(); + commandByte(rxbuffer); + } + /* + // direct print + else if ( cmd == 1 ) { + //lcd.print(rxbuffer); + // are we receiving a larger string ? Keep adding to buffer + if ( buf_ix == 0 || micros() - lastwrite < CHARBUF_TIMEOUT ) { + bigbuffer[buf_ix] = rxbuffer; + buf_ix++; + } + } + */ + else if ( cmd > 1 ) { + lcd.print(cmd); + } +} + +void commandByte(char c) { + uint8_t cols, rows, col, row; + switch (c) { + case LCD_CLEARDISPLAY: + #ifdef DBGME + lcd.print("Clear Display!"); + #endif + lcd.clear(); + break; + case LCD_RETURNHOME: + #ifdef DBGME + lcd.print("Return Home!"); + #endif + lcd.home(); + break; + case LCD_BACKLIGHT: + #ifdef DBGME + lcd.print("Backlight!"); + #endif + break; + case LCD_NOBACKLIGHT: + #ifdef DBGME + lcd.print("No Backlight!"); + #endif + break; + case LCD_SETDIMENSION: + TinyWireS.receive(); + cols = TinyWireS.receive(); + TinyWireS.receive(); + rows = TinyWireS.receive(); + #ifdef DBGME + lcd.print("Set Dim:"); + lcd.print(int(cols)); + lcd.print(" / "); + lcd.print(int(rows)); + tws_delay(660); + #endif + lcd_begin(cols, rows); + break; + case LCD_SETCURSOR: + if ( TinyWireS.receive() == 0 ) { + col = TinyWireS.receive(); + if ( TinyWireS.receive() == 0 ) { + row = TinyWireS.receive(); + } + } + #ifdef DBGME + lcd.print("Set Cursor:"); + lcd.setCursor(0,1); + lcd.print(int(col)); + lcd.print(" - "); + lcd.print(int(row)); + tws_delay(660); + #endif + lcd.setCursor(col, row); + break; + case LCD_SHOWFIRMWAREREVISION: + lcd_revision(); + break; + default: + #ifdef DBGME + lcd.print("Unknown Com!"); + lcd.setCursor(1,1); + lcd.print(int(c)); + #endif + break; + } +} + +// start the display, helper for init() +void lcd_begin(uint8_t cols, uint8_t rows) { + lcd.begin(cols,rows); + lcd.home(); + lcd.clear(); +} + +// display revision +void lcd_revision() { + lcd.clear(); + lcd.print("tinyLCD_I2C :"); + lcd.setCursor(0, 1); + lcd.print("$Revision: 1.13 $"); +} + +// flush receive buffer and output to LCD +void flush_buffer() { + lcd.print(bigbuffer); + buf_ix = 0; + memset(&bigbuffer[0], 0, sizeof(bigbuffer)); +} + +void test_lcd() { + lcd.print("==T=E=S=T======="); + delay(1200); + lcd.setCursor(0,1); + lcd.print("XXXXXXXXXXXXXXX"); + delay(1200); + lcd.clear(); + lcd.print("XXXXXXXXXXXXXXXX"); + lcd.setCursor(0,1); + lcd.print("================"); + delay(2000); + lcd.clear(); + lcd.print("Uptime now (s):"); + while ( 1 ) { + lcd.setCursor(0,1); + lcd.print(millis()/1); + lcd.print(" us"); + } +} diff --git a/src/tinyLCD_I2C/tinyLCD_I2C.cpp b/src/tinyLCD_I2C/tinyLCD_I2C.cpp new file mode 100644 index 0000000..c94015f --- /dev/null +++ b/src/tinyLCD_I2C/tinyLCD_I2C.cpp @@ -0,0 +1,265 @@ +// $Id: tinyLCD_I2C.cpp,v 1.12 2013-07-03 14:52:53 obiwan Exp $ +// + +#include "tinyLCD_I2C.h" +#include +#include "Wire.h" +#if ARDUINO < 100 + #include +#else + #include +#endif + +tinyLCD_I2C::tinyLCD_I2C(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows) +{ + _Addr = lcd_addr; + _cols = lcd_cols; + _rows = lcd_rows; + _backlightval = LCD_NOBACKLIGHT; +} + +void tinyLCD_I2C::init(){ + init_priv(); +} + +void tinyLCD_I2C::init_priv() +{ + Wire.begin(); + begin(_cols, _rows); +} + +void tinyLCD_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { + displayDimension(cols, lines); + delayMicroseconds(550*1000); + clear(); + delayMicroseconds(850*1000); + home(); + delayMicroseconds(650*1000); +} + +void tinyLCD_I2C::displayDimension(uint8_t cols, uint8_t lines) { + command(LCD_SETDIMENSION); + command(cols); + command(lines); +} + +// clear display +void tinyLCD_I2C::clear(){ + command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero + delayMicroseconds(400); // this command takes a long time! +} + +// jump to 0,0 +void tinyLCD_I2C::home(){ + command(LCD_RETURNHOME); // set cursor position to zero + delayMicroseconds(400); // this command takes a long time! +} + +// set cursor position +void tinyLCD_I2C::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])); */ + command(LCD_SETCURSOR); + delayMicroseconds(2500); + command(col); + delayMicroseconds(2500); + command(row); + delayMicroseconds(2500); +} + + +// Turn the display on/off (quickly) +void tinyLCD_I2C::noDisplay() { + _displaycontrol &= ~LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void tinyLCD_I2C::display() { + _displaycontrol |= LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns the underline cursor on/off +void tinyLCD_I2C::noCursor() { + _displaycontrol &= ~LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void tinyLCD_I2C::cursor() { + _displaycontrol |= LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turn on and off the blinking cursor +void tinyLCD_I2C::noBlink() { + _displaycontrol &= ~LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void tinyLCD_I2C::blink() { + _displaycontrol |= LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// These commands scroll the display without changing the RAM +void tinyLCD_I2C::scrollDisplayLeft(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); +} +void tinyLCD_I2C::scrollDisplayRight(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); +} + +// This is for text that flows Left to Right +void tinyLCD_I2C::leftToRight(void) { + _displaymode |= LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This is for text that flows Right to Left +void tinyLCD_I2C::rightToLeft(void) { + _displaymode &= ~LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'right justify' text from the cursor +void tinyLCD_I2C::autoscroll(void) { + _displaymode |= LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'left justify' text from the cursor +void tinyLCD_I2C::noAutoscroll(void) { + _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// Allows us to fill the first 8 CGRAM locations +// with custom characters +void tinyLCD_I2C::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]); + } +} + +// Turn the (optional) backlight off/on +void tinyLCD_I2C::noBacklight(void) { + _backlightval=LCD_NOBACKLIGHT; + command(LCD_NOBACKLIGHT); +} + +void tinyLCD_I2C::backlight(void) { + _backlightval=LCD_BACKLIGHT; + command(LCD_BACKLIGHT); +} + + + +/*********** mid level commands, for sending data/cmds */ + +inline void tinyLCD_I2C::command(uint8_t value) { + send(value, 0); +} + +inline size_t tinyLCD_I2C::write(uint8_t value) { + send(value, Rs); + return 0; +} + + + +/************ low level data pushing commands **********/ + +// write either command or data +void tinyLCD_I2C::send(uint8_t value, uint8_t mode) { + /* + uint8_t highnib=value>>4; + uint8_t lownib=value & 0x0F; + write4bits((highnib)|mode); + write4bits((lownib)|mode); + */ + Wire.beginTransmission(_Addr); + if ( mode == 0 ) { + Wire.write(mode); + } + // bad delay, need to make the opposite site faster by using a buffer + delayMicroseconds(80); + Wire.write((int)(value)); + Wire.endTransmission(); +} + +/* +void tinyLCD_I2C::write4bits(uint8_t value) { + expanderWrite(value); + pulseEnable(value); +} + +void tinyLCD_I2C::expanderWrite(uint8_t _data){ + Wire.beginTransmission(_Addr); + Wire.write((int)(_data) | _backlightval); + Wire.endTransmission(); +} + +void tinyLCD_I2C::pulseEnable(uint8_t _data){ + expanderWrite(_data | En); // En high + delayMicroseconds(1); // enable pulse must be >450ns + + expanderWrite(_data & ~En); // En low + delayMicroseconds(50); // commands need > 37us to settle +} +*/ + + +// Alias functions + +void tinyLCD_I2C::cursor_on(){ + cursor(); +} + +void tinyLCD_I2C::cursor_off(){ + noCursor(); +} + +void tinyLCD_I2C::blink_on(){ + blink(); +} + +void tinyLCD_I2C::blink_off(){ + noBlink(); +} + +void tinyLCD_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){ + createChar(char_num, rows); +} + +void tinyLCD_I2C::setBacklight(uint8_t new_val){ + if(new_val){ + backlight(); // turn backlight on + }else{ + noBacklight(); // turn backlight off + } +} + +void tinyLCD_I2C::printstr(const char c[]){ + //This function is not identical to the function used for "real" I2C displays + //it's here so the user sketch doesn't have to be changed + print(c); +} + +// display firmware revision +void tinyLCD_I2C::showFirmware(){ + command(LCD_SHOWFIRMWAREREVISION);// clear display, set cursor position to zero +} + +// unsupported API functions +void tinyLCD_I2C::off(){} +void tinyLCD_I2C::on(){} +void tinyLCD_I2C::setDelay (int cmdDelay,int charDelay) {} +uint8_t tinyLCD_I2C::status(){return 0;} +uint8_t tinyLCD_I2C::keypad (){return 0;} +uint8_t tinyLCD_I2C::init_bargraph(uint8_t graphtype){return 0;} +void tinyLCD_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end){} +void tinyLCD_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end){} +void tinyLCD_I2C::setContrast(uint8_t new_val){} + diff --git a/src/tinyLCD_I2C/tinyLCD_I2C.h b/src/tinyLCD_I2C/tinyLCD_I2C.h new file mode 100644 index 0000000..59b4029 --- /dev/null +++ b/src/tinyLCD_I2C/tinyLCD_I2C.h @@ -0,0 +1,141 @@ +// tinyLCD_I2C.h +// $Id: tinyLCD_I2C.h,v 1.9 2013-07-03 14:59:55 obiwan Exp $ +// +// derived from standard I2C Library +// 2013 boxtec.ch +// + +#ifndef tinyLCD_I2C_h +#define tinyLCD_I2C_h + +#include +#include "Print.h" +#include + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 +#define LCD_SETDIMENSION 0x9f +#define LCD_SETCURSOR 0x9e +#define LCD_SHOWFIRMWAREREVISION 0x9d +#define LCD_SETDIMENSION 0x9f +#define LCD_SETCURSOR 0x9e +#define LCD_AUTOSCROLL 0x17 +#define LCD_NOAUTOSCROLL 0x1a +#define LCD_SHOWFIRMWAREREVISION 0x1b + + +// flags for display entry mode +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +#define LCD_5x10DOTS 0x04 +#define LCD_5x8DOTS 0x00 + +// flags for backlight control +#define LCD_BACKLIGHT 0x81 +#define LCD_NOBACKLIGHT 0x80 + +#define En B00000100 // Enable bit +#define Rw B00000010 // Read/Write bit +#define Rs B00000001 // Register select bit + + + +class tinyLCD_I2C : public Print { +public: + tinyLCD_I2C(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows); + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS ); + void displayDimension(uint8_t, uint8_t); + void clear(); + void home(); + void noDisplay(); + void display(); + void noBlink(); + void blink(); + void noCursor(); + void cursor(); + void scrollDisplayLeft(); + void scrollDisplayRight(); + void printLeft(); + void printRight(); + void leftToRight(); + void rightToLeft(); + void shiftIncrement(); + void shiftDecrement(); + void noBacklight(); + void backlight(); + void autoscroll(); + void noAutoscroll(); + void createChar(uint8_t, uint8_t[]); + void setCursor(uint8_t, uint8_t); +#if defined(ARDUINO) && ARDUINO >= 100 + virtual size_t write(uint8_t); +#else + virtual void write(uint8_t); +#endif + void command(uint8_t); + void init(); + void showFirmware(); + + ////compatibility API function aliases + void blink_on(); // alias for blink() + void blink_off(); // alias for noBlink() + void cursor_on(); // alias for cursor() + void cursor_off(); // alias for noCursor() + void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight() + void load_custom_character(uint8_t char_num, uint8_t *rows); // alias for createChar() + void printstr(const char[]); + +////Unsupported API functions (not implemented in this library) +uint8_t status(); +void setContrast(uint8_t new_val); +uint8_t keypad(); +void setDelay(int,int); +void on(); +void off(); +uint8_t init_bargraph(uint8_t graphtype); +void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end); +void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end); + + +private: + void init_priv(); + void send(uint8_t, uint8_t); + //void write4bits(uint8_t); + //void expanderWrite(uint8_t); + //void pulseEnable(uint8_t); + uint8_t _Addr; + uint8_t _displayfunction; + uint8_t _displaycontrol; + uint8_t _displaymode; + uint8_t _numlines; + uint8_t _cols; + uint8_t _rows; + uint8_t _backlightval; +}; + +#endif