Driving a 2x16 LCD with only One Pin and 74HC595


Closed Thread
Results 1 to 21 of 21
  1. #1
    Join Date
    Jan 2014
    Posts
    10

    Default Driving a 2x16 LCD with only One Pin and 74HC595

    Hello,

    with the idea from this WebSide http://www.romanblack.com/shift1.htm, using the Darrel Taylor LCD_AnyPin.pbp + HighJack as a template and the willing to drive the LCD with only one Pin and to use the LCDOUT Command with all features, i wrote a routine for the 74HC595 controlling.

    Name:  1_Wire_74HC595.jpg
Views: 5897
Size:  222.9 KB

    and here is the Code:


    Code:
    @ DEVICE pic16F628A, intOSC_osc_noclkout, WDT_OFF, PWRT_OFF, BOD_OFF, MCLR_OFF
    
    define osc 8 
    
    INTCON  = 0
    PortA   = 0
    PortB   = 0
    TRISA   = 0                         ' CATODES TO PORTA
    TRISB   = 0                         ' ANODES  TO PORTB
    CMCON   = 7
      
    Serial_Pin var PortA.3
    
    B0 var byte
    B1 VAR Byte
    B2 VAR Byte
    B3 VAR Byte
    B4 var Byte
    B5 VAR Byte
    B6 VAR Byte
    B7 VAR Byte
    
    B0 = 0
    B1 = 255
                          
    
    ;----[ Change these to match your LCD ]--------------------------------------- 
    INCLUDE "One_Wire_74HC595.pbp" ; *** Include MUST be AFTER LCD Pin assignments * 
    
    ;----[ Your Main program starts here ]---------------------------------------- 
    LCDOUT $FE, 1
    LCDOUT $FE, 1, IHex 255
    Pause 2000
    Start:
    Repeat
    B0 = B0 + 1
    B1 = B1 - 1
    B2 = B0 DIG 2
    B3 = B0 DIG 1
    B4 = B0 Dig 0
    B5 = B1 DIG 2
    B6 = B1 DIG 1
    B7 = B1 Dig 0
    LCDOUT $FE,$80,"Counter = ",#B2,#B3,#B4  
    LCDOUT $FE,$C0,"Counter = ",#B5,#B6,#B7
    Pause 1000 
    Until B0 > 254 OR B1 < 1
    SWAP B0, B1
    goto Start
    END

    Code:
    A  var byte
    B  var byte
    C  var byte
    D  var bit
    E  VAR byte
    
    
    INCLUDE "VirtualPort.bas"
    
    LCD_DATAUS    CON 2000
    LCD_COMMANDUS CON 50
    'PAUSE 100 : LCDOUT $FE,1 : PAUSE 100   ; Initialize LCD
    
    Goto Over_One_Wire_74HC595
    
    ;===============( DO NOT Change anything below this line )====================
    
    ASM ; Make sure HighJack has been installed in PBP's .LIB file
        ifndef LCDOUT_HIGHJACKED 
            error "HighJacked-LCDOUT Not found in PBPPIC??.LIB"
        endif
    ENDASM
    DEFINE  HJ_LCDOUT  _LCDsend    ; Redirect PBP's LCDOUT to LCDsend: Subroutine
    
    ;----[Send a byte to the Virtual LCD PORT]------------(DO NOT Change)---------
    TempChar        var  byte
    Char            VAR  Byte
    LCD_Initialized VAR  FLAGS.1
    RSS             VAR  FLAGS.0                ; LCD RS State
    
    ;----[ This routine is called once for every character sent by LCDOUT ]-------
    LCDsend:
          @  MOVE?AB  _TempChar                 ; Get char sent by LCDOUT, in WREG
          if !LCD_Initialized then LCD_Init     ; Make sure LCD was Initialized 
      LCDAfterInit:
          if TempChar = $FE then RSS=0 : goto LCDsendDone ; next char is Command 
          Char = TempChar
      LCDsendCOM:
          Gosub Toggle_Nibble
          IF RSS = 0 then                       ; Is a Command
              IF Char = 1 then CommandDelay     ; Long delay for Clear Screen
              IF Char = 2 then CommandDelay     ; Long delay for Home
              @  DelayUS   _LCD_DATAUS          ; Short delay for everything else
              goto DelayDone
          else                        
              @  DelayUS   _LCD_DATAUS          ; Short delay for Data
              goto DelayDone
          endif
      CommandDelay:
          @  DelayUS   _LCD_COMMANDUS
      DelayDone:
        if LCD_Initialized then RSS = 1       ; Set RS to Data next time
      LCDsendDone:
    return
    
    ;----[Initialize the LCD]-------------------(DO NOT Change)-------------------
    LCD_Init:
        A = 2
        Char = $33 : gosub  LCDsendCOM : @ DelayUS 5000
                         gosub  LCDsendCOM : @  DelayUS 100
                         gosub  LCDsendCOM : @  DelayUS 100                 
        Char = $22 : gosub  LCDsendCOM   ; Start 4-bit mode
        A = 5
        Char = $28 : gosub  LCDsendCOM  ; Function Set, 4-bit, 2-line, 5x7
        Char = $0C : gosub  LCDsendCOM  ; Display ON
        
        Char = $06 : gosub  LCDsendCOM  ; Entry Mode
        LCD_Initialized = 1             ; LCD has been Initialized
    goto LCDAfterInit
    
    Toggle_Nibble:
    For C = 0 to A
    SELECT CASE c
     CASE 0
        B = Char & %11110000   ' Upper 4 Bits 
        If RSS = 1 Then
           B = B | %00000100    ' Set RS Bit 
        Endif       
     CASE 1, 4
        B = B | %00001000       ' Set Enable Bit 
     CASE 2, 5 
        B = B ^ %00001000       ' Enable Toggel
     Case 3     
        B = Char * 16               ' Lower 4 Bits Shift           
        If RSS = 1 Then
           B = B | %00000100    ' Set RS Bit
        Endif            
    END SELECT
    '******************************Shift_74HC595***********************************
    E = 7
    Repeat
    D = B >> E
    E = E - 1
    SELECT CASE D
    CASE 1 
     Serial_Pin = 0
     @ nop             ' min 1 µs for 1 
     Serial_Pin = 1       
     Pauseus 15        ' min 15 µs 
    Case 0
     Serial_Pin = 0
     Pauseus 15        ' min 15 µs for 0 
     Serial_Pin = 1       
     Pauseus 30        ' min 30 µs danach
    END SELECT    
    Until E = 0
    
    'Latch
    Serial_Pin = 0
    Pauseus 200        ' min 200 µs for Latch
    Serial_Pin = 1        
    Pauseus 300        ' min 300 µs 
    Next
    Return 
    
    Over_One_Wire_74HC595:

    As long as Strings will be send, all runs pretty good
    Example:
    LCDOUT $FE, 1, "Hello"

    But I can do what I want, everytime I want to use the HEX, BIN, DEC, REP or STR commands i get Errors in displaying the correct Data.

    Example:
    LCDOUT, $FE, 1 IHex 255

    I get F0 as answer and not $FF
    Without I the answer is $220

    What I also found out is, when I wrote a simple loop that show me the Hex Characters from 1 to 20....
    Till 16 all is Displayed correct. After 16 till 20, 10 is displaying.


    I hope somebody can help me.

    Thanks

    P.S. Sorry for my Bad English
    Last edited by struppi81; - 25th January 2014 at 14:35.

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Change all of your PAUSEUS's to @ DelayUS xxx

    PAUSEUS will change PBP's system variables that are already in use creating ASCII characters from a value using DEC, BIN, HEX etc.
    @ DelayUS does not use the system vars.
    DT

  3. #3
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Hi Darrel,

    First, Thanks for your Help.

    I replace all, but the situation is the same.

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Ok, you also have a multiplication in your code, which has the same problem of using System variables.

    Change it to this ...
    Code:
    ;    B = Char * 16               ' Lower 4 Bits Shift
        B = Char << 1
        B = B << 1
        B = B << 1
        B = B << 1
    Added:

    Name:  1-wire_LCD.jpg
