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.