// --------------------------------------------------------------------------- // Created by Francisco Malpartida on 7.3.2012. // Copyright 2011 - Under creative commons license 3.0: // Attribution-ShareAlike CC BY-SA // // This software is furnished "as is", without technical support, and with no // warranty, express or implied, as to its usefulness for any purpose. // // Thread Safe: No // Extendable: Yes // // @file LiquidCrystal_SRG.h // This file implements a basic liquid crystal library that comes as standard // in the Arduino SDK but using a generic SHIFT REGISTER extension board. // // @brief // This is a basic implementation of the LiquidCrystal library of the // Arduino SDK. The original library has been reworked in such a way that // this class implements the all methods to command an LCD based // on the Hitachi HD44780 and compatible chipsets using a 3 wire latching // shift register. While it has been tested with a 74HC595N shift register // it should also work with other latching shift registers such as the MC14094 // and the HEF4094 // // This particular driver has been created as generic as possible to enable // users to configure and connect their LCDs using just 3 digital IOs from the // AVR or Arduino, and connect the LCD to the outputs of the shiftregister // in any configuration. The library is configured by passing the IO pins // that control the strobe, data and clock of the shift register and a map // of how the shiftregister is connected to the LCD. // // // +--------------------------------------------+ // | MCU | // | IO1 IO2 IO3 | // +----+-------------+-------------+-----------+ // | | | // | | | // +----+-------------+-------------+-----------+ // | Strobe Data Clock | // | 8-bit shift/latch register | 74HC595N // | Qa0 Qb1 Qc2 Qd3 Qe4 Qf5 Qg6 Qh7 | // +----+----+----+----+----+----+----+----+----+ // | | | | | | | // |11 |12 |13 |14 |6 |5 |4 (LCD pins) // +----+----+----+----+----+----+----+----+----+ // | DB4 DB5 DB6 DB7 E Rw RS | // | LCD Module | // // NOTE: Rw is not used by the driver so it can be connected to GND. // // The functionality provided by this class and its base class is identical // to the original functionality of the Arduino LiquidCrystal library. // // // History // 2012.03.29 bperrybap - fixed constructors not properly using Rs // Fixed incorrect use of 5x10 for default font // - now matches original LQ library. // moved delay to send() so it is per cmd/write vs shiftout() // NOTE: delay is on hairy edge of working when FAST_MODE is on. // because of waitUsec(). // There is margin at 16Mhz AVR but might fail on 20Mhz AVRs. // // @author F. Malpartida - fmalpartida@gmail.com // --------------------------------------------------------------------------- // flags for backlight control #include #include #include #if (ARDUINO < 100) #include #else #include #endif #include "LiquidCrystal_SR3W.h" #include "FastIO.h" /*! @defined @abstract LCD_NOBACKLIGHT @discussion No BACKLIGHT MASK */ #define LCD_NOBACKLIGHT 0x00 /*! @defined @abstract LCD_BACKLIGHT @discussion BACKLIGHT MASK used when backlight is on */ #define LCD_BACKLIGHT 0xFF // Default library configuration parameters used by class constructor with // only the I2C address field. // --------------------------------------------------------------------------- /*! @defined @abstract Enable bit of the LCD @discussion Defines the IO of the expander connected to the LCD's Enable */ #define EN 4 // Enable bit /*! @defined @abstract Read/Write bit of the LCD @discussion Defines the IO of the expander connected to the LCD's Rw pin */ #define RW 5 // Read/Write bit /*! @defined @abstract Register bit of the LCD @discussion Defines the IO of the expander connected to the LCD's Register select pin */ #define RS 6 // Register select bit /*! @defined @abstract LCD dataline allocation this library only supports 4 bit LCD control mode. @discussion D4, D5, D6, D7 LCD data lines pin mapping of the extender module */ #define D4 0 #define D5 1 #define D6 2 #define D7 3 LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe) { init( data, clk, strobe, RS, RW, EN, D4, D5, D6, D7 ); } LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe, uint8_t backlighPin, t_backlighPol pol) { init( data, clk, strobe, RS, RW, EN, D4, D5, D6, D7 ); setBacklightPin(backlighPin, pol); } LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe, uint8_t En, uint8_t Rw, uint8_t Rs, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 ) { init( data, clk, strobe, Rs, Rw, En, d4, d5, d6, d7 ); } LiquidCrystal_SR3W::LiquidCrystal_SR3W(uint8_t data, uint8_t clk, uint8_t strobe, uint8_t En, uint8_t Rw, uint8_t Rs, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, uint8_t backlighPin, t_backlighPol pol) { init( data, clk, strobe, Rs, Rw, En, d4, d5, d6, d7 ); setBacklightPin(backlighPin, pol); } void LiquidCrystal_SR3W::send(uint8_t value, uint8_t mode) { if ( mode != FOUR_BITS ) { write4bits( (value >> 4), mode ); // upper nibble } write4bits( (value & 0x0F), mode); // lower nibble #if (F_CPU <= 16000000) // No need to use the delay routines on AVR since the time taken to write // on AVR with SR pin mapping even with fio is longer than LCD command execution. waitUsec(37); //goes away on AVRs #else delayMicroseconds ( 37 ); // commands & data writes need > 37us to complete #endif } void LiquidCrystal_SR3W::setBacklightPin ( uint8_t value, t_backlighPol pol = POSITIVE ) { _backlightPinMask = ( 1 << value ); _backlightStsMask = LCD_NOBACKLIGHT; _polarity = pol; setBacklight (BACKLIGHT_OFF); // Set backlight to off as initial setup } void LiquidCrystal_SR3W::setBacklight ( uint8_t value ) { // Check if backlight is available // ---------------------------------------------------- if ( _backlightPinMask != 0x0 ) { // Check for polarity to configure mask accordingly // ---------------------------------------------------------- if (((_polarity == POSITIVE) && (value > 0)) || ((_polarity == NEGATIVE ) && ( value == 0 ))) { _backlightStsMask = _backlightPinMask & LCD_BACKLIGHT; } else { _backlightStsMask = _backlightPinMask & LCD_NOBACKLIGHT; } loadSR( _backlightStsMask ); } } // PRIVATE METHODS // ----------------------------------------------------------------------------- int LiquidCrystal_SR3W::init(uint8_t data, uint8_t clk, uint8_t strobe, uint8_t Rs, uint8_t Rw, uint8_t En, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) { _data = fio_pinToBit(data); _clk = fio_pinToBit(clk); _strobe = fio_pinToBit(strobe); _data_reg = fio_pinToOutputRegister(data); _clk_reg = fio_pinToOutputRegister(clk); _strobe_reg = fio_pinToOutputRegister(strobe); // LCD pin mapping _backlightPinMask = 0; _backlightStsMask = LCD_NOBACKLIGHT; _polarity = POSITIVE; _En = ( 1 << En ); _Rw = ( 1 << Rw ); _Rs = ( 1 << Rs ); // Initialise pin mapping _data_pins[0] = ( 1 << d4 ); _data_pins[1] = ( 1 << d5 ); _data_pins[2] = ( 1 << d6 ); _data_pins[3] = ( 1 << d7 ); _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; return (1); } void LiquidCrystal_SR3W::write4bits(uint8_t value, uint8_t mode) { uint8_t pinMapValue = 0; // Map the value to LCD pin mapping // -------------------------------- for ( uint8_t i = 0; i < 4; i++ ) { if ( ( value & 0x1 ) == 1 ) { pinMapValue |= _data_pins[i]; } value = ( value >> 1 ); } // Is it a command or data // ----------------------- mode = ( mode == DATA ) ? _Rs : 0; pinMapValue |= mode | _backlightStsMask; loadSR ( pinMapValue | _En ); // Send with enable high loadSR ( pinMapValue); // Send with enable low } void LiquidCrystal_SR3W::loadSR(uint8_t value) { // Load the shift register with information fio_shiftOut(_data_reg, _data, _clk_reg, _clk, value, MSBFIRST); // Strobe the data into the latch ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { fio_digitalWrite_HIGH(_strobe_reg, _strobe); fio_digitalWrite_SWITCHTO(_strobe_reg, _strobe, LOW); } }