Views: 3784
Size:  64.7 KB

    The 16F628A only has a 4Mhz internal oscillator, yours was running at 8Mhz, and your circuit wouldn't work at 4Mhz.
    I had to increase the capacitors to 4.7nF

    Code:
    @ DEVICE pic16F628A, intOSC_osc_noclkout, WDT_OFF, PWRT_OFF, BOD_OFF, MCLR_OFF
    DEFINE OSC 4
    
    Serial_Pin var PortA.3
    
    B0 var byte
    B1 VAR Byte
    
    OUTPUT Serial_Pin
    CMCON = 7
    B0 = 0
    B1 = 255
                          
    INCLUDE "One_Wire_74HC595.pbp" ; *** Include MUST be AFTER LCD Pin assignments * 
    
    ;----[ Your Main program starts here ]---------------------------------------- 
    LCDOUT $FE, 1
    LCDOUT $FE, 1, IHex 255
    Pause 2000
    
    Main:
        LCDOUT $FE,$80,"B0 = ",DEC B0,"    "  
        LCDOUT $FE,$C0,"B1 = ",DEC B1,"    "
        B0 = B0 + 1
        B1 = B1 - 1
        PAUSE 1000
    GOTO Main
    Last edited by Darrel Taylor; - 25th January 2014 at 19:52.
    DT

  5. #5
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Awesome, Darrel

    Yes, that's it!!

    Can I also write:

    B = Char
    B = B << 4

    I tested it once more with the Pauseus...it also runs.
    Would you still recommend to use the DelayUS Command in whole code?

    Thanks in advance!
    Last edited by struppi81; - 25th January 2014 at 21:02.

  6. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Most definitely, you must not use PAUSEUS.

    And no, you cant use B = B << 4
    The CPU can only shift one bit at a time. So it requires a loop and a variable to count the number of shifts.
    That uses a SYSTEM variable.

    And there are two more issues that cause instability.

    1) The reason I had to change the capacitors is the @ NOP which changes timing with different oscillator frequencies.
    It should be replaced with ...
    Code:
    @ DelayUS 1
    And the capacitors should be left at 4.7nF
    That way it will work with all PBP OSC frequencies.
    .
    2) And this statement also affects System variables, for the same reason as B =B << 4 ...
    Code:
    D = B >> E
    It could be replaced with ...
    Code:
    F  var byte
    G  var byte
    
    ;D = B >> E
    F = E
    G = B
    ShiftLoop
        G = G >> 1
        F = F - 1
    IF F != 0 THEN ShiftLoop
    D = G.0
    Although I have a feeling it can be reduced somehow.
    .
    I think that should give a stable include file.
    At least it works well here.

    But I'll add that you are using common variable names in the include like ...A, B, C etc.
    That means that when someone uses your include, they cannot use those variable names.
    It's better to make unique variable names that are unlikely to be used by the person using your code.
    Descriptive names are the best. Try to use a name that describes what the variable is used for.
    DT

  7. #7
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Ok, with the variable name you are right!

    About Point 2:

    Could be this a better Solution:

    Code:
    '******************************Shift_74HC595***********************************
    F = B
    E = 7
    Repeat
    ;D = B >> E
    ASM
      rlf _F, F
      BTFSS STATUS, C  
      BCF _D                 
      BTFSC STATUS, C  
      BSF _D    
    ENDASM
    E = E - 1
    SELECT CASE D
    CASE 1 
     Serial_Pin = 0
     @  DelayUS 1         ' min 1 µs for 1
     Serial_Pin = 1
     @  DelayUS 15        ' min 15 µs 
    Case 0
     Serial_Pin = 0
     @  DelayUS 15        ' min 15 µs for 0 
     Serial_Pin = 1
     @  DelayUS 30        ' min 30 µs 
    END SELECT    
    Until E = 0
    
    'Latch
    Serial_Pin = 0
     @  DelayUS 200        ' min 200 µs for Latch 
    Serial_Pin = 1 
     @  DelayUS 300        ' min 300 µs 
    Next
    Return
    Thanks in advance!
    Last edited by struppi81; - 26th January 2014 at 00:48.

  8. #8
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Here I'm again.

    Again to my last post:
    I think over it again and C Flag is also an System Variable.
    Also too unsuitable.

    What have I done:

    I rewrite the code once again.
    I change the Variable Name's an insert your code from Statement 2.
    Could it be, that there is an small mistake.
    Code:
    F  var byte
    G  var byte
    
    ;D = B >> E
    F = E
    G = B
    ShiftLoop
       ;G = G >> 1
        G = G << 1
        F = F - 1
    IF F != 0 THEN ShiftLoop
    ;D = G.0
    D = G.7
    Once Again here is the code

    Code:
    Char_Temp             var byte
    ShiftOut_Steps        var byte
    Count_ShiftOut_Steps  var byte
    ShiftLoop_Steps       Var byte
    Bit_Shift             Var byte
    Readout_Bit           var bit
    
    INCLUDE "VirtualPort.bas"
    
    LCD_DATAUS    CON 2000
    LCD_COMMANDUS CON 50
    
    Goto Over_One_Wire_74HC595
    
    ;===============( DO NOT Change anything below this line )====================
    
    ASM ; Make sure HighJack has been installed in PBP's .LIB file
        ifndef LCDOUT_HIGHJACKED 
            error "HighJacked-LCDOUT Not found in PBPPIC??.LIB"
        endif
    ENDASM
    DEFINE  HJ_LCDOUT  _LCDsend    ; Redirect PBP's LCDOUT to LCDsend: Subroutine
    
    ;----[Send a byte to the Virtual LCD PORT]------------(DO NOT Change)---------
    TempChar        var  byte
    Char            VAR  Byte
    LCD_Initialized VAR  FLAGS.1
    RSS             VAR  FLAGS.0                ; LCD RS State
    
    ;----[ This routine is called once for every character sent by LCDOUT ]-------
    LCDsend:
          @  MOVE?AB  _TempChar                 ; Get char sent by LCDOUT, in WREG
          if !LCD_Initialized then LCD_Init     ; Make sure LCD was Initialized 
      LCDAfterInit:
          if TempChar = $FE then RSS=0 : goto LCDsendDone ; next char is Command 
          Char = TempChar
      LCDsendCOM:  
          Goto ShiftLoop_Char
      After_ShiftLoop_Char:
          IF RSS = 0 then                       ; Is a Command
              IF Char = 1 then CommandDelay     ; Long delay for Clear Screen
              IF Char = 2 then CommandDelay     ; Long delay for Home
              @  DelayUS   _LCD_DATAUS          ; Short delay for everything else
              goto DelayDone
          else                        
              @  DelayUS   _LCD_DATAUS          ; Short delay for Data
              goto DelayDone
          endif
      CommandDelay:
          @  DelayUS   _LCD_COMMANDUS
      DelayDone:
        if LCD_Initialized then RSS = 1       ; Set RS to Data next time
      LCDsendDone:
    return
    
    ;----[Initialize the LCD]-------------------(DO NOT Change)-------------------
    LCD_Init:
        ShiftOut_Steps = 2
        Char = $33 : gosub  LCDsendCOM : @  DelayUS 5000
                     gosub  LCDsendCOM : @  DelayUS 100
                     gosub  LCDsendCOM : @  DelayUS 100                 
        Char = $22 : gosub  LCDsendCOM   ; Start 4-bit mode
        
        ShiftOut_Steps = 5
        Char = $28 : gosub  LCDsendCOM   ; Function Set, 4-bit, 2-line, 5x7
        Char = $0C : gosub  LCDsendCOM   ; Display ON
        
        Char = $06 : gosub  LCDsendCOM   ; Entry Mode
        LCD_Initialized = 1              ; LCD has been Initialized
    goto LCDAfterInit
    
    ;----[Send it to 74HC595]-------------------(DO NOT Change)-------------------
    
    ShiftLoop_Char:
    For Count_ShiftOut_Steps = 0 to ShiftOut_Steps           ' For To Loop
    SELECT CASE Count_ShiftOut_Steps
     CASE 0
        Char_Temp = Char & %11110000                         ; Isolate Upper 4 Bits 
        If RSS = 1 Then : Char_Temp = Char_Temp | %00000100  ; Set RS Bit          
     CASE 1, 4
        Char_Temp = Char_Temp | %00001000                    ; Set Enable Bit 
     CASE 2, 5 
        Char_Temp = Char_Temp ^ %00001000                    ; Toggel Enable 
     Case 3     
        Char_Temp = Char << 1                                ; Shift Up Lower 4 Bits  
        Char_Temp = Char_Temp << 1
        Char_Temp = Char_Temp << 1
        Char_Temp = Char_Temp << 1 
        If RSS = 1 Then : Char_Temp = Char_Temp | %00000100  ; Set RS Bit            
    END SELECT
    Bit_Shift = Char_Temp
    
    ;----[Shift_Routine_74HC595 ]---------------(DO NOT Change)-------------------
    ShiftLoop_Steps = 7
    
    ShiftLoop: 
    
    Readout_Bit = Bit_Shift.7
    SELECT CASE Readout_Bit
    CASE 1 
      Serial_Pin = 0 : @  DelayUS 1         ; min 1 µs for 1
      Serial_Pin = 1 : @  DelayUS 15        ; min 15 µs 
    Case 0
      Serial_Pin = 0 : @  DelayUS 15        ; min 15 µs for 0
      Serial_Pin = 1 : @  DelayUS 30        ; min 30 µs 
    END SELECT
    
    Bit_Shift = Bit_Shift << 1
    ShiftLoop_Steps = ShiftLoop_Steps - 1
    IF ShiftLoop_Steps != 0 THEN : Goto ShiftLoop
    
    ;Latch
    Serial_Pin = 0 : @  DelayUS 200        ; min 200 µs for Latch 
    Serial_Pin = 1 : @  DelayUS 300        ; min 300 µs
    
    'Count_ShiftOut_Steps = Count_ShiftOut_Steps + 1                       ' for If Then Request
    'IF Count_ShiftOut_Steps != ShiftOut_Steps Then : goto ShiftLoop_Char  ' for If Then Request
    Next                                                                   ' For To Loop
    Goto After_ShiftLoop_Char
    
    Over_One_Wire_74HC595:
    I also wanted to replace the For To Loop with an normal If - Then request, because of the Usage of System Variables; or is there neither.
    It also works well but when I simulate it, it takes too much CPU Usage and Runs very slow.
    Using an Repeat Until Loop also.
    With an For To Loop the simulation is better.

    But which Loop is the best, when one think only about the Usage in an Microcontroller?
    What did you say. Is it OK or is there something which one can also improve.

    Thanks in advance!

  9. #9
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    STATUS,C is not a PBP system variable. You can use it.

    FOR loops, REPEAT/UNTIL, WHILE/WHEN, DO/LOOP all do not use the system vars (as long as the test condition is = or !=).
    They will use system vars if the test condition is <, <=, >, >= etc.

    Speed differences between any of the loop types will not be significant on a real chip.
    The major slow down with this interface is the timing required to activate inputs on the 595 using the capacitors.
    All those delays in the code make writing to the LCD very slow.
    DT

  10. #10
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Your include looks better with the new variable names.
    I ran it this morning, and it seems to be working.

    Have you looked at the signals going to the 595 on a scope?
    Scary stuff to be putting in a digital chip.

    Yellow is the serial data.
    Blue is after the 1.5K resistor.
    Magenta is after the 33K resistor.

    Name:  1-wire_LCD_Scope.jpg
