+ Post New Thread
Page 1 of 2 1 2 LastLast
Results 1 to 20 of 23
  1. #1
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    [moved] Arduino / LCD / '595 cascade

    I am using the standard Arduino Liquidcrystal595.h with 3-wire connect successfully.
    My only problem is to extend this to use 5 additional outputs from a 2nd '595.
    How to modify the circuit while still using the existing LCD (HB44870) but adding the 2nd '595 to make use of additional outputs?
    And then how to modify the sketch?

  2. #2
    Full Member level 1
    Points: 609, Level: 5

    Join Date
    Apr 2016
    Posts
    115
    Helped
    0 / 0
    Points
    609
    Level
    5

    Re: [moved] Arduino / LCD / '595 cascade

    Show your code.



    •   Alt23rd September 2016, 19:15

      advertising

        
       

  3. #3
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    This part is working successfully.
    lcd595.jpg

    #include <LiquidCrystal595.h> // the library
    LiquidCrystal595 lcd(7,8,9); // datapin, latchpin, clockpin

    void setup() {
    lcd.begin(16,2); // LCD 1602

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("LCD 3-wire");
    lcd.setCursor(0,1);
    lcd.print("communicator");
    }

    void loop() {
    // not used.
    Example of what I'm looking at here.
    But instead the 1st '595 must run the LCD as per above and the 2nd '595 outputs switched on command from Arduino.



  4. #4
    Full Member level 1
    Points: 609, Level: 5

    Join Date
    Apr 2016
    Posts
    115
    Helped
    0 / 0
    Points
    609
    Level
    5

    Re: [moved] Arduino / LCD / '595 cascade

    I'm not sure what you mean, but if you want two LCDs...

    Code:
    #include <LiquidCrystal595.h> // the library
    LiquidCrystal595 lcd1(7,8,9); // datapin, latchpin, clockpin
    
    LiquidCrystal595 lcd2(4,5,6); // datapin, latchpin, clockpin
    
    void setup() {
    lcd1.begin(16,2); // LCD 1602
    lcd2.begin(16,2); // LCD 1602
    
    lcd1.clear();
    lcd2.clear();
    lcd1.setCursor(0,0);
    lcd2.setCursor(0,0);
    lcd1.print("LCD 3-wire");
    lcd2.print("Second LCD");
    lcd1.setCursor(0,1);
    lcd2.setCursor(0,1);
    lcd1.print("communicator");
    lcd2.print("is here");
    }
    you can change 4,5,6 pins to other suitable...



  5. #5
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    hi Alloy,
    Not really but you have given me another useful clue...!
    My system is split into 2 parts :
    (a) control unit, with Arduino, input, output, etc, and
    (b) display unit with LCD, 2 buttons, piezo beeper and 6 LEDs.
    The 2 parts are interconnected by one 8-core cable, so I'm severely limited.
    I.e. +5V, GND, 2 buttons, 3 for '595, only 1 remaining wire.
    By cascading 2 x '595 I don't need extra wires for my 6 LEDs and piezo.

    I now have this test rig working.

    // for 2 x 74HC595 ... (20160924)

    int SER_Pin = 8; // 14 / 595
    int RCLK_Pin = 9; // 12 / 595
    int SRCLK_Pin = 10; //11 / 595

    boolean reg [16];

    void setup() {

    pinMode (SER_Pin, OUTPUT);
    pinMode (RCLK_Pin, OUTPUT);
    pinMode (SRCLK_Pin, OUTPUT);

    //reset all register pins
    clearReg ();
    writeReg ();
    }

    void clearReg () {
    for(int i = 15; i >= 0; i--) {
    reg [i] = LOW;
    }
    }

    void writeReg () {

    digitalWrite (RCLK_Pin, LOW);

    for (int i = 15; i >= 0; i--) {
    digitalWrite (SRCLK_Pin, LOW);

    int val = reg [i];

    digitalWrite (SER_Pin, val);
    digitalWrite (SRCLK_Pin, HIGH);

    }
    digitalWrite (RCLK_Pin, HIGH);

    }

    void K(int index, int value) {
    reg [index] = value;
    }

    void loop() {

    K (0, 0);
    K (1, 1);
    K (2, 0);
    K (3, 0);
    K (4, 0);
    K (5, 0);
    K (6, 0);
    K (7, 1);
    K (8, 0);
    K (9, 0);
    K (10, 0);
    K (11, 0);
    K (12, 1);
    K (13, 0);
    K (14, 0);
    K (15, 1);

    writeReg();
    }
    so I imagine K0 ...K7 for LCD (I'll call it '595a) and K8+ for LEDs & piezo (on '595b).

    Looking at Liquidcrystal595.cpp ....
    Code:
     
    /* -----------------------------------------------------------------------------------
     * Adaption of the LiquidCrystal library shipped with Arduino 22
     * for use with 74HC595 shift register adapter board found on:
     * http://www.stephenhobley.com
     
     * Code adaption by Steve Hobley - February 2011
    
     /*---Shift Register 74HC595---
     * [SR Pin 14 (DS)]    to Arduino pin - Yellow wire [datapin]
     * [SR Pin 12 (ST_CP)] to Arduino pin - Green wire  [latchpin]
     * [SR Pin 11 (SH_CP)] to Arduino pin - White wire  [clockpin]
     * Black wire to Ground
     * Red wire to +5v
    
     -----Shift Reg to LCD--------
     * SR Pin 15  - ENABLE              10000000
     * SR Pin 1   - D4                        00000010 
     * SR Pin 2   - D5			   00000100
     * SR Pin 3   - D6			   00001000
     * SR Pin 4   - D7			  00010000
     * SR Pin 5   - MOSFET / LED1 00100000
     * SR Pin 6   - LED 2                  01000000
     * SR Pin 7   - RS                       00000001
     *
     * -----------------------------------------------------------------------------------
     */
    // 595 mappings - LED1 is also the backlight controller
    #define ENABLE_PIN  B00000001
    #define RS_PIN		B10000000
    #define LED1_PIN    B00100000
    #define LED2_PIN    B01000000
    #define DATABITS	B00011110
    
    #define PIN_D4		B00000010
    #define PIN_D5		B00000100
    #define PIN_D6		B00001000
    #define PIN_D7		B00010000
    
    #include "LiquidCrystal595.h"
    
    #include <stdio.h>
    #include <string.h>
    #include <inttypes.h>
    #include "WProgram.h"
    
    // When the display powers up, it is configured as follows:
    //
    // 1. Display clear
    // 2. Function set: 
    //    DL = 1; 8-bit interface data 
    //    N = 0; 1-line display 
    //    F = 0; 5x8 dot character font 
    // 3. Display on/off control: 
    //    D = 0; Display off 
    //    C = 0; Cursor off 
    //    B = 0; Blinking off 
    // 4. Entry mode set: 
    //    I/D = 1; Increment by 1 
    //    S = 0; No shift 
    //
    // Note, however, that resetting the Arduino doesn't reset the LCD, so we
    // can't assume that its in that state when a sketch starts (and the
    // LiquidCrystal constructor is called).
    
    LiquidCrystal595::LiquidCrystal595(uint8_t datapin, uint8_t latchpin, uint8_t clockpin)
    {
      init(datapin, latchpin, clockpin);
    }
    
    // Performs the shift, MSB first 
    void LiquidCrystal595::shift595()
    {
        digitalWrite(_latchpin, LOW);
        shiftOut(_datapin, _clockpin, MSBFIRST, _register);  
        digitalWrite(_latchpin, HIGH);
    }
    
    void LiquidCrystal595::init(uint8_t datapin, uint8_t latchpin, uint8_t clockpin)
    {
      _datapin  = datapin;
      _latchpin = latchpin;
      _clockpin = clockpin;
    
       pinMode(_datapin, OUTPUT);
       pinMode(_latchpin, OUTPUT);
       pinMode(_clockpin, OUTPUT);
       
       _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
      
      begin(16, 1);  
    }
    
    void LiquidCrystal595::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;
      }
    
      // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
      // according to datasheet, we need at least 40ms after power rises above 2.7V
      // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
      delayMicroseconds(50000); 
      // Now we pull both RS and R/W low to begin commands
      
      setRSPin(LOW);
      setEPin(LOW);
      shift595();
      
      //digitalWrite(_rs_pin, LOW);
      //digitalWrite(_enable_pin, LOW);
      
      //if (_rw_pin != 255) { 
      //  digitalWrite(_rw_pin, LOW);
      //}
      
      //put the LCD into 4 bit or 8 bit mode
      if (! (_displayfunction & LCD_8BITMODE)) 
      {
        // this is according to the hitachi HD44780 datasheet
        // figure 24, pg 46
    
        // we start in 8bit mode, try to set 4 bit mode
        write4bits(0x03);
        delayMicroseconds(4500); // wait min 4.1ms
    
        // second try
        write4bits(0x03);
        delayMicroseconds(4500); // wait min 4.1ms
        
        // third go!
        write4bits(0x03); 
        delayMicroseconds(150);
    
        // finally, set to 4-bit interface
        write4bits(0x02); 
      } else {
        // this is according to the hitachi HD44780 datasheet
        // page 45 figure 23
    
        // Send function set command sequence
        command(LCD_FUNCTIONSET | _displayfunction);
        delayMicroseconds(4500);  // wait more than 4.1ms
    
        // second try
        command(LCD_FUNCTIONSET | _displayfunction);
        delayMicroseconds(150);
    
        // third go
        command(LCD_FUNCTIONSET | _displayfunction);
      }
    
      // finally, 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 LiquidCrystal595::clear()
    {
      command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
      delayMicroseconds(2000);  // this command takes a long time!
    }
    
    void LiquidCrystal595::home()
    {
      command(LCD_RETURNHOME);  // set cursor position to zero
      delayMicroseconds(2000);  // this command takes a long time!
    }
    
    void LiquidCrystal595::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 LiquidCrystal595::noDisplay() {
      _displaycontrol &= ~LCD_DISPLAYON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    void LiquidCrystal595::display() {
      _displaycontrol |= LCD_DISPLAYON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    
    // Turns the underline cursor on/off
    void LiquidCrystal595::noCursor() {
      _displaycontrol &= ~LCD_CURSORON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    void LiquidCrystal595::cursor() {
      _displaycontrol |= LCD_CURSORON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    
    // Turn on and off the blinking cursor
    void LiquidCrystal595::noBlink() {
      _displaycontrol &= ~LCD_BLINKON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    void LiquidCrystal595::blink() {
      _displaycontrol |= LCD_BLINKON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    
    // These commands scroll the display without changing the RAM
    void LiquidCrystal595::scrollDisplayLeft(void) {
      command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
    }
    void LiquidCrystal595::scrollDisplayRight(void) {
      command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
    }
    
    // This is for text that flows Left to Right
    void LiquidCrystal595::leftToRight(void) {
      _displaymode |= LCD_ENTRYLEFT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // This is for text that flows Right to Left
    void LiquidCrystal595::rightToLeft(void) {
      _displaymode &= ~LCD_ENTRYLEFT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // This will 'right justify' text from the cursor
    void LiquidCrystal595::autoscroll(void) {
      _displaymode |= LCD_ENTRYSHIFTINCREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // This will 'left justify' text from the cursor
    void LiquidCrystal595::noAutoscroll(void) {
      _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // Allows us to fill the first 8 CGRAM locations
    // with custom characters
    void LiquidCrystal595::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]);
      }
    }
    
    /*********** mid level commands, for sending data/cmds */
    
    inline void LiquidCrystal595::command(uint8_t value) {
      send(value, LOW);
    }
    
    inline void LiquidCrystal595::write(uint8_t value) {
      send(value, HIGH);
    }
    
    /************ low level data pushing commands **********/
    
    // write either command or data, with automatic 4/8-bit selection
    void LiquidCrystal595::send(uint8_t value, uint8_t mode) 
    {
      setRSPin(mode);
      shift595();
      
      //digitalWrite(_rs_pin, mode);
    
      // if there is a RW pin indicated, set it low to Write
      //if (_rw_pin != 255) { 
      //  digitalWrite(_rw_pin, LOW);
      //}
      
      if (_displayfunction & LCD_8BITMODE) 
      {
        write8bits(value); 
      } 
      else 
      {
        write4bits(value>>4);
        write4bits(value);
      }
    }
    
    void LiquidCrystal595::pulseEnable(void) 
    {
       // LOW / HIGH / LOW of ENABLE_PIN
      setEPin(LOW);   // LOW
      shift595();
      
      delayMicroseconds(1);
      setEPin(HIGH);    // HIGH
      shift595();
      
      delayMicroseconds(1); // enable pulse must be >450ns
      
      setEPin(LOW);   // LOW
      shift595();
      delayMicroseconds(100);  // commands need > 37us to settle
    }
    
    void LiquidCrystal595::write4bits(uint8_t value) 
    {
      int val_nibble= value & 0x0F;  //clean the value.  (unnecessary)
    	
      setD4Pin(val_nibble & 01);
      val_nibble >>= 1;
      setD5Pin(val_nibble & 01);
      val_nibble >>= 1;
      setD6Pin(val_nibble & 01);
      val_nibble >>= 1;
      setD7Pin(val_nibble & 01);
      
      pulseEnable();
    }
    
    void LiquidCrystal595::write8bits(uint8_t value) 
    {
      return;
      // Should not be used
    }
    
    // Accessor functions --------------------------------------------------------
    void LiquidCrystal595::setLED1Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= LED1_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~LED1_PIN;   // LOW
    	}
    }
    
    void LiquidCrystal595::setLED2Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= LED2_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~LED2_PIN;   // LOW
    	}
    }
    
    void LiquidCrystal595::setEPin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= ENABLE_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~ENABLE_PIN;   // LOW
    	}
    }
    
    void LiquidCrystal595::setD4Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D4;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D4;   // LOW
    	}
    }
    
    void LiquidCrystal595::setD5Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D5;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D5;   // LOW
    	}
    }
    void LiquidCrystal595::setD6Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D6;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D6;   // LOW
    	}
    }
    void LiquidCrystal595::setD7Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D7;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D7;   // LOW
    	}
    }
    
    void LiquidCrystal595::setRSPin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= RS_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~RS_PIN;   // LOW
    	}
    }
    If I'm on the right track I imagine that connecting K0 ... K7 should happen here somewhere ...
    Code:
    // 595 mappings - LED1 is also the backlight controller
    #define ENABLE_PIN     B00000001
    #define RS_PIN		B10000000
    #define LED1_PIN          B00100000
    #define LED2_PIN          B01000000
    #define DATABITS   	B00011110
    
    #define PIN_D4		B00000010
    #define PIN_D5		B00000100
    #define PIN_D6		B00001000
    #define PIN_D7		B00010000
    but how to do that beats me for now.
    Also, should one interfere/muddle with the Liquidcrystal595 library? (perhaps rename a "new" library? Or can this be done in the normal code leaving that library intact, and if so, how?
    (Of course I could have saved 2 outputs using the setLEDxPin on '595a, but what the heck...?)

    Thanks and very good wishes.



  6. #6
    Super Moderator
    Points: 40,308, Level: 49
    Awards:
    Most Frequent Poster

    Join Date
    Apr 2014
    Posts
    8,240
    Helped
    1991 / 1991
    Points
    40,308
    Level
    49

    Re: [moved] Arduino / LCD / '595 cascade

    Hi,

    I hope I understand right:
    * two 595 connected in series:
    * MOSI --> 595A_SER (LCD)
    * 595A_QH--> 595B_SER
    * (optionlal: 595B_QH--> MISO)
    * all other control lines in parallel to both 595

    Software:
    * activate chipselect
    * write 8 bits for 595B
    * write 8 bits for 595A
    * deactivete chipselect

    Klaus



  7. #7
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    Not quite. I want to use one '595 for the LCD (which I call '595a) and 2nd ('595b) for additional LED indicators.
    I have a test rig working :
    Code:
    // for 2 x 74HC595   (20160924)
    
    int SER_Pin = 8;   // 14 / 595
    int RCLK_Pin = 9;  // 12 / 595
    int SRCLK_Pin = 10; //11 / 595
    
    boolean reg [16];
    
    void setup()  {
      
      pinMode (SER_Pin, OUTPUT);
      pinMode (RCLK_Pin, OUTPUT);
      pinMode (SRCLK_Pin, OUTPUT);
    
      //reset all register pins
      clearReg ();
      writeReg ();
    }               
    
    
    void clearReg () {
      for(int i = 15; i >=  0; i--) {
        reg [i] = LOW;
      }
    } 
    
    void writeReg ()  {
    
      digitalWrite (RCLK_Pin, LOW);
    
      for (int i = 15; i >=  0; i--)  {
        digitalWrite (SRCLK_Pin, LOW);
    
        int val = reg [i];
    
        digitalWrite (SER_Pin, val);
        digitalWrite (SRCLK_Pin, HIGH);
      }
      digitalWrite (RCLK_Pin, HIGH);
    }
    
    void K(int index, int value)  {
      reg [index] = value;
    }
    
    void loop(){
    
      K (0, 0);
      K (1, 1);
      K (2, 0);
      K (3, 0);
      K (4, 0);
      K (5, 0);
      K (6, 0);
      K (7, 1);
      K (8, 0);
      K (9, 0);
      K (10, 0);
      K (11, 0);
      K (12, 1);
      K (13, 0);
      K (14, 0);
      K (15, 1);
    
      writeReg();  
    }
    ... and then looking at Liquidcrystal595.cpp ...

    Code:
    /* -----------------------------------------------------------------------------------
     * Adaption of the LiquidCrystal library shipped with Arduino 22
     * for use with 74HC595 shift register adapter board found on:
     * http://www.stephenhobley.com
     
     * Code adaption by Steve Hobley - February 2011
    
     /*---Shift Register 74HC595---
     * [SR Pin 14 (DS)]    to Arduino pin - Yellow wire [datapin]
     * [SR Pin 12 (ST_CP)] to Arduino pin - Green wire  [latchpin]
     * [SR Pin 11 (SH_CP)] to Arduino pin - White wire  [clockpin]
     * Black wire to Ground
     * Red wire to +5v
    
     -----Shift Reg to LCD--------
     * SR Pin 15  - ENABLE        10000000
     * SR Pin 1   - D4            00000010 
     * SR Pin 2   - D5			  00000100
     * SR Pin 3   - D6			  00001000
     * SR Pin 4   - D7			  00010000
     * SR Pin 5   - MOSFET / LED1 00100000
     * SR Pin 6   - LED 2         01000000
     * SR Pin 7   - RS            00000001
     *
     * -----------------------------------------------------------------------------------
     */
    // 595 mappings - LED1 is also the backlight controller
    #define ENABLE_PIN  B00000001
    #define RS_PIN		B10000000
    #define LED1_PIN         B00100000
    #define LED2_PIN         B01000000
    #define DATABITS         B00011110
    
    #define PIN_D4		B00000010
    #define PIN_D5		B00000100
    #define PIN_D6		B00001000
    #define PIN_D7    		B00010000
    
    #include "LiquidCrystal595.h"
    
    #include <stdio.h>
    #include <string.h>
    #include <inttypes.h>
    #include "WProgram.h"
    
    // When the display powers up, it is configured as follows:
    //
    // 1. Display clear
    // 2. Function set: 
    //    DL = 1; 8-bit interface data 
    //    N = 0; 1-line display 
    //    F = 0; 5x8 dot character font 
    // 3. Display on/off control: 
    //    D = 0; Display off 
    //    C = 0; Cursor off 
    //    B = 0; Blinking off 
    // 4. Entry mode set: 
    //    I/D = 1; Increment by 1 
    //    S = 0; No shift 
    //
    // Note, however, that resetting the Arduino doesn't reset the LCD, so we
    // can't assume that its in that state when a sketch starts (and the
    // LiquidCrystal constructor is called).
    
    LiquidCrystal595::LiquidCrystal595(uint8_t datapin, uint8_t latchpin, uint8_t clockpin)
    {
      init(datapin, latchpin, clockpin);
    }
    
    // Performs the shift, MSB first 
    void LiquidCrystal595::shift595()
    {
        digitalWrite(_latchpin, LOW);
        shiftOut(_datapin, _clockpin, MSBFIRST, _register);  
        digitalWrite(_latchpin, HIGH);
    }
    
    void LiquidCrystal595::init(uint8_t datapin, uint8_t latchpin, uint8_t clockpin)
    {
      _datapin  = datapin;
      _latchpin = latchpin;
      _clockpin = clockpin;
    
       pinMode(_datapin, OUTPUT);
       pinMode(_latchpin, OUTPUT);
       pinMode(_clockpin, OUTPUT);
       
       _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
      
      begin(16, 1);  
    }
    
    void LiquidCrystal595::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;
      }
    
      // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
      // according to datasheet, we need at least 40ms after power rises above 2.7V
      // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
      delayMicroseconds(50000); 
      // Now we pull both RS and R/W low to begin commands
      
      setRSPin(LOW);
      setEPin(LOW);
      shift595();
      
      //digitalWrite(_rs_pin, LOW);
      //digitalWrite(_enable_pin, LOW);
      
      //if (_rw_pin != 255) { 
      //  digitalWrite(_rw_pin, LOW);
      //}
      
      //put the LCD into 4 bit or 8 bit mode
      if (! (_displayfunction & LCD_8BITMODE)) 
      {
        // this is according to the hitachi HD44780 datasheet
        // figure 24, pg 46
    
        // we start in 8bit mode, try to set 4 bit mode
        write4bits(0x03);
        delayMicroseconds(4500); // wait min 4.1ms
    
        // second try
        write4bits(0x03);
        delayMicroseconds(4500); // wait min 4.1ms
        
        // third go!
        write4bits(0x03); 
        delayMicroseconds(150);
    
        // finally, set to 4-bit interface
        write4bits(0x02); 
      } else {
        // this is according to the hitachi HD44780 datasheet
        // page 45 figure 23
    
        // Send function set command sequence
        command(LCD_FUNCTIONSET | _displayfunction);
        delayMicroseconds(4500);  // wait more than 4.1ms
    
        // second try
        command(LCD_FUNCTIONSET | _displayfunction);
        delayMicroseconds(150);
    
        // third go
        command(LCD_FUNCTIONSET | _displayfunction);
      }
    
      // finally, 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 LiquidCrystal595::clear()
    {
      command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
      delayMicroseconds(2000);  // this command takes a long time!
    }
    
    void LiquidCrystal595::home()
    {
      command(LCD_RETURNHOME);  // set cursor position to zero
      delayMicroseconds(2000);  // this command takes a long time!
    }
    
    void LiquidCrystal595::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 LiquidCrystal595::noDisplay() {
      _displaycontrol &= ~LCD_DISPLAYON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    void LiquidCrystal595::display() {
      _displaycontrol |= LCD_DISPLAYON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    
    // Turns the underline cursor on/off
    void LiquidCrystal595::noCursor() {
      _displaycontrol &= ~LCD_CURSORON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    void LiquidCrystal595::cursor() {
      _displaycontrol |= LCD_CURSORON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    
    // Turn on and off the blinking cursor
    void LiquidCrystal595::noBlink() {
      _displaycontrol &= ~LCD_BLINKON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    void LiquidCrystal595::blink() {
      _displaycontrol |= LCD_BLINKON;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
    }
    
    // These commands scroll the display without changing the RAM
    void LiquidCrystal595::scrollDisplayLeft(void) {
      command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
    }
    void LiquidCrystal595::scrollDisplayRight(void) {
      command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
    }
    
    // This is for text that flows Left to Right
    void LiquidCrystal595::leftToRight(void) {
      _displaymode |= LCD_ENTRYLEFT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // This is for text that flows Right to Left
    void LiquidCrystal595::rightToLeft(void) {
      _displaymode &= ~LCD_ENTRYLEFT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // This will 'right justify' text from the cursor
    void LiquidCrystal595::autoscroll(void) {
      _displaymode |= LCD_ENTRYSHIFTINCREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // This will 'left justify' text from the cursor
    void LiquidCrystal595::noAutoscroll(void) {
      _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
    }
    
    // Allows us to fill the first 8 CGRAM locations
    // with custom characters
    void LiquidCrystal595::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]);
      }
    }
    
    /*********** mid level commands, for sending data/cmds */
    
    inline void LiquidCrystal595::command(uint8_t value) {
      send(value, LOW);
    }
    
    inline void LiquidCrystal595::write(uint8_t value) {
      send(value, HIGH);
    }
    
    /************ low level data pushing commands **********/
    
    // write either command or data, with automatic 4/8-bit selection
    void LiquidCrystal595::send(uint8_t value, uint8_t mode) 
    {
      setRSPin(mode);
      shift595();
      
      //digitalWrite(_rs_pin, mode);
    
      // if there is a RW pin indicated, set it low to Write
      //if (_rw_pin != 255) { 
      //  digitalWrite(_rw_pin, LOW);
      //}
      
      if (_displayfunction & LCD_8BITMODE) 
      {
        write8bits(value); 
      } 
      else 
      {
        write4bits(value>>4);
        write4bits(value);
      }
    }
    
    void LiquidCrystal595::pulseEnable(void) 
    {
       // LOW / HIGH / LOW of ENABLE_PIN
      setEPin(LOW);   // LOW
      shift595();
      
      delayMicroseconds(1);
      setEPin(HIGH);    // HIGH
      shift595();
      
      delayMicroseconds(1); // enable pulse must be >450ns
      
      setEPin(LOW);   // LOW
      shift595();
      delayMicroseconds(100);  // commands need > 37us to settle
    }
    
    void LiquidCrystal595::write4bits(uint8_t value) 
    {
      int val_nibble= value & 0x0F;  //clean the value.  (unnecessary)
    	
      setD4Pin(val_nibble & 01);
      val_nibble >>= 1;
      setD5Pin(val_nibble & 01);
      val_nibble >>= 1;
      setD6Pin(val_nibble & 01);
      val_nibble >>= 1;
      setD7Pin(val_nibble & 01);
      
      pulseEnable();
    }
    
    void LiquidCrystal595::write8bits(uint8_t value) 
    {
      return;
      // Should not be used
    }
    
    // Accessor functions --------------------------------------------------------
    void LiquidCrystal595::setLED1Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= LED1_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~LED1_PIN;   // LOW
    	}
    }
    
    void LiquidCrystal595::setLED2Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= LED2_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~LED2_PIN;   // LOW
    	}
    }
    
    void LiquidCrystal595::setEPin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= ENABLE_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~ENABLE_PIN;   // LOW
    	}
    }
    
    void LiquidCrystal595::setD4Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D4;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D4;   // LOW
    	}
    }
    
    void LiquidCrystal595::setD5Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D5;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D5;   // LOW
    	}
    }
    void LiquidCrystal595::setD6Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D6;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D6;   // LOW
    	}
    }
    void LiquidCrystal595::setD7Pin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= PIN_D7;    // HIGH
    	}
    	else
    	{
    		_register &= ~PIN_D7;   // LOW
    	}
    }
    
    void LiquidCrystal595::setRSPin(uint8_t pinValue)
    {
    	if (pinValue == HIGH)
    	{
    		_register |= RS_PIN;    // HIGH
    	}
    	else
    	{
    		_register &= ~RS_PIN;   // LOW
    	}
    }
    I imagine that the changes for K0...K7 should happen here, leaving the remainder (K8...K15) for the add-on's.

    Code:
    // 595 mappings - LED1 is also the backlight controller
    #define ENABLE_PIN     B00000001
    #define RS_PIN		B10000000
    #define LED1_PIN         B00100000
    #define LED2_PIN         B01000000
    #define DATABITS         B00011110
    
    #define PIN_D4		B00000010
    #define PIN_D5		B00000100
    #define PIN_D6		B00001000
    #define PIN_D7    		B00010000
    But how to do this is beyond my level.
    Should I alter/muddle with the original library and change its name (risking breaking it) ?
    Or can changes be made in the new sketch leaving the original library intact?
    If so, how?



  8. #8
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    hi KlausST,
    Yes, I think you have it as I intended.
    Now to make it happen is another story !



  9. #9
    Full Member level 1
    Points: 609, Level: 5

    Join Date
    Apr 2016
    Posts
    115
    Helped
    0 / 0
    Points
    609
    Level
    5

    Re: [moved] Arduino / LCD / '595 cascade

    Quote Originally Posted by Adri67 View Post
    Should I alter/muddle with the original library and change its name (risking breaking it) ?
    Or can changes be made in the new sketch leaving the original library intact?
    If so, how?
    (I still don't fully understand what you want to do, but) You can always copy any library you want, rename it to ABCLibrary_myVersion and use and modify this copy.
    Just always remember to check the names of functions and files, also always have a backup copy...



    •   Alt24th September 2016, 17:00

      advertising

        
       

  10. #10
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    I will try to explain more clearly.
    I have the standard Arduino 3-wire design feeding a '595 (which I call '595a) to drive one LCD 1602. That works perfectly.
    But I need to INCREASE the number of digital outputs in my "display module" by using an additional '595 (called '595b) which is "cascaded" (or "daisy-chained") to '595a. (The reason for doing this is the few connection wires between Arduino in the "main unit" and the "display module" containing the two '595s and LCD .)

    Normally one can cascade 2 x '595. After serial data input (14a = pin 14 of '595a) has been set in QAa (15a) ... QHa (7a) (the first '595) it feeds from QH'a (9a) connected to SER input (14b) of '595b (the second '595). In this way data bits 00...07 switch '595a's outputs QAa... QHa, and data bits 08...15 should switch QAb...QHb.

    In other words :

    bit # Q output Pin/IC
    00 QAa 15a
    01 QBa 1a
    02 QCa 2a
    03 QDa 3a
    04 QEa 4a
    05 QFa 5a
    06 QGa 6a
    07 QHa 7a
    08 QAb 15b
    09 QBb 1b
    10 QCb 2b
    etc....... to
    15 QHb 7b

    If my understanding is correct then QHb (7b) should be connected to RS of the LCD module (pin 4) instead of the "normal" (single '595, "three-wire") connection to QHa (7a).
    There would be other changes necessary but I am not fully able to implement them as I have limited experience/knowledge.
    Can you help?

    (Where is Stephen Hobley? He wrote the "3-wire" story but didn't expand on using cascade.....)



    •   Alt25th September 2016, 08:35

      advertising

        
       

  11. #11
    Full Member level 1
    Points: 609, Level: 5

    Join Date
    Apr 2016
    Posts
    115
    Helped
    0 / 0
    Points
    609
    Level
    5

    Re: [moved] Arduino / LCD / '595 cascade

    1. Use other chip, like 16 bit I2C port-expander mcp23017 / mcp23017sp
    2. Did you look at:
    https://www.arduino.cc/en/Reference/ShiftOut
    http://lucidtronix.com/tutorials/40

    "Arduino Code for Two Daisy Chained 74HC595 Shift Registers"
    Once you've got your shift registers daisy chained together writing out to the chain is super easy. All you have to do is call the shiftOut function once for every shift register you have connected. So in this code, which drives two 7 Segment LED displays, we have these two lines inside the nested for loops:
    Code:
          shiftOut(dataPin, clockPin, MSBFIRST, dec_digits[onesColumn]);
          shiftOut(dataPin, clockPin, MSBFIRST, dec_digits[tensColumn]);
    This outputs the numbers 00-99 on the shift registers. Not that the first call to shift out sends its byte to the shift register at the far end of the chain (i.e. the register that is furthest from the Arduino.

    Code:
    /* LucidTronix
     * Daisy Chained Shift Registers
     * 74HC595 connected to 7-Segment LED display
     * Tutorial at:
     * http://www.lucidtronix.com/tutorials/40
     * April 2013
     */
    
    int dataPin = 2;
    int latchPin = 3;
    int clockPin = 4;
    
    byte dec_digits[] = {0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010010,0b10000011,0b11111000,0b10000000,0b10011000 };
    
    void setup() {
      //set pins to output so you can control the shift register
      pinMode(latchPin, OUTPUT);
      pinMode(clockPin, OUTPUT);
      pinMode(dataPin, OUTPUT);
    }
    
    void loop() {
      for (int tensColumn = 0; tensColumn < 10; tensColumn++) {
        for (int onesColumn = 0; onesColumn < 10; onesColumn++) {
          // take the latchPin low so 
          // the LEDs don't change while you're sending in bits:
          digitalWrite(latchPin, LOW);
          // shift out the bits:
          shiftOut(dataPin, clockPin, MSBFIRST, dec_digits[onesColumn]);
          shiftOut(dataPin, clockPin, MSBFIRST, dec_digits[tensColumn]); 
          //take the latch pin high so the LEDs will light up:
          digitalWrite(latchPin, HIGH);
          // pause before next value:
          delay(300);
        }
      }
    }



  12. #12
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    Responding to Klaus .....

    Quote Originally Posted by KlausST View Post
    Hi,

    I hope I understand right:
    * two 595 connected in series:
    * MOSI --> 595A_SER (LCD)
    * 595A_QH--> 595B_SER
    * (optionlal: 595B_QH--> MISO)
    * all other control lines in parallel to both 595

    Software:
    * activate chipselect
    * write 8 bits for 595B
    * write 8 bits for 595A
    * deactivete chipselect

    Klaus
    Yes, Klaus, I think you have understood what I mean perfectly.
    Now the trick is to implement it, possibly without disturbing the Liquidcrystal595.h library but otherwise creating a new library to suit the needs.
    So many thanks for your understanding and help so far. Good wishes.

    - - - Updated - - -



  13. #13
    Advanced Member level 3
    Points: 4,477, Level: 15

    Join Date
    Jun 2016
    Posts
    948
    Helped
    106 / 106
    Points
    4,477
    Level
    15

    Re: [moved] Arduino / LCD / '595 cascade

    I have only used Arduino a little. I can help you with your code but I will use mikroC PRO AVR Compiler for the C Code. I have made LCD_595 Library for my Compiler. If you are interested then I can help you. I am not interested in editing the Arduino_595 Library.



  14. #14
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    Quote Originally Posted by KlausST View Post
    Hi,

    I hope I understand right:
    * two 595 connected in series:
    * MOSI --> 595A_SER (LCD)
    * 595A_QH--> 595B_SER
    * (optionlal: 595B_QH--> MISO)
    * all other control lines in parallel to both 595

    Software:
    * activate chipselect
    * write 8 bits for 595B
    * write 8 bits for 595A
    * deactivete chipselect

    Klaus
    Yes, Klaus, you have it right.
    I came across this diagram ...

    lcd595ex.png

    ... from this site.

    It looks about right and uses a library called "libraries1". Pretty detailed but incomplete.
    How this must tie in with Liquidcrystal595.h beats me.

    Any ideas on how to move forward with this?



  15. #15
    Super Moderator
    Points: 40,308, Level: 49
    Awards:
    Most Frequent Poster

    Join Date
    Apr 2014
    Posts
    8,240
    Helped
    1991 / 1991
    Points
    40,308
    Level
    49

    Re: [moved] Arduino / LCD / '595 cascade

    Hi,

    maybe you can look into the library.

    The 595 acces is just simple SPI access.
    If you can modify this acces to transmit 16 bit ...

    But
    Writing the SPI access on your own isnt difficult, too.
    I assume there are raw SPI libraries.

    Klaus



  16. #16
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    Quote Originally Posted by KlausST View Post
    Hi,

    maybe you can look into the library.

    The 595 acces is just simple SPI access.
    If you can modify this acces to transmit 16 bit ...

    But
    Writing the SPI access on your own isnt difficult, too.
    I assume there are raw SPI libraries.

    Klaus
    I have been looking at SPI but it's a whole new battlefield and not exactly "...on your own isn't difficult..." !
    Will continue learning but can you help finding an answer in the mean time?



  17. #17
    Super Moderator
    Points: 40,308, Level: 49
    Awards:
    Most Frequent Poster

    Join Date
    Apr 2014
    Posts
    8,240
    Helped
    1991 / 1991
    Points
    40,308
    Level
    49

    Re: [moved] Arduino / LCD / '595 cascade

    Hi,

    I cant help you with code.
    Im more in hardware. I can read code, but dont write code anymore.

    ****
    There will be others to help you with code or libraries.

    You can also goto ATMEL site and look for SPI code.
    Look at AVR151.
    or google: "avr spi site:www.atmel.com" => https://www.google.de/search?q=avr+s...O8-ugAaG5I6ABA

    Klaus



  18. #18
    Junior Member level 2
    Points: 548, Level: 4

    Join Date
    Aug 2014
    Posts
    21
    Helped
    0 / 0
    Points
    548
    Level
    4

    Re: [moved] Arduino / LCD / '595 cascade

    Quote Originally Posted by KlausST View Post
    Hi,
    I cant help you with code.
    Im more in hardware. I can read code, but dont write code anymore.
    There will be others to help you with code or libraries.

    Klaus
    Understood, with thanks.

    It still remains to be a problem which should have a simple solution.
    I have now tried 4 forums (specialising in Arduino / LCD / '595) but still don't have answers that work.
    (So many entries with "cascade" & "daisy chain" but all about Knight Riders and LEDs-in-pattern but none with effective answers about simple control of the "extra" outputs 'beyond' the LCD.)

    Does anyone have an idea where I should look for a solution?
    Another forum, perhaps?



    •   Alt6th October 2016, 16:52

      advertising

        
       

  19. #19
    Super Moderator
    Points: 40,308, Level: 49
    Awards:
    Most Frequent Poster

    Join Date
    Apr 2014
    Posts
    8,240
    Helped
    1991 / 1991
    Points
    40,308
    Level
    49

    Re: [moved] Arduino / LCD / '595 cascade

    Hi,

    Did you try the solution of post#6?
    It really is very simple raw SPI communication.

    Klaus



  20. #20
    Advanced Member level 1
    Points: 5,282, Level: 17

    Join Date
    Jul 2004
    Location
    Hungary
    Posts
    462
    Helped
    186 / 186
    Points
    5,282
    Level
    17

    Re: [moved] Arduino / LCD / '595 cascade

    Hi Adri67;
    If you are using two or more ('cascaded') 595's, the main problem will be the proper handling of the LCD E pin.
    So ... my advice:
    Use a separated line fo the E pin, and tied 595 clock pins. The 3 control lines also:
    - first 595 data in
    - all 595 SH_CP - ST_CP (tied clock pins)
    - a separated LCD E
    like this:
    http://www.electronics-lab.com/proje...hift-register/
    True, the given link uses a PIC but you can transform it easily.
    Using this method you cannot using the 'original' Arduino LCD libraries, but you can (I hope) easily expand the circuit.



+ Post New Thread
Please login
Page 1 of 2 1 2 LastLast
--[[ ]]--