Step 4Software
The Trick
Yes, like everything, there's a trick. The trick is that there are never more than 8 LEDs illuminated at one time.For this to work well, a bit of crafty programming is needed. The concept I have chosen is to use a timer interrupt. Here's how the display interrupt works in plain english:
- Timer counts up to a certain point, when reached the interrupt service routine is run.
- This routine decides which row is the next one to be displayed.
- The information for the next row is looked up from a buffer and shifted into the column driver (this information is not "latched" so it is not yet displayed).
- The row driver is shut off, no LEDs are currently lit.
- The column driver is "latched" make in the information we shifted in two steps ago the current information to display.
- The row driver then provides current to the new row we are displaying.
- The interrupt service routine ends and program returns to normal flow until the next interrupt.
The full LED display is mapped out in an array. In between interrupts the array can be changed (be mindful of atomicity) and will appear on the display during the next interrupt.
The specifics of writing code for the AVR microcontroller and of how to write code to talk to the shift registers is beyond the scope of this instructable. I have included the source code (written in C and compiled with AVR-GCC) as well as the hex file to program directly. I have commented all of the code so you should be able to use this to clear up any questions about how to get data into the shift register and how the row refresh is working.
Please note that I am using a font file that came with the ks0108 universal C library. That library can be found here: http://en.radzio.dxp.pl/ks0108/
Update:
Shift Registers: How To
I've decided to add a bit about how to program with shift registers. I hope this clears things up for those who haven't worked with them before.What they do
Shift Registers take a signal from one wire and output that information to many different pins. In this case, there is one data wire that takes in the data and 8 pins that are controlled depending on what data has been received. To make things better, there is an outpin for each shift register that can be connected to the input pin of another shift register. This is called cascading and makes the expansion potential an almost unlimited prospect.
The Control Pins
Shift registers have 4 control pins:
- Latch - This pin tells the shift register when it is time to switch to newly entered data
- Data - The 1's and 0's telling the shift register what pins to activate are received on this pin.
- Clock - This is a pulse sent from the microcontroller that tells the shift register to take a data reading and move to the next step in the communication process
- Enable Output - This is an on/off switch, High=On, Low=Off
Here's a crash course in the operation of the above control pins:
Step 1: Set Latch, Data, and Clock low
- Setting the Latch low tells the shift register we are about to write to it.
Step 3: Set Clock pin high, telling the Shift Register to read in the current Data pin value
- All other values currently in the Shift Register will move over by 1 place, making room for the current logic value of the Data pin.
- The clock pin must be set low before changing to the next Data value. Toggling this pin between high and low is what creates the "clock pulse" the shift register needs to know when to move to the next step in the process.
- This tells the shift register to take all of the data that has been shifted in and use it to activate the output pins. This means that you will not see data as it is shifting in; no change in the output pins will occur until the Latch is set high.
- There will be no pin output until the Enable Output is set to high, no matter what is happening with the other three control pins.
- This pin can always be left high if you wish
There are two pins you can use for cascading, Os and Os1. Os is for fast rising clocks and Os1 is for slow rising clocks. Hook this pin to the data pin of the next shift register and the overflow from this chip will be entered into the next.
End of update
Addressing the display
In the example program I have created an array of 8 bytes called row_buffer[]. Each byte corresponds to one row of the 8x8 display, row 0 being the bottom and row 7 being the top. The least significant bit of each row is on the right, the most significant bit on the left. Changing the display is as easy as writing a new value to that data array, the interrupt service routine takes care of refreshing the display.Programming
Programming will not be discussed in detail here. I would warn you not to use a DAPA programming cable as I believe you will be unable to program the chip once it is running at 12MHz. All other standard programmers should work (STK500, MKII, Dragon, Parallel/Serial programmers, etc.).Fuses:
Make sure to program the fuses to use the 12MHz crystal
hfuse: 0xC9
lfuse: 0xEF
In Action
Once you program the chip the display should scroll a "Hello World!". Here is a video of the LED matrix in actions. The video quality is pretty low as I made this with my digital camera's video feature and not a proper video or webcam.
8x8_Matrix.zip9 KB| « Previous Step | Download PDFView All Steps | Next Step » |









































I have a simple ASM program with a matrix display light just columns. An example:
;-----------------------
LIST P=16F876
#include <p16F876.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
ORG 0x2100
DE 0x00
ORG 0
cblock 0x20
d1
d2
d3
endc
goto start
Delay
;999990 cycles
movlw 0x07
movwf d1
movlw 0x2F
movwf d2
movlw 0x03
movwf d3
Delay_0
decfsz d1, f
goto $+2
decfsz d2, f
goto $+2
decfsz d3, f
goto Delay_0
;6 cycles
goto $+1
goto $+1
goto $+1
;4 cycles (including call)
return
loop:
movlw b'00000111'
movwf PORTA
movlw b'11110010'
movwf PORTB
movlw b'11111111'
movwf PORTC
call Delay
call Delay
call Delay
goto loop
start:
bsf STATUS,RP0 ; select register page 1
movlw 0 ; put 0 into W
movwf TRISC ; set portC all output
clrf TRISA
clrf TRISB
bsf STATUS,RP1 ; select Page 2,
bcf STATUS,RP0 ; by setting RP1 in Status register and clearing RP0
clrf PORTC ; select Digital I/O on port C
bcf STATUS,RP1 ; back to Register Page 0
goto loop
end
;-----------------------
This program code is OK. But I want the program to which I could display the words fleeing across the screen. Started, I tried to ignite a pair of columns on different sites but with the burning LEDs. But received some strange flashing, do not light longer ... Anybody know what's wrong ...
Programme code:
;-----------------------
LIST P=16F876
#include <p16F876.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
ORG 0x2100
DE 0x00
ORG 0
cblock 0x20
Delay1 ; delay loop 1
Delay2 ; delay loop 2
Delay3 ; delay loop 3
TimeDelay ; time delay x 0.001 s
EndCount ; used to tell PIC the end of the table is reached
Counter ; used as table counter
Line1 ; Line 1
Line2 ; Line 2
Line3 ; Line 3
Line4 ; Line 4
Line5 ; Line 5
sad
Line6 ; Line 6
Line7 ; Line 7
Line8 ; Line 8
Layer4 ; brightness, and time
Brightness ; LED brightness
Time ; time for each pattern to stay
Temp ; temp register
d1
d2
d3
endc
goto start
Delay
;999990 cycles
movlw 0x17
movwf d1
movlw 0x2F
movwf d2
movlw 0x03
movwf d3
Delay_0
decfsz d1, f
goto $+2
decfsz d2, f
goto $+2
decfsz d3, f
goto Delay_0
;6 cycles
goto $+1
goto $+1
goto $+1
;4 cycles (including call)
return
loop:
movlw b'00000001'
movwf Line1
movlw b'11110010'
movwf Line2
call output
call Delay
movlw b'11100000'
movwf Line1
movlw b'10101010'
movwf Line2
call output
call Delay
goto loop
start:
bsf STATUS,RP0 ; select register page 1
movlw 0 ; put 0 into W
movwf TRISC ; set portC all output
clrf TRISA
clrf TRISB
bsf STATUS,RP1 ; select Page 2,
bcf STATUS,RP0 ; by setting RP1 in Status register and clearing RP0
clrf PORTC ; select Digital I/O on port C
bcf STATUS,RP1 ; back to Register Page 0
goto loop
output:
movfw Layer4
andlw b'00000001'
movwf Time
incf Time,1
bcf STATUS,C
rlf Time,1
bcf STATUS,C
rlf Time,1
bcf STATUS,C
rlf Time,1
bcf STATUS,C
rlf Time,1
bcf STATUS,C
rlf Time,1
clrf PORTB ; clear port B
movfw Line1 ; move layer1 to W
movwf PORTC ; put W onto PortC
bsf PORTB,4 ; turn on layer 1 buy outputing bit 5 of PortB
movfw Brightness ; put brightness into W
call Delayy ; call the delay
bcf PORTB,4 ; turn off layer 1
movfw Brightness ; put Brightness into W
sublw 4 ; sub W from 4
btfss STATUS,Z ; skip if the zero flag is set
call Delayy ; call the delay
decfsz Time
clrf PORTB ; clear port B
movfw Line2 ; move Line2 to W
movwf PORTC ; put W onto PortC
bsf PORTB,5 ; turn on layer 2 buy outputing bit 6 of PortB
movfw Brightness ; put brightness into W
call Delayy ; call the delay
bcf PORTB,5 ; turn off layer 2
movfw Brightness ; put Brightness into W
sublw 4 ; sub W from 4
btfss STATUS,Z ; skip if the zero flag is set
call Delayy ; call the delay
decfsz Time
decfsz Time ; decrement the Time regiester
return
Delayy:
movwf Delay3 ; put W into Delay 3
Loop1:
; After Delay2 decreses to 0, it is reset to..
movlw 0x1 ; put 1 into W
movwf Delay2 ; put W into Delay2
Loop2:
; After Delay1 decreses to 0, it is reset to E9h
movlw 0x1D ; put 80 into W
movwf Delay1 ; put W into Delay1
Loop3:
decfsz Delay1 ; decrement Delay1
goto Loop3 ; jump back to Loop3
decfsz Delay2 ; decrement Delay2
goto Loop2 ; jump back to Loop2
decfsz Delay3 ; decrement Delay3
goto Loop1 ; jump back to Loop1
return
end
;----------------------------------------------------------
Thanks for help. :)
You should also be able to put the chip in the DragonRider with a crystal in the crystal slot and "recover" it without using high voltage programming.
Check out my other instructable for more help:
http://www.instructables.com/id/How-to-use-the-Dragon-Rider-500-with-your-AVR-Drag/