Views: 2405
Size:  136.5 KB

    And you can see that it takes 910 uS per nibble (1.82 mS per byte).

    It would be interesting to see how it works on real hardware.
    DT

  11. #11
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Hello Darrel,

    yes your are right, very scary!

    And yes I use the scope, because of controlling the puls length (µs).


    What I have done again:

    I reduce the code a little bit and I change/simplified some parts.

    Code:
    I replace this:
    
    Char_Temp = Char << 1                                 ; Shift Up Lower 4 Bits  
    Char_Temp = Char_Temp << 1
    Char_Temp = Char_Temp << 1
    Char_Temp = Char_Temp << 1 
    
    with this:
    
    Char_Temp = Char & %00001111                     ; Shift Up Lower4 Bits
    @ swapf _Char_Temp ,F

    Also I reduce the Upper an Lower Nibbel Part from 6 to only 4 Steps.

    Code:
    SELECT CASE Count_ShiftOut_Steps
     CASE 0
        Char_Temp = Char & %11110000                         ; Isolate Upper 4 Bits 
        If RSS = 1 Then : Char_Temp = Char_Temp | %00000100  ; Set RS Bit          
     CASE 1, 3
        Char_Temp = Char_Temp | %00001000                    ; Set Enable Bit 
     Case 2
        Char_Temp = Char & %00001111                         ; Shift Up Lower4 Bits
        @ swapf _Char_Temp ,F
        If RSS = 1 Then : Char_Temp = Char_Temp | %00000100  ; Set RS Bit            
    END SELECT
    Because Toggle the Enable Bit again is not necessary.


    Further, I change (Post 6, Point 2...."Although I have a feeling it can be reduced somehow")

    Code:
    This:
    
    ;----[Shift_Routine_74HC595 ]---------------(DO NOT Change)-------------------
    ShiftLoop_Steps = 7
    
    ShiftLoop:
    Readout_Bit = Bit_Shift.7
    SELECT CASE Readout_Bit
    CASE 1 
      Serial_Pin = 0 : @  DelayUS 1          ; min 1 µs for 1
      Serial_Pin = 1 : @  DelayUS 15         ; min 15 µs 
    Case 0
      Serial_Pin = 0 : @  DelayUS 15         ; min 15 µs for 0
      Serial_Pin = 1 : @  DelayUS 30         ; min 30 µs 
    END SELECT
    
    Bit_Shift = Bit_Shift << 1
    ShiftLoop_Steps = ShiftLoop_Steps - 1
    IF ShiftLoop_Steps != 0 THEN : Goto ShiftLoop
    
    ;Latch
    Serial_Pin = 0 : @  DelayUS 200        ; min 200 µs for Latch 
    Serial_Pin = 1 : @  DelayUS 300        ; min 300 µs
    Next  
    
    To This:                                     
    
    ;----[Shift_Routine_74HC595 ]---------------(DO NOT Change)-------------------
    ShiftLoop: 
    For ShiftLoop_Steps = 0 to 6
     @ rlf _Bit_Shift, F                     ; Shift 1.Pos left
    If STATUS.0 = 1 Then                     ; Carry Flag
       Serial_Pin = 0 : @  DelayUS 1         ; min 1 µs for 1
       Serial_Pin = 1 : @  DelayUS 15        ; min 15 µs
    else
       Serial_Pin = 0 : @  DelayUS 15        ; min 15 µs for 0
       Serial_Pin = 1 : @  DelayUS 30        ; min 30 µs 
    endif
    next
    
    ;Latch
    Serial_Pin = 0 : @  DelayUS 200         ; min 200 µs for Latch 
    Serial_Pin = 1 : @  DelayUS 300         ; min 300 µs
    Next
    Up to now, the code runs very good. (I Think a little bit better then before.)
    But sometimes when I simulate it on the PC, after some time, the LCD shows only cryptic characters.
    Then I have to restart the simulation again an all works fine.

    What du you think, is there something one can improve?

    Thanks in advance!

  12. #12
    Join Date
    Dec 2010
    Posts
    409


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Note also there will be a wide variation of timings across components, a wide variation of chip sensitivity, and a sensitivity to clock speed, temperature, power supply voltage, data rates, etc. etc. This approach is "O.K." for a hobby project, but it would be a very bad idea to try to use it in a commercial project, especially anything that might see volume.

    Not to rain on your parade, but given you can get PIC devices with fewer pins and at lower cost than a 74HC595, you would be further ahead to create a dedicated display driver PIC that you can send data to by 1 pin serial. Fewer components too, and rock solid communications.

  13. #13
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Hello,

    Yesterday I tested it with an 12F675 at 4 Mhz intOSC and till now it runs stable and fast.
    When I less busy, I will test it out with other frequencies.

    But i have yet again an comprehension question to this code:

    Code:
    LCDsend:
          @  MOVE?AB  _TempChar                 ; Get char sent by LCDOUT, in WREG
          if !LCD_Initialized then LCD_Init     ; Make sure LCD was Initialized 
      LCDAfterInit:
          if TempChar = $FE then RSS=0 : goto LCDsendDone   goto DONE ; next char is Command 
          Char = TempChar
      LCDsendCOM:  
          Goto ShiftLoop_Char
      After_ShiftLoop_Char:
          IF RSS = 0 then                       ; Is a Command
              IF Char = 1 then CommandDelay     ; Long delay for Clear Screen
              IF Char = 2 then CommandDelay     ; Long delay for Home
              @  DelayUS   _LCD_DATAUS          ; Short delay for everything else
              goto DelayDone
          else                        
              @  DelayUS   _LCD_DATAUS          ; Short delay for Data
              goto DelayDone
          endif
      CommandDelay:
          @  DelayUS   _LCD_COMMANDUS
      DelayDone:
        if LCD_Initialized then RSS = 1       ; Set RS to Data next time
      LCDsendDone:
      bsf     STATUS, C       ; Set no timeout for Serout2mod  
    return
    When i compare these steps with them in pbppic14.lib, than i note that in the upper code some parts (Red marked) not exist, like in the library code.

    @ Darrel:
    Are these Commands not necessary or why didn't you include them?


    Further I would shrink this code to this:

    Code:
    LCDsend:
          @  MOVE?AB  _TempChar                 ; Get char sent by LCDOUT, in WREG
          if !LCD_Initialized then LCD_Init     ; Make sure LCD was Initialized 
      LCDAfterInit:
          if TempChar = $FE then RSS=0 : goto LCDsendDone ; next char is Command 
          Char = TempChar
      LCDsendCOM:  
          Goto ShiftLoop_Char
      After_ShiftLoop_Char:     
        if LCD_Initialized then RSS = 1       ; Set RS to Data next time
      LCDsendDone: 
    return
    Because of the fact, that the shifting time of 1 byte needs about 2 - 4ms, it is not nessesary to include extra Delays for Data or Commands.

    Can I do it in this way?



    Thanks in advance!

  14. #14
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    If you use GOTO DONE, it limits the use of your include to 14-bit devices.
    In the 18F library, it's called DUNN.

    There's no need to use DONE, since the FSR hasn't been changed, and RETURN resets the BANK to 0 anyhow.

    The bsf STATUS, C is only required if the end user is using the SEROUT2 command with a Flow Control Pin.
    My observations have concluded that nobody uses that function. Or if they understand how to use Flow Control, they probably aren't using LCD_AnyPin.

    However, to cover ALL the bases ... you are correct! bsf STATUS, C should be there. But it needs an @ sign.

    As for removing the delays ... I don't think that's a good idea.
    The measurement I took previously was 1.8 mS per byte.
    Most good LCD's take 1.6 mS for a Clear Screen, so it would be fine (with a good LCD).
    But there are LCD's that take longer, 2.4 mS is not uncommon.

    You could remove the LCD_DATAUS part since it will always be under 1.8 mS.

    But I think the ability to add delays for LCD_COMMANDUS should remain in the program.
    You can easily set LCD_COMMANDUS to 0 in the main program for normal displays.
    For slower LCD's, just set it to the difference of say 2.4 mS - 1.8 ms = 0.6 mS or 600 uS.
    DT

  15. #15
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Smile Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Thanks Darrel,

    now I'm wiser, again thanks.

    With the delays......

    To shift out one byte (Data or Command) after LCDInit it needs 4 Steps.
    One Step require a time nearly 910µs - 1ms.
    That makes nearly 4ms. => No extra Delay necessary. Right?

    The First 4 commands in the LCD_Init part needs only 2 Steps, because only the 4 upper bits shifted out.
    There, I'm agree with you that the delay should be longer.

    Could I place them here: ?

    Code:
    LCD_Init:
        ShiftOut_Steps = 1
        Char = $33 : gosub  LCDsendCOM : @  DelayUS 5000
                     gosub  LCDsendCOM : @  DelayUS 600
                     gosub  LCDsendCOM : @  DelayUS 600                
        Char = $22 : gosub  LCDsendCOM : @  DelayUS 600  ; Start 4-bit mode
        .........
        .........
        .........

    Further I tested again with other frequencies.
    I use 8 Mhz and a 20 Mhz quarz.
    Also there are, no problems. It runs stable.

    What I find out is that it is absolute necessary, to add an capacitor between +V and GND of the 74HC595.
    I use an 100nF.
    Otherwise you get sometimes error in displaying the right things.

    The capacitor for the Latch Pulse, I would change back to 2.2nF. And the capacitor for the 1 or 0 Pulse should be left at 4.7nF.

    Here are some picture make with my mini DSO.

    Clock Pulse
    Name:  Clock.jpg
