A question was asked on the Positron compilers forum the other day (protoncompiler.com), concerning interfacing seven segment LED displays, using shift registers, and it triggered something in me to write some code for the task, and show how good the Positron compilers are. So I created the code listing below:
'
' /\\\\\\\\\
' /\\\///////\\\
' \/\\\ \/\\\ /\\\ /\\\
' \/\\\\\\\\\\\/ /\\\\\ /\\\\\\\\\\ /\\\\\\\\ /\\\\\\\\\\\ /\\\\\\\\\\\ /\\\\\\\\\
' \/\\\//////\\\ /\\\///\\\ \/\\\////// /\\\/////\\\ \////\\\//// \////\\\//// \////////\\\
' \/\\\ \//\\\ /\\\ \//\\\ \/\\\\\\\\\\ /\\\\\\\\\\\ \/\\\ \/\\\ /\\\\\\\\\\
' \/\\\ \//\\\ \//\\\ /\\\ \////////\\\ \//\\/////// \/\\\ /\\ \/\\\ /\\ /\\\/////\\\
' \/\\\ \//\\\ \///\\\\\/ /\\\\\\\\\\ \//\\\\\\\\\\ \//\\\\\ \//\\\\\ \//\\\\\\\\/\\
' \/// \/// \///// \////////// \////////// \///// \///// \////////\//
' 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.
' Will operate on any 14-bit PIC or 18F microcontroller.
'
' 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 ST_CP of the 74595, and is the the Latch input
$define SR_Clock_Pin PORTB.5 ' Connects to SH_CP of the 74595, and is the Clock input
$define SR_Data_Pin PORTB.3 ' Connects to DS of the 74595, and is the Serial Data input
'
' Tell the program to use the data values for Common Cathode displays (comment out for Common Anode)
'
$define CC_Display
'
' 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 = 0 To 65535 Step 5 ' 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 shift register's 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
The source code for the interface running on a PIC16F628 device, can be downloaded from here: Seven_Segments_using_74595
Below is a video of the code listing operating within the Proteus simulator.