News:

Let's find out together what makes a PIC Tick!

Main Menu

LED indicator for 74HC595

Started by tolyan249, Aug 21, 2026, 03:14 AM

Previous topic - Next topic

tolyan249

There's this LED indicator based on the 74HC595 — has anyone worked with them?
I just don't know how to work with them.
I have a PIC16F628; they say you can use it via SPI.
Maybe someone has some experience with it?
Thank you.

ken_k

The chips are 8 bit serial input shift registers.The data sheet explains how they work.
My guess is you will clock in a bit for each 7 segments and then enable the output.
I did something similar years ago and it worked very well.

ken_k

Here is a link to the PCB.

https://aqtronic.com/product/static-drive-3-bit-7-segment-led-display-module-with-74hc595/

The link below shows how the displays may be connected to the IC. Although written for Arduino the description may help you.

https://wiki.geeetech.com/index.php/Arduino_7_segment_LED_timer_with_74HC595_module

A friend of mine made a very long PCB with a lot of 7 segment displays on it (side by side) with a 74HC595 for each display. If a certain number of 7 seg displays were required the PCB could be broken off at the required spot.
 
These displays don't strobe so they look good when taking a video of them.

I guess you will have to write your own code.
I once drive 45 relays using this method using similar IC's. I simply bit bashed three pins to the relay PCB.
 


Frizie

Very easy to use with Positron's SHOUT instruction ;D
Ohm sweet Ohm | www.picbasic.nl

tolyan249

Thank you all for your help; I'll try to write a program for it.

Pepe

#5
demo proteus

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 16F628A

Config FOSC_HS, WDTE_OFF, PWRTE_OFF, MCLRE_OFF, BOREN_ON, LVP_OFF, CPD_OFF, CP_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------


Declare Xtal = 16
Declare Optimiser_Level = 3
Declare Reminders Off
Declare Watchdog = Off
Declare Create_Coff On
'-----------------------------------------
' Pines
'-----------------------------------------
Symbol DATA_PIN  = PORTB.3
Symbol CLOCK_PIN = PORTB.4
Symbol LATCH_PIN = PORTB.5

'-----------------------------------------
' Variables
'-----------------------------------------
Dim Numero As Word
Dim Centenas As Byte
Dim Decenas As Byte
Dim Unidades As Byte

Dim SegDisp[10] As Byte

'-----------------------------------------
' Tabla de segmentos
'-----------------------------------------
SegDisp[0] = 3
SegDisp[1] = 159
SegDisp[2] = 37
SegDisp[3] = 13
SegDisp[4] = 153
SegDisp[5] = 73
SegDisp[6] = 65
SegDisp[7] = 27
SegDisp[8] = 1
SegDisp[9] = 9

'-----------------------------------------
' Configuración
'-----------------------------------------
TRISB = %00000000
Clear PORTB

'-----------------------------------------
' Programa
'-----------------------------------------
Do

    For Numero = 0 To 999

        Centenas = Dig Numero,2
        Decenas = Dig Numero,1
        Unidades = Dig Numero,0

        LATCH_PIN = 0

        SHOut  DATA_PIN, CLOCK_PIN,0,[ SegDisp[Unidades] ]
        SHOut  DATA_PIN, CLOCK_PIN,0,[ SegDisp[Decenas] ]
        SHOut  DATA_PIN, CLOCK_PIN,0,[ SegDisp[Centenas] ]

        LATCH_PIN = 1

        DelayMS 200

    Next Numero

    DelayMS 200

    For Numero = 999 To 0 Step -1

        Centenas = Dig Numero,2
        Decenas = Dig Numero,1
        Unidades = Dig Numero,0

        LATCH_PIN = 0

        HRSOut 0, DATA_PIN, CLOCK_PIN, SegDisp[Unidades]
        HRSOut 0, DATA_PIN, CLOCK_PIN, SegDisp[Decenas]
        HRSOut 0, DATA_PIN, CLOCK_PIN, SegDisp[Centenas]

        LATCH_PIN = 1

        DelayMS 200

    Next Numero

    DelayMS 200

Loop

top204

You beat me too it Pepe, and nice coding.

The initial question intrigued me, and I have seen some C code that is rather cumbersome (to say the least), and actually not working correctly, so I created some code myself for the task, using a PIC16F628A device running at 20MHz, but it will operate on any 14-bit core (enhanced or not enhanced) device, or 18F device, at any supported speed.

It's been a while since I created code for an old 14-bit core device, so it ticked the nostalgia box as well, but they are rather inflexible and 'very' out of date now, so it will be a rare occurrence. :-)

The code below is for five, Common Anode or Common Cathode, seven segment LEDs, displaying a 16-bit value passed to the 'Display' procedure. It has zero blanking implemented as well:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interface to Five Common Anode seven segment LED displays using 74HC595 shift registers.
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook.
'
    Device = 16F628A                                                                        ' Tell the compiler what device to compile for
    Declare Xtal = 20                                                                       ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Variable_Bank_Cross = On                                                   ' Make sure all multi-byte variables remain within a single RAM bank
'
' Setup the USART for any debugging required
'
    Declare Hserial_Baud  = 9600
    Declare HSerout_Pin   = PORTB.2
    Declare HSerin_Pin    = PORTB.1
    Declare Hserial_Clear = On                                                              ' Enable Error clearing on received bytes
'
' Setup the pins to the 74HC595 Shift Registers
'
$define SR_Latch_Pin PORTB.4                                                                ' Connects to pin 12 of the 74595 (named ST_CP or RCLK), and is the Storage Latch input
$define SR_Clock_Pin PORTB.5                                                                ' Connects to pin 11 of the 74595 (named SH_CP or SRCLK), and is the Clock input
$define SR_Data_Pin  PORTB.3                                                                ' Connects to pin 14 of the 74595 (named DS or SER), and is the Serial Data input

'$define CC_Display                                                                         ' Tell the program to use the lookup values for Common Cathode displays (comment out for Common Anode)
'
' Create variables for the demo here
'
    Dim wCountValue As Word                                                                 ' Holds the main count value

'---------------------------------------------------------------------------------------------------------
' The main program starts here
' Display an incrementing value on the seven segment displays
'
Main:
    Setup()                                                                                 ' Setup the program and any peripherals
    Do                                                                                      ' Create a loop
        For wCountValue = 1 To 65535 Step 2                                                 ' Create a counting loop
            Display(wCountValue)                                                            ' Display the value on the seven segment displays
            DelayMs 100                                                                     ' A delay, so that the LEDs are not a blur
        Next                                                                                ' Close the counting loop
    Loop                                                                                    ' Loop forever

'---------------------------------------------------------------------------------------------------------
' Display a 16-bit value on the seven segment LEDs
' Input    : pValue holds the value to display on the LEDs
' Output    : None
' Notes    : The routine has zero blanking for the value displayed
'
Proc Display(pValue As Word)
    Dim Digit10000s As Byte = Dig(pValue, 4)                                                ' Holds the fifth digit value (to the right of the 16-bit value)
    Dim Digit1000s  As Byte = Dig(pValue, 3)                                                ' Holds the fourth digit value (to the right of the 16-bit value)
    Dim Digit100s   As Byte = Dig(pValue, 2)                                                ' Holds the third digit value (to the right of the 16-bit value)
    Dim Digit10s    As Byte = Dig(pValue, 1)                                                ' Holds the second digit value (to the right of the 16-bit value)
    Dim Digit1s     As Byte = Dig(pValue, 0)                                                ' Holds the first digit value (to the right of the 16-bit value)
$ifdef CC_Display                                                                           ' Are the LED displays Common Cathode?
    Symbol cBlankVal = 0                                                                    ' Yes. So a 0 blanks them
$else                                                                                       ' Otherwise... They are Common Anode displays...
    Symbol cBlankVal = 255                                                                  ' So 255 blanks them
$endif
'
' Convert the digit values from pValue
'
    Digit1s     = FindSegments(Digit1s)                                                     ' \
    Digit10s    = FindSegments(Digit10s)                                                    ' |
    Digit100s   = FindSegments(Digit100s)                                                   ' | Convert the digits into their 7 segment patterns
    Digit1000s  = FindSegments(Digit1000s)                                                  ' |
    Digit10000s = FindSegments(Digit10000s)                                                 ' /

    PinClear SR_Latch_Pin                                                                  ' Clear the latch, so the outputs can alter
    If pValue < 10 Then                                                                    ' Is the value a single digit?
        Digit10s    = cBlankVal                                                            ' Yes. So blank out the second digit
        Digit100s   = cBlankVal                                                            ' Blank out the third digit
        Digit1000s  = cBlankVal                                                            ' Blank out the fourth digit
        Digit10000s = cBlankVal                                                            ' Blank out the fifth digit
   
    ElseIf pValue < 100 Then                                                               ' Is the value 2 digits?
        Digit100s   = cBlankVal                                                            ' Yes. So blank out the third digit
        Digit1000s  = cBlankVal                                                            ' Blank out the fourth digit
        Digit10000s = cBlankVal                                                            ' Blank out the fifth digit
   
    ElseIf pValue < 1000 Then                                                              ' Is the value 3 digits?
        Digit1000s  = cBlankVal                                                            ' Yes. So blank out the fourth digit
        Digit10000s = cBlankVal                                                            ' Blank out the fifth digit

    ElseIf pValue < 10000 Then                                                             ' Is the value 4 digits?
        Digit10000s = cBlankVal                                                            ' Yes. So blank out the fifth digit
    EndIf
    SR_Write(Digit1s)                                                                      ' \
    SR_Write(Digit10s)                                                                     ' |
    SR_Write(Digit100s)                                                                    ' | Write the five digits to the shift registers
    SR_Write(Digit1000s)                                                                   ' |
    SR_Write(Digit10000s)                                                                  ' /
    PinSet SR_Latch_Pin                                                                    ' Latch the values on the outputs of the shift registers
EndProc

'---------------------------------------------------------------------------------------------------------
' Lookup the segment data for LED displays
' Input    : pValue holds the value to lookup
' Output    : Returns the segment value for a digit on a display
' Notes    : If the $define CC_Display is uncommented, the table is for Common Cathode displays, else it is for Common Anode displays.
'          : It is much more efficient in a procedure, than using multiple LookUp commands.
'
Proc FindSegments(pValue As Byte), Byte
$ifdef CC_Display                                                                          ' Are the LED displays Common Cathode?
    Result = Lookup pValue,[%11111100, %01100000, %11011010, %11110010, %01100110, %10110110, %10111110, %11100100, %11111110, %11110110]
$else                                                                                      ' Otherwise... They are Common Anode displays...
    Result = Lookup pValue,[%00000011, %10011111, %00100101, %00001101, %10011001, %01001001, %01000001, %00011011, %00000001, %00001001]
$endif
EndProc

'---------------------------------------------------------------------------------------------------------
' Write a byte to the shift register
' Input    : pData holds the 8-bit data to send
' Output    : None
' Notes    : Sends Least Significant Bit first
'          : Alter the DelayUS values for a faster or slower write
'
Proc SR_Write(pData As Byte)
    Dim bBits As Byte Access

    PinClear SR_Clock_Pin
    For bBits = 7 DownTo 0                                                                  ' Create a loop to send out the bits
        Ror pData                                                                           ' Rotate the Least Significant Bit into the Carry flag
        PinClear SR_Data_Pin                                                                ' \
        If STATUSbits_C = 1 Then                                                            ' | Transfer the state of the Carry flag to the Data pin
            PinSet SR_Data_Pin                                                              ' |
        EndIf                                                                               ' /
        DelayUs 7                                                                           ' \
        PinSet SR_Clock_Pin                                                                 ' | Clock the bit out
        DelayUs 7                                                                           ' |
        PinClear SR_Clock_Pin                                                               ' /
    Next
EndProc

'---------------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input    : None
' Output    : None
' Notes    : None
'
Proc Setup()
    PinLow SR_Latch_Pin                                                                     ' Make the shift register's Latch pin an output low
    PinLow SR_Clock_Pin                                                                     ' Make the shift register's Clock pin an output low
    PinLow SR_Data_Pin                                                                      ' Make the shift register's Data pin an output low
EndProc

'---------------------------------------------------------------------------------------------------------
' Setup the config fuses for the PIC16F628 device, to operate with an external crystal
'
    Config HS_OSC, WDT_OFF, PWRTE_ON, BODEN_OFF, LVP_OFF, CP_OFF, MCLRE_ON, DATA_CP_OFF

To reduce it to 3 LED displays is simplicity with the commented source code telling the user what is happening within it.

Below is a screenshot of the program operating in Proteus with Common Anode LEDs.

Seven_Segments_74HC595.jpg

The Positron8 source codes, and proteus project files are attached below.

Regards
Les

tolyan249

Thank you all so much for your help.

top204

Below is version 2 of the above firmware to drive seven segment LED display from shift registers.

The change in the firmware is the use of a Flash memory table for the LED segment patterns, instead of the LookUp command in a separate procedure. This makes the code a more efficient.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interface to Five Common Cathode or Common Anode seven segment LED displays using 74HC595 shift registers.
'
' Version 2.0 using a Flash memory table for the seven segment LED values, instead of a LookUp command in a procedure.
' Changed for more efficiency.
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook.
'
    Device = 16F628A                                                                        ' Tell the compiler what device to compile for
    Declare Xtal = 20                                                                       ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Variable_Bank_Cross = On                                                   ' Make sure all multi-byte variables remain within a single RAM bank
'
' Setup the pins to the 74HC595 Shift Registers
'
$define SR_Latch_Pin PORTB.4                                                                ' Connects to pin 12 of the 74595 (named ST_CP or RCLK), and is the Storage Latch input
$define SR_Clock_Pin PORTB.5                                                                ' Connects to pin 11 of the 74595 (named SH_CP or SRCLK), and is the Clock input
$define SR_Data_Pin  PORTB.3                                                                ' Connects to pin 14 of the 74595 (named DS or SER), and is the Serial Data input

$define CC_Display                                                                          ' Tell the program to use the table values for Common Cathode displays (comment out for Common Anode)
'
' Create variables for the demo here
'
    Dim wCountValue As Word                                                                 ' Holds the main count value

'---------------------------------------------------------------------------------------------------------
' The main program starts here
' Display an incrementing value on the seven segment displays
'
Main:
    Setup()                                                                                 ' Setup the program and any peripherals
    Do                                                                                      ' Create a loop
        For wCountValue = 1 To 65535 Step 2                                                 ' Create a counting loop
            Display(wCountValue)                                                            ' Display the value on the seven segment displays
            DelayMS 100                                                                     ' A delay, so that the LEDs are not a blur
        Next                                                                                ' Close the counting loop
    Loop                                                                                    ' Loop forever

'---------------------------------------------------------------------------------------------------------
' Display a 16-bit value on the seven segment LEDs
' Input     : pValue holds the value to display on the LEDs
' Output    : None
' Notes     : The routine has zero blanking for the value displayed
'
Proc Display(pValue As Word)
    Dim Digit10000s As Byte = Dig(pValue, 4)                                                ' Extract the fifth digit value (to the right of the 16-bit value)
    Dim Digit1000s  As Byte = Dig(pValue, 3)                                                ' Extract the fourth digit value (to the right of the 16-bit value)
    Dim Digit100s   As Byte = Dig(pValue, 2)                                                ' Extract the third digit value (to the right of the 16-bit value)
    Dim Digit10s    As Byte = Dig(pValue, 1)                                                ' Extract the second digit value (to the right of the 16-bit value)
    Dim Digit1s     As Byte = Dig(pValue, 0)                                                ' Extract the first digit value (to the right of the 16-bit value)
'
' Create a flash memory table to convert the digits to seven segment display values (a to g)
'
$ifdef CC_Display                                                                           ' Are the LED displays Common Cathode?
    Symbol cBlankVal = 0                                                                    ' Yes. So a 0 blanks them
    Dim Segs As Flash8 = %11111100, %01100000, %11011010, %11110010, %01100110, %10110110, %10111110, %11100100, %11111110, %11110110
$else                                                                                       ' Otherwise... They are Common Anode displays...  
    Symbol cBlankVal = 255                                                                  ' So 255 blanks them
    Dim Segs As Flash8 = %00000011, %10011111, %00100101, %00001101, %10011001, %01001001, %01000001, %00011011, %00000001, %00001001
$endif
    Digit1s     = CRead8 Segs[Digit1s]                                                      ' \
    Digit10s    = CRead8 Segs[Digit10s]                                                     ' |
    Digit100s   = CRead8 Segs[Digit100s]                                                    ' | Convert the digits into their 7 segment patterns
    Digit1000s  = CRead8 Segs[Digit1000s]                                                   ' |
    Digit10000s = CRead8 Segs[Digit10000s]                                                  ' /

    PinClear SR_Latch_Pin                                                                   ' Clear the latch, so the outputs can alter
    If pValue < 10 Then                                                                     ' Is the value a single digit?
        Digit10s    = cBlankVal                                                             ' Yes. So blank out the second digit
        Digit100s   = cBlankVal                                                             ' Blank out the third digit
        Digit1000s  = cBlankVal                                                             ' Blank out the fourth digit
        Digit10000s = cBlankVal                                                             ' Blank out the fifth digit

    ElseIf pValue < 100 Then                                                                ' Is the value 2 digits?
        Digit100s   = cBlankVal                                                             ' Yes. So blank out the third digit
        Digit1000s  = cBlankVal                                                             ' Blank out the fourth digit
        Digit10000s = cBlankVal                                                             ' Blank out the fifth digit

    ElseIf pValue < 1000 Then                                                               ' Is the value 3 digits?
        Digit1000s  = cBlankVal                                                             ' Yes. So blank out the fourth digit
        Digit10000s = cBlankVal                                                             ' Blank out the fifth digit

    ElseIf pValue < 10000 Then                                                              ' Is the value 4 digits?
        Digit10000s = cBlankVal                                                             ' Yes. So blank out the fifth digit
    EndIf
    SR_Write(Digit1s)                                                                       ' \
    SR_Write(Digit10s)                                                                      ' |
    SR_Write(Digit100s)                                                                     ' | Write the five digits to the shift registers
    SR_Write(Digit1000s)                                                                    ' |
    SR_Write(Digit10000s)                                                                   ' /
    PinSet SR_Latch_Pin                                                                     ' Latch the values on the outputs of the shift registers
EndProc

'---------------------------------------------------------------------------------------------------------
' Write a byte to the shift register
' Input     : pData holds the 8-bit data to send
' Output    : None
' Notes     : Sends Least Significant Bit first
'           : Alter the DelayUS values for a faster or slower write
'
Proc SR_Write(pData As Byte)
    Dim bBits As Byte Access

    PinClear SR_Clock_Pin
    For bBits = 7 DownTo 0                                                                  ' Create a loop to send out the bits
        Ror pData                                                                           ' Rotate the Least Significant Bit into the Carry flag
        PinClear SR_Data_Pin                                                                ' \
        If STATUSbits_C = 1 Then                                                            ' | Transfer the state of the Carry flag to the Data pin
            PinSet SR_Data_Pin                                                              ' |
        EndIf                                                                               ' /
        DelayUS 7                                                                           ' \
        PinSet SR_Clock_Pin                                                                 ' | Clock the bit out
        DelayUS 7                                                                           ' |
        PinClear SR_Clock_Pin                                                               ' /
    Next
EndProc

'---------------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    PinLow SR_Latch_Pin                                                                     ' Make the shift register's Latch pin an output low
    PinLow SR_Clock_Pin                                                                     ' Make the shift register's Clock pin an output low
    PinLow SR_Data_Pin                                                                      ' Make the shift register's Data pin an output low
EndProc

'---------------------------------------------------------------------------------------------------------
' Setup the config fuses for the PIC16F628 device, to operate with an external crystal
'
    Config HS_OSC, WDT_OFF, PWRTE_ON, BODEN_OFF, LVP_OFF, CP_OFF, MCLRE_ON, DATA_CP_OFF

Frizie

Les, you wrote:
    If pValue < 10 Then                                                                     ' Is the value a single digit?
        Digit10s = 0                                                                        ' Yes. So blank out the second digit
        Digit100s = 0                                                                       ' Blank out the third digit
        Digit1000s = 0                                                                      ' Blank out the fourth digit
        Digit10000s = 0                                                                     ' Blank out the fifth digit

    ElseIf pValue < 100 Then                                                                ' Is the value 2 digits?
        Digit100s = 0                                                                       ' Yes. So blank out the third digit
        Digit1000s = 0                                                                      ' Blank out the fourth digit
        Digit10000s = 0                                                                     ' Blank out the fifth digit

    ElseIf pValue < 1000 Then                                                               ' Is the value 3 digits?
        Digit1000s = 0                                                                      ' Yes. So blank out the fourth digit
        Digit10000s = 0                                                                     ' Blank out the fifth digit

    ElseIf pValue < 10000 Then                                                              ' Is the value 4 digits?
        Digit10000s = 0                                                                     ' Yes. So blank out the fifth digit
    EndIf


But is it not more efficient to do it like this:
    If pValue < 10    Then Digit10s    = 0    ' If value is 1 digits, blank out the second digit
    If pValue < 100   Then Digit100s   = 0    ' If value is 2 digits, blank out the third  digit
    If pValue < 1000  Then Digit1000s  = 0    ' If value is 3 digits, blank out the fourth digit
    If pValue < 10000 Then Digit10000s = 0    ' If value is 4 digits, blank out the fifth  digit
Ohm sweet Ohm | www.picbasic.nl

top204

#10
Nice one Frizie.

It is always good to have a third person's look over code, because sometimes, the obvious is overlooked. :-)

So the version 3 code listing is now:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Interface to five Common Cathode or Common Anode seven segment LED displays using 74HC595 shift registers.
'
' Version 2.0 using a Flash memory table for the seven segment LED values, instead of a LookUp command in a procedure.
' Changed for more efficiency.
'
' Version 3.0 using a few If-Then statements to remove the leading blanks, instead of a block of ElseIf statements
' Many thanks Frizie.
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/positron-compilers-experimenters-notebook.
'
    Device = 16F628A                                                                        ' Tell the compiler what device to compile for
    Declare Xtal = 20                                                                       ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Variable_Bank_Cross = On                                                   ' Make sure all multi-byte variables remain within a single RAM bank
'
' Setup the USART for any debugging required
'
    Declare Hserial_Baud  = 9600
    Declare HSerout_Pin   = PORTB.2
    Declare HSerin_Pin    = PORTB.1
    Declare Hserial_Clear = On                                                              ' Enable Error clearing on received bytes
'
' Setup the pins to the 74HC595 Shift Registers
'
$define SR_Latch_Pin PORTB.4                                                                ' Connects to pin 12 of the 74595 (named ST_CP or RCLK), and is the Storage Latch input
$define SR_Clock_Pin PORTB.5                                                                ' Connects to pin 11 of the 74595 (named SH_CP or SRCLK), and is the Clock input
$define SR_Data_Pin  PORTB.3                                                                ' Connects to pin 14 of the 74595 (named DS or SER), and is the Serial Data input

$define CC_Display                                                                          ' Tell the program to use the table value for Common Cathode displays (comment out for Common Anode)
'
' Create variables for the demo here
'
    Dim wCountValue As Word                                                                 ' Holds the main count value

'---------------------------------------------------------------------------------------------------------
' The main program starts here
' Display an incrementing value on the seven segment displays
'
Main:
    Setup()                                                                                 ' Setup the program and any peripherals
    Do                                                                                      ' Create a loop
        For wCountValue = 1 To 65535 Step 2                                                 ' Create a counting loop
            Display(wCountValue)                                                            ' Display the value on the seven segment displays
            DelayMS 100                                                                     ' A delay, so that the LEDs are not a blur
        Next                                                                                ' Close the counting loop
    Loop                                                                                    ' Loop forever

'---------------------------------------------------------------------------------------------------------
' Display a 16-bit value on the seven segment LEDs
' Input     : pValue holds the value to display on the LEDs
' Output    : None
' Notes     : The routine has zero blanking for the value displayed
'
Proc Display(pValue As Word)
    Dim Digit10000s As Byte = Dig(pValue, 4)                                                ' Extract the fifth digit value (to the right of the 16-bit value)
    Dim Digit1000s  As Byte = Dig(pValue, 3)                                                ' Extract the fourth digit value (to the right of the 16-bit value)
    Dim Digit100s   As Byte = Dig(pValue, 2)                                                ' Extract the third digit value (to the right of the 16-bit value)
    Dim Digit10s    As Byte = Dig(pValue, 1)                                                ' Extract the second digit value (to the right of the 16-bit value)
    Dim Digit1s     As Byte = Dig(pValue, 0)                                                ' Extract the first digit value (to the right of the 16-bit value)
'
' Create a flash memory table to convert the digits to seven segment display values (a to g)
'
$ifdef CC_Display                                                                           ' Are the LED displays Common Cathode?
    Symbol cBlankVal = 0                                                                    ' Yes. So a 0 blanks them
    Dim Segs As Flash8 = %11111100, %01100000, %11011010, %11110010, %01100110, %10110110, %10111110, %11100100, %11111110, %11110110
$else                                                                                       ' Otherwise... They are Common Anode displays...
    Symbol cBlankVal = 255                                                                  ' So 255 blanks them
    Dim Segs As Flash8 = %00000011, %10011111, %00100101, %00001101, %10011001, %01001001, %01000001, %00011011, %00000001, %00001001
$endif
    Digit1s     = CRead8 Segs[Digit1s]                                                      ' \
    Digit10s    = CRead8 Segs[Digit10s]                                                     ' |
    Digit100s   = CRead8 Segs[Digit100s]                                                    ' | Convert the digits into their 7 segment patterns
    Digit1000s  = CRead8 Segs[Digit1000s]                                                   ' |
    Digit10000s = CRead8 Segs[Digit10000s]                                                  ' /

    PinClear SR_Latch_Pin                                                                   ' Clear the latch, so the outputs can alter
    If pValue < 10    Then Digit10s    = cBlankVal                                          ' If pValue is 1 digit, then blank out the second digit
    If pValue < 100   Then Digit100s   = cBlankVal                                          ' If pValue is 2 digits, then blank out the third  digit
    If pValue < 1000  Then Digit1000s  = cBlankVal                                          ' If pValue is 3 digits, then blank out the fourth digit
    If pValue < 10000 Then Digit10000s = cBlankVal                                          ' If pValue is 4 digits, then blank out the fifth  digit
    SR_Write(Digit1s)                                                                       ' \
    SR_Write(Digit10s)                                                                      ' |
    SR_Write(Digit100s)                                                                     ' | Write the five digits to the shift registers
    SR_Write(Digit1000s)                                                                    ' |
    SR_Write(Digit10000s)                                                                   ' /
    PinSet SR_Latch_Pin                                                                     ' Latch the values on the outputs of the shift registers
EndProc

'---------------------------------------------------------------------------------------------------------
' Write a byte to the shift register
' Input     : pData holds the 8-bit data to send
' Output    : None
' Notes     : Sends Least Significant Bit first
'           : Alter the DelayUS values for a faster or slower write
'
Proc SR_Write(pData As Byte)
    Dim bBits As Byte Access

    PinClear SR_Clock_Pin
    For bBits = 7 DownTo 0                                                                  ' Create a loop to send out the bits
        Ror pData                                                                           ' Rotate the Least Significant Bit into the Carry flag
        PinClear SR_Data_Pin                                                                ' \
        If STATUSbits_C = 1 Then                                                            ' | Transfer the state of the Carry flag to the Data pin
            PinSet SR_Data_Pin                                                              ' |
        EndIf                                                                               ' /
        DelayUS 7                                                                           ' \
        PinSet SR_Clock_Pin                                                                 ' | Clock the bit out
        DelayUS 7                                                                           ' |
        PinClear SR_Clock_Pin                                                               ' /
    Next
EndProc

'---------------------------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    PinLow SR_Latch_Pin                                                                     ' Make the shift register's Latch pin an output low
    PinLow SR_Clock_Pin                                                                     ' Make the shift register's Clock pin an output low
    PinLow SR_Data_Pin                                                                      ' Make the shift register's Data pin an output low
EndProc

'---------------------------------------------------------------------------------------------------------
' Setup the config fuses for the PIC16F628 device, to operate with an external crystal
'
    Config HS_OSC, WDT_OFF, PWRTE_ON, BODEN_OFF, LVP_OFF, CP_OFF, MCLRE_ON, DATA_CP_OFF

Best regards
Les

tolyan249

Les, thank you so much for your help

top204

Below is another version of the Display procedure within the above code listings, using Frizie's principle, but twisted to make it a bit more efficient in operation:

'---------------------------------------------------------------------------------------------------------
' Display a 16-bit value on the seven segment LEDs
' Input     : pValue holds the value to display on the LEDs
' Output    : None
' Notes     : The routine has zero blanking for the value displayed
'
Proc Display(pValue As Word)
Declare Warnings = Off                                                                      ' Disable the warnings about calling Dig from within CREad8
    Dim Digit10000s As Byte                                                                 ' Holds the fifth digit value (to the right of the 16-bit value)
    Dim Digit1000s  As Byte                                                                 ' Holds the fourth digit value (to the right of the 16-bit value)
    Dim Digit100s   As Byte                                                                 ' Holds the third digit value (to the right of the 16-bit value)
    Dim Digit10s    As Byte                                                                 ' Holds the second digit value (to the right of the 16-bit value)
    Dim Digit1s     As Byte                                                                 ' Holds the first digit value (to the right of the 16-bit value)
'
' Create a flash memory table to convert the digits to seven segment display patterns (a to g)
'
$ifdef CC_Display                                                                           ' Are the LED displays Common Cathode?
    Symbol cBlankVal = 0                                                                    ' Yes. So a 0 blanks them
    Dim Segs As Flash8 = %11111100, %01100000, %11011010, %11110010, %01100110, %10110110, %10111110, %11100100, %11111110, %11110110
$else                                                                                       ' Otherwise... They are Common Anode displays...
    Symbol cBlankVal = 255                                                                  ' So 255 blanks them
    Dim Segs As Flash8 = %00000011, %10011111, %00100101, %00001101, %10011001, %01001001, %01000001, %00011011, %00000001, %00001001
$endif   
    Digit1s     = CRead8 Segs[Dig(pValue, 0)]                                               ' Extract the first digit of pValue, and convert it into a 7 segment pattern                                                   
    Digit10s    = cBlankVal                                                                 ' \
    Digit100s   = cBlankVal                                                                 ' | Default to all the leading zeros blanked out
    Digit1000s  = cBlankVal                                                                 ' |
    Digit10000s = cBlankVal                                                                 ' /    
    If pValue > 9 Then                                                                      ' Does pValue have 2 digits in its integer value?
        Digit10s = CRead8 Segs[Dig(pValue, 1)]                                              ' Yes. So extract the second digit of pValue, and convert it into a 7 segment pattern
    EndIf
    If pValue > 99 Then                                                                     ' Does pValue have 3 digits in its integer value?
        Digit100s = CRead8 Segs[Dig(pValue, 2)]                                             ' Yes. So extract the third digit of pValue, and convert it into a 7 segment pattern
    EndIf
    If pValue > 999 Then                                                                    ' Does pValue have 4 digits in its integer value?
        Digit1000s = CRead8 Segs[Dig(pValue, 3)]                                            ' Yes. So extract the fourth digit of pValue, and convert it into a 7 segment pattern                                                 
    EndIf
    If pValue > 9999 Then                                                                   ' Does pValue have 5 digits in its integer value?
         Digit10000s = CRead8 Segs[Dig(pValue, 4)]                                          ' Yes. So extract the fifth digit of pValue, and convert it into a 7 segment pattern 
    EndIf    
    PinClear SR_Latch_Pin                                                                   ' Clear the latch, so the outputs can alter
    SR_Write(Digit1s)                                                                       ' \
    SR_Write(Digit10s)                                                                      ' |
    SR_Write(Digit100s)                                                                     ' | Write the five digits to the shift registers
    SR_Write(Digit1000s)                                                                    ' |
    SR_Write(Digit10000s)                                                                   ' /
    PinSet SR_Latch_Pin                                                                     ' Latch the values on the outputs of the shift registers
Declare Warnings = On                                                                       ' Re-enable warnings before the procedure is exited
EndProc

Just replace the Display procedure code in the previous code listings with this version.

Regards
Les