Views: 2332
Size:  54.7 KB

    Pulse 1 or 0 with 2.2nF
    Name:  1_0 2.2nF.jpg
Views: 2310
Size:  57.6 KB Name:  1_0 2.2 nF.jpg
Views: 2264
Size:  55.7 KB

    Pulse 1 or 0 with 4.7nF
    Name:  1_0 4.7nF.jpg
Views: 2280
Size:  57.3 KB Name:  1_0 4.7nF_2.jpg
Views: 2337
Size:  55.6 KB

    Latch 2.2nF & Latch 4.7nF
    Name:  Latch 2.2nF.jpg
Views: 2301
Size:  57.3 KB Name:  Latch 4.7nF.jpg
Views: 2335
Size:  56.4 KB

  16. #16
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Quote Originally Posted by struppi81 View Post
    To shift out one byte (Data or Command) after LCDInit it needs 4 Steps.
    One Step require a time nearly 910µs - 1ms.
    That makes nearly 4ms. => No extra Delay necessary. Right?
    No, each byte whether it's a command or data requires two nibbles at 910 uS or 1.82 mS total.

    You need the delays!

    And I would leave the initialization timing the same.
    It only happens once per power-on, so you're not saving any time during normal operations.
    DT

  17. #17
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Now im confused

    LCD_Init _Only the First 4 Commands (2 Steps):


    Step1: shiftout 1 byte.
    Enable_High + Data high nibble + Latch => nearly 910µs (Delay at the next Command)

    Step2: shiftout 1 byte
    Enable_Low + Data high nibble + Latch => nearly 910µs (Delay at the next Command till Latch)

    => 1,8 µs => extra delay necessary.

    Next Command....

    The 3 others Commands 4 Steps ; (see after LCD Init)


    After LCD Init (4 Steps): (Commands without RS)

    Step1: shiftout 1 byte.
    RS + Enable_High + Data high nibble + Latch => nearly 910µs (Delay at the next Command or Data)

    Step2: shiftout 1 byte
    RS + Enable_Low + Data high nibble + Latch => nearly 910µs (Delay at the next Command or Data)

    Step3: shiftout 1 byte
    RS + Enable_High + Data low nibble + Latch => nearly 910µs (Delay at the next Command or Data)

    Step4: shiftout 1 byte
    RS + Enable_Low + Data low nibble + Latch => nearly 910µs (Delay at the next Command or Data till Latch)

    => 3,6µs

    Next Command or Data....


  18. #18
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Or I'm confused, not sure.
    I see how it takes 4 "steps" just to toggle the E line.

    But, the LCD will not accept any data or commands while it is busy.
    Even though it takes 4 steps ... you are clocking in the first nibble after the first 2 steps 1.82 mS.

    The HD44780 datasheet timing diagrams show that the first nibble can't be clocked in until after the last command is complete (not busy).
    There is no text that confirms it, but that's what the timing diagrams show.
    DT

  19. #19
    Join Date
    Jan 2014
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    OK,

    now I post my Final, good working code.

    I implement the ability to add delays for LCD_COMMANDUS in the main programm and the part, if somebody want to use SEROUT2 with a Flow Control Pin. (I don't have test it yet)

    With my LCD's, I could set the LCD_COMMANDUS Value to 0.

    It would be very interesting if somebody could test it out with an slower LCD and post which value he have to set or general experiences.

    A big thanks to Darrel Taylor.

    Zip File implements:
    One_Wire_74HC595_Main.pbp
    One_Wire_74HC595.bas
    VirtualPort.bas
    Attached Files Attached Files
    Last edited by struppi81; - 12th February 2014 at 11:51.

  20. #20
    Join Date
    Jan 2014
    Posts
    2


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Hello,
    I desperately looking for a simple code
    use an LCD via a 74HC595 or 3 wire.
    why is it so difficult to make a code with
    LCDOUT the order?
    mimie64

  21. #21
    Join Date
    Apr 2015
    Posts
    3


    Did you find this post helpful? Yes | No

    Default Re: Driving a 2x16 LCD with only One Pin and 74HC595

    Hello.

    In the simulation proteus, sometimes appear strange characters, is this normal?

Similar Threads

  1. 2x16 LCD Graphics :)
    By Art in forum General
    Replies: 51
    Last Post: - 13th June 2015, 11:02
  2. Need advice with LCD 2x16
    By fratello in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 26th April 2011, 06:58
  3. LCD via 74HC595
    By helloo in forum General
    Replies: 7
    Last Post: - 31st October 2010, 20:49
  4. 2x16 lcd problem
    By k3v1nP in forum mel PIC BASIC
    Replies: 11
    Last Post: - 30th October 2008, 04:46
  5. small 2X16 LCD
    By Ron Marcus in forum Off Topic
    Replies: 2
    Last Post: - 26th October 2007, 20:37

Members who have read this thread : 2

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts