In this project the PIC is used to control a block of two7-segment LED displays directly. The demonstration program is just a counter from 00 to 99 in about 500msec intervals. Therefore, the displayed sequence of 100 numbers is 00, 01, 02, ..., 99 repeated periodically.
The LED display I use is HDSP-521E, all whose segments have a common anode. As in the last experiment on driving a single-digit LED, I use just one current-limiting resistor of 220 Ohm connected to the common anode of each digit. A better solution would be to put a separate resistor between the PIC and LED block.
| Schematic | Layout | Segm. codes | ||
![]() |
Because of a limited number of PIC pins, we cannot display each of the digits at the same time. A practical solution is to alternate displaying them starting with the left one, then followed by the right one periodically. This way one digit will be displayed in each moment, but due to the human eye ability to "remember" am image for about 25 msec we will have an impression of displaying both digits simultaneously.
In the sample program below each digit on the LED display is active for 10msec which eliminates flickering. To switch between the digits we use PNP transistors controlled by the PORTA of PIC. The codes at pins RA0 and RA1 alternate between 1 and 2 (01 and 10 in binary) resulting in displaying the left and the right digit, respectively (the displayed digit corresponds to 0 at the corresponding pin of PORTA).
Displaying a digit is implemented in function displayDigit. This function starts with flipping the state of PORTA to display the corresponding digit. This is controlled by the variable d alternating between 1 and 2 as described above. After that the code corresponding to the digit n (passed as a parameter) is output to PORTB as in the last experiment. The function completes by calling a 10msec delay() function. The delay() function takes a parameter del as a number of milliseconds. The del-loop of this function consists of 5 instructions and executes in 5 CPU cycles (the goto instruction takes 2 cycles). Thus, each iteration of this loop takes 5μs for PIC1684A @ 4Mhz. This loop is repeated 200 times providing a delay of 5μs·200=1msec. Therefore, id the parameter del is 10, this code provides a 10msec delay.
The variable s is used to control the update speed of the counter. It is decremented from the initial value of 25 after each loop through the display digits, i.e. once in about 20msec. This results in updating the number on the display after every 20*25=500msec. The variables n1 and n0 control the digits currently displayed on the left and the right LED display, respectively. As soon as the variable s reaches the value 0, n0 is incremented on 1. If n0 reaches 10 it is reset back to 0 and n1 is incremented. When n1 reaches 10 it is reset back to 0 and the entire sequence of numbers 00, 01, ..., 99 will be repeating over and over.
TITLE "7seg2.asmt" ; displaying 0,1,...,99 on a double digit LED
List P=16F84a, R=DEC
INCLUDE "p16F84a.inc"
; data segment
CBLOCK 0x00C
del, n ; variables for passing the parameters
delTMP ; local var for the delay function
n1, n0 ; digits to display on LEDs (left,right)
d ; currently processing digit (1 or 2)
s ; counter update speed (500 ms)
segments:10 ; 7-seg codes array
ENDC
; code segment
PAGE
__CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC
org 0 ; start program at the beginning of mem
bsf STATUS, RP0 ; change to BANK 1
movlw 3
movwf PORTA ; turn off all digits
clrf TRISB ^ 0x80 ; enable RB1-RB7 for output
movlw 0x1C
movwf TRISA ^ 0x80 ; enable RA0 and RA1 for output
movlw 0x7F ; enable internal Pull-Ups
movwf OPTION_REG ^ 0x80
bcf STATUS, RP0 ; back to BANK 0
; initialization
call initSegments
clrf n1 ; start counting with 00
clrf n0
movlw 1 ; start displaying the left digit
movwf d ; this number will flip between 2 and 1
movlw 25 ; set up counter update speed 500ms
movwf s ; 2*10*25 = 500ms
; main loop
loop
movf n1, w ; display the left digit n1
movwf n ; pass n1 to displayDigit as n
call displayDigit ; update the left digit
movf n0, w ; display the left digit n0
movwf n ; pass n0 to displayDigit
call displayDigit ; update the right digit
decfsz s, f ; time to update the counter?
goto loop ; NO - display same digits n1,n0 again
; update the counter digits n1 and n0
movlw 25 ; YES - update n0 (and n1)
movwf s ; restore s
incf n0, f ; n0++ (the right digit)
movf n0, w
sublw 10
btfss STATUS, Z ; n0 == 10?
goto loop ; NO - continue
clrf n0 ; YES - reset n0 to 0
incf n1, f ; increment the right digit
movf n1, w
sublw 10
btfss STATUS, Z ; n1 == 10?
goto loop ; NO - digits update is done
clrf n1 ; YES - reset n1 to 0
goto loop
; procedures
displayDigit ; display digit n at position d
movf d, w
movwf PORTA ; start displaying the digit #d
xorlw 3 ; flip d
movwf d ; save it
movfw n ; get parameter to w
addlw segments
movwf FSR ; FSR is a pointer to the digit code
movf INDF, w ; w = segments[digit]
xorlw 0xFF ; invert the code for a common anode LED
movwf PORTB ; light on the digit
movlw 10 ; a 10ms delay
movwf del
call delay
return
initSegments ; set up 7-seg digit codes
movlw b'11011110' ; gidit 0
movwf segments+0
movlw b'00011000' ; digit 1
movwf segments+1
movlw b'11101100' ; digit 2
movwf segments+2
movlw b'01111100' ; digit 3
movwf segments+3
movlw b'00111010' ; digit 4
movwf segments+4
movlw b'01110110' ; digit 5
movwf segments+5
movlw b'11110110' ; digit 6
movwf segments+6
movlw b'00011100' ; digit 7
movwf segments+7
movlw b'11111110' ; digit 8
movwf segments+8
movlw b'01111110' ; digit 9
movwf segments+9
return
delay ; a delay for del milliseconds
movlw 200
movwf delTMP
delL nop ; this loop takes 5us*200 = 1ms
nop ; for PIC16F84A @ 4 Mhz
decfsz delTMP, f
goto delL
decfsz del
goto delay
return
end
|
Download 7seg2.asm
Last modified:Mon, Jan 23, 2023.