Control 3 (expandable to 8) 7 segment LED displays with 3 io pins and a driver IC

by Ken Mathis

Ken Mathis of ASC shares this code:

;FILE NAME:MAX7219
;Date:June 16, 2004
;Programmer:Ken Mathis
;Purpose of this program is to control several seven segment displays using the MAX7219
;seven segment display driver IC. The seven segment displays are multiplexed with the 
;7219 and are commone cathode type displays.


;This test code controls only 3 seven segment displays. The code can easily be expanded 
;for the max7219 to control up to 8 seven segment displays while consuming only 3 SX
;output pins
;Where appropriate, explanations are provided to account for more than 3 seven segment displays

;This configuration uses the SX internal oscillator as the timimg for shifting data
;out is not critical
;-----[Assembler directives]---------------------------------------
ifdef __SASM
	DEVICE	SX18L, STACKX, OPTIONX
	IRC_CAL	IRC_FAST
	FREQ	4_000_000
else
	DEVICE	SX18AC, OPTIONX
endif
DEVICE	TURBO, OSC4MHZ
RESET	START

;-----[Define variables and constants]------------------------------
org	$07		;$07 is first free variable space
Decode	ds	2	;assign 2 bytes of space for Decode - 7 & 8
ShtDn	ds	2	;assign 2 bytes of space for Shutdown - 9 & A
ScnLmt	ds	2	;assign 2 bytes of space for Scan Limit - B & C
Inten	ds	2	;assign 2 bytes of space for Intensity - D & E
bitcnt	ds	1	;assign 1 byte of space for bit counter - F

;dig0, dig1, & dig2 represent three 7 segment displays with a common cathode and
;dig0 is the least significant display
dig0	ds	2	;assign 2 bytes of space for Digit 0 - 10 & 11
dig1	ds	2	;assign 2 bytes of space for Digit 1 - 12 & 13
dig2	ds	2	;assign 2 bytes of space for Digit 2 - 14 & 15
;To display more digits variable manes MUST be added here sequentially
;after dig2 for the code to properly work.


; !!! IF 8 SEVEN SEGMENT DISPLAYS ARE USED, there will be no more room
;for the word counter (wrdcnt) in bank one. To avoid switching banks in 
;this circumstance, the upper or lower byte of any of the initialization 
;words (Decode, ShtDn, ScnLmt, or Inten) can be reused/reloaded with
;the appropriate value after the initialization if finished. A comment
;will be shown where to reload Decode if needed

wrdcnt	ds	1	;assign 1 byte of space for word counter - 16


;----[Define symbolic pin names]---------------------------------------


data	EQU	rb.1	;data pin connects to pin 1 of 7219
clock	EQU	rb.2	;clock pin connects to 13 of 7219
load	EQU	rb.3	;load pin connects to 12 of 7219

;-----[calls should be placed on first page between org $000 and org $100]--
org	$000

;5uS delay - generated using the delay code generator at sxlist.com
del_5uS
	jmp	$+1
	jmp	$+1
	jmp	$+1
	jmp	$+1
	nop
	nop
	ret

;sub to shift out msbit of each byte into carry
rotate
	rl	ind	;move msbit into carry 
	jc	high	;if carry is high jump to high
	clrb	data	;if carry is low ensure data pin is low
	jmp	$+2	;jump 2 lines
high
	setb	data	;make data pin high
	nop		;no operation
	ret

;clock pulse generation to shift data out of SX into max 7219
shiftout
	call	del_5uS	;5 uS set-up time
	setb	clock	;make clock (rb.2) high
	call	del_5uS	;5 uS hold time
	clrb	clock	;make clock low
	ret		;return

;-----[MAIN PROGRAM]------------------------------------------------------------
org	$100

Start			;reset point	

;-------[I/O port setting]------------------------------------------------------
	mode	$0f	;set mode for port direction
	mov	w,#$0
	mov	!ra,w	; all ra ports output
	mov	w,#$00
	mov	!rb,w	;all rb ports output



;-------[prepare variables for initialization of max7219]-----------------------
;mov w,#$XX loads the w register with hex value 
;mov NAME,w loads value of w into variable name
;Later in this program the initiazation is explained in detail
	mov	w,#$09
	mov	Decode,w
	mov	Inten+1,w
	mov	w,#$0f
	mov	Decode+1,w
	mov	w,#$10
	mov	bitcnt,w
	mov	w,#$0c
	mov	shtdn,w
	mov	w,#$01
	mov	shtdn+1,w
	mov	dig0,w
	mov	w,#$0b
	mov	scnlmt,w
	mov	w,#$02
	mov	scnlmt+1,w
	mov	dig1,w
	mov	w,#$0a
	mov	inten,w
	mov	w,#$03
	mov	dig2,w
	mov	w,#$04
	mov	wrdcnt,w


;point to first register that will hold data to shift out which
;is Decode at address $07. NOTE that this is a SX18 and does not have an RC
;port.	
	mov	w,#$07	
	mov	fsr,w

;-------[The program currently causes display to load 4 to each digit. To test a
;different value, change four to any digit 0 to 9. Your actual program will load 
;dig0+1, dig1+1 and dig2+1 with some dynamic data.
	mov	w,#$04
	mov	dig0+1,w
	mov	dig1+1,w
	mov	dig2+1,w


;------[MAX7219 Operation]----------------------------------------------------
;The 7219 must first be initialized. Initialization is done by sending serial
;data to the IC. Four 16 bit values sent will complete the initialization.

;To send a 16 bit value load is brought LOW, then each of 16 bits (msb 1st) is 
;clocked into the IC, and load is then brought HIGH to complete the shifting 
;of 16 bits into the device

;For each word sent to the IC, the most significant byte is the address and the
;lower byte sets the option for each particular function.
;For the descriptions that follow values will be shown as $Xx. The upper case x
;represents the upper nibble and the value is "don't care"

;DECODE MODE - Address $X9 
;Options	$X0 = No decoding
;		$X1 = Decode digit 0 (BCD)
;		$XF = Decode digits 0-3
;		$FF = Decode digits 0-7
;Sending $090F sets decode mode to enable digits 0-3 and unstucts that the least
;sig nibble is BCD 

;SHUTDOWN MODE - Address $XC
;Options	$X0 = Shutdown
;		$X1 = Normal Operation
;Sending $0C01 sets the IC for normal operation

;SCANLIMIT - Address $XB
;Options	$Xx where the least significant nibble sets the number of digits
;		to enable. digit 0, x = 0. digits 0 & 1 x = 1. digits 0, 1, & 2 x = 2
;Sending $0B02 enbables digts 0, 1 & 2
;Sending $0B07 enables all 8 digits

;INTENSITY - Address $XA
;Options	$00 = minimum intensity
;		$FF = maximum intensity
;		See MAX7219 data sheet for resistor selection and current


;----[set up SX controll pins]--------------------------------------------------------
	clrb	data		;make data pin low
	clrb	clock		;make clock pin low
	setb	load		;make load pin high
	call	del_5uS		;wait 5 uS

;----[Start of routine to send out first 16 bits]-------------------------------------
	clrb	load		;enable 7219 to start accepting serial data.
j1
	call	rotate		;call routine to move msbit into carry and set data pin 
				;high or low depending on state of bit carried out
	call	shiftout	;call routine to shift data bit to 7219
	dec	bitcnt		;decrement bit counter
	cjne	bitcnt,#8,j2	;check if 8 bits have been sent out
	inc	fsr		;if 8 bits were sent, increment fsr to point to next 
				;register
	jmp	$-8		;move back up to call rotate
j2
	cja	bitcnt,#0,j1	;check of bit counter is at zero (16 bits shifted out?)
	setb	load		;if 16 bits shifted out, load them into the 7219
	dec	wrdcnt		;check if the 4 initialization words shifted out
	cja	wrdcnt,#0,j3	;if word counter is above 0, jump to j3
	jmp	$+5		;if the 4 initialization words shifted out jump down 5 lines
j3	
	mov	w,#$10		;reload bit counter with 16
	mov	bitcnt,w	;reload bit counter with 16
	inc	fsr		;increment fsr to point to the next register
	jmp	$-$18		;jump up to the "clrb load" instruction to start another
				;sequence of shifting out 16 more bits


;-----[shift actual data into max7219]---------
;Data is sent to the 7219 in the same manner as the initialization described above.
;load is brought LOW, 16 bits clocked into device and load is brought HIGH to complete
;the loading of one digit.

;For each digit, the upper byte of 16 bits is the address of the digit and the lower
;byte is the value sent to the 7 segment. This value is either BCD or the "word" to control
;each of the 8 segments (decimal point). Remember that DECODE MODE determines how to 
;use the lower byte

;For	digit 0 the address is $01
;	digit 1 the address is $02
;	digit 2 the address is $03

;If decode mode was selected sending the 16 bit value of $0207 will tell the IC that
;digit number 1 gets a value of 7


	mov	w,#$10
	mov	fsr,w		;point to first address of digit 0 holding the most sig byte
	mov	bitcnt,w	;load the bit counter with 16

;If using 8 seven segment displays as decribed above, comment out the next two lines 
	mov	w,#$03		;since three digits are used in this example, wrdcnt is loaded w/3
	mov	wrdcnt,w
;Use these next two lines if 8 seven segments are used.
;	mov	w,#$08
;	mov	Decode,w

;----[Start of routine to send out first 16 bits of TEST data]-------------------------------------
;The rest of this code is exactly the same as the initialization code, so no comments added here.
;see initialzation above for comments.
	clrb	load		
j4
	call	rotate
	call	shiftout
	dec	bitcnt
	cjne	bitcnt,#8,j5
	inc	fsr
	jmp	$-8
j5
	cja	bitcnt,#0,j4
	setb	load
;If using 8 seven segment displays as decribed above, comment out the next two lines 
	dec	wrdcnt
	cja	wrdcnt,#0,j6

;Use these next two lines 
;	dec	Decode
;	cja	Decode,#0,j6

	jmp	$+5
j6	
	mov	w,#$10
	mov	bitcnt,w
	inc	fsr
	jmp	$-$18

	setb	load
	sleep

END