The Mux Mux Light Display
could then do the register map for the PIC program and I
could start writing code. I’ve done several PIC projects, so I
have snippets of code that I have used to initialize Timer0
and the USART. I’ve specified 9600 baud for the serial input
but you can modify the code to support the baud rate of
your choosing. The code uses Timer0 for the time between
display changes; I choose around 500 µs for a flicker free
display. The register map is:
; **************************************************
; PORT A & B I/O definitions for 16F648A version
;
; BIT 7 1
; PORTA a
; PORTB NC
;
;
**************************************************
6
DP
g
5432
c MCLR NC f
CA4 CA3 CA2 CA1
0
ed
RS232 b
There is also a bit mask register named this_segment.
This has the “bit selector” for the or operation to isolate
the bit, by shigting a zero through a field of ones. The
result of the logical-or operation is mostly ones. For the
selected bit, and the decoded digit, if both bits are low,
then the output of that bit will be low, driving the cathode
for that segment low and the ones in the other bits will
leave the other cathodes high (hence, no current
will flow). So, we will have, at most, only one segment lit
at any one time.
For the common cathode design, the voltage levels are
reversed, so we have to perform a logical-and function in a
field of ones with a mask of mostly zeros. The result of the
and operation is mostly zeros. For the selected bit and the
where DP is the decimal point, a-g are
the segments, and CA1-CA4 are the
digits. Note that my configuration has
the leftmost digit as CA4 while most
documentation has it as the rightmost. I do
it this way in case I have three digit
displays. NC stands for no connection.
There is an assembler define statement
that selects either common anode or
common cathode displays. If you have
a common cathode display, comment
out the #define COMMON_ANODE
statement and reassemble.
All the real work of the code is done in
the interrupt service routines. When
Timer0 generates an interrupt, the code
goes to the next segment to light or not
light, as required. Let’s look at a portion of
the code to see how we multiplex the
display. We will use the common anode
design. The code is listed in the LED
Segment Selection sidebar.
The segments are stored in an array
in general-purpose registers from
seg7digit to seg7digit+ 3 where each byte
represents a digit. There is a pointer
(modulo 4) named this_digit, which rolls
from 0, 1, 2, 3, 0, 1... and selects which
digit we will display. The pointer plus the
offset address to the base of seg7buffer is
added together and put in the field select
register (FSR). The contents of the register
pointed to by the address in the FSR
is read from memory using the INDR
(indirect register) and placed in the W
register. Then this value is held in the
register, decoded_digit. This has all
eight segments for the current digit we
are displaying.
LED SEGMENT SELECTION
NOTES:
1) Only the common anode code is shown for clarity. Refer to the source
code for additional details.
2) The seven-segment values have been stored in seg7digit buffer, NOT
bcd values. They are converted while in the serial interrupt service routine.
3) Turning on the common anodes is done outside this code and is
not shown.
;————-
; update the LED display with the new values.
; this is done on about a 500 microsecond rate to allow for all
; 32 iterations through the display.
;————-
; set up to do the next segment
bsf STATUS,C ;set carry bit
rlf this_segment,F ;set up next segment
btfsc STATUS,C ;see if we have rotated through
goto led_update100 ;still working on this digit
; here if we have rotated through all segments of the current digit
; set up for next digit.
movlw B’11111110’
movwf this_segment
incf this_digit,F
movlw B’00000011’
andwf this_digit,F
movf this_digit,W
addlw seg7digit
movwf FSR
movf INDF,W
movwf decoded_digit
;modulo 4 increment
;hold digit as pointer offset
;add in offset
;use FSR for buffer select
;hold digit in W
;hold onto value
; Turn off all cathodes and anodes in PORTB
led_update100:
movlw
movwf
; Do PORT A
; Turn off ALL cathodes PORTA
movlw H’FF’
movwf PORTA
B’10000001’
PORTB
; Turn on the selected segment on the display
movf this_segment,W ;get the desired segment
iorwf decoded_digit,W ;and with decoded digit
movwf decoded_segment ;and hold it
June 2007 41