Welcome to the Matrix. The LED Matrix!
A quick search of the Internet shows various LED Chasers and circuit designs that mimic Knight Rider's Kitt car or Battlestar Galactica's Cyclon Scanner/Eye. This circuit uses a simple 12bit PIC to run 16 LEDs in a 4x4 matrix configuration (this includes the fading-tail-light effect as the LEDs scan from side to side).
Two of these scanners were mounted on two pictures of "suspected cyclons" at a science-fiction End Of Season Party as part of the props and decorations to add to the theme of the party.
![]() ![]() |
This is it. The end. The last episode of Battlestar Galactica. We will find all the clues and get all the answers. It will be two solid hours of our favourite show. Natasha Eloi from Space will be our special guest.
It's bound to be one frakkin' good finish. |
Needless to say, but still worth saying it.
The Party was definitely a Frakkin success.
You can download the Larson Eye file, or you can copy and paste the code shown below into your ASM code editor.
title 'Eye, Copyright by Jose Da Silva, 2009mar20' list P=16C54 ; list P=16F84 list f=INHX8M,C=120,T=on,ST=off ;****************************************************************************** ;DIP 16C54 or 16F84 ____ ____ ; <-|a2 \/ a1|-> ; <-|a3 a0|-> ; gnd-Rx120k ->|TOCKI osc1|<-RC=(12k+100pf)=650khz ;3k9+104!MCLR/Vpp->|!MCLR osc2|-> /4 ; gnd ->|Vss Vdd|<- +5v ; LEDrow0+ <-|b0 b7|--W--> LEDcol0- <->ICSPDAT ; LEDrow1+ <-|b1 b6|--W--> LEDcol1- <->ICSPCLK ; LEDrow2+ <-|b2 b5|--W--> LEDcol2- ; LEDrow3+ <-|b3 b4|--W--> LEDcol3- ; ---------- ; radix dec nolist #ifdef __16C54 #include "P16C5X.INC" StartR equ 8 ;Start of available RAM #endif #ifdef __16F84 #include "P16F84.INC" errorlevel -224 ;Suppress tris/option warnings StartR equ 0x0c ;Start of available RAM #endif list __fuses _CP_OFF&_WDT_OFF&_RC_OSC __idlocs h'0904' ;date code - finished 2009, mar20th ;as seen on 13th Colony Battlestar Galactica group on www.meetup.com #define LEDPORT PORTB #define BUTTON PORTA,4 #define freq 655000 #define LEDs 17 ;16 LEDs (+1 for looping back) ;****************************************************************************** ;RMB substitution from V5 to V8 code migration (TY RES solution, jun2011) rmb macro bytes org $ org $+bytes ;...next loc endm ;****************************************************************************** org StartR nxtLEDt rmb 1 ;next primary LED to light from 3 LED table LEDprtV rmb 4 ;port values for 3+1 LEDs temp rmb 2 ;temporary storage used by subroutines countB rmb 2 ;large loop of about 1000x4x17x2 dataOut rmb 2 ;data to transmit out Atris rmb 1 ;Current state of output PORTs Aport rmb 1 org 0 #ifdef __16F84 goto Reset goto Reset goto Reset goto Reset goto Reset #endif ;****************************************************************************** ;4 LED Table, this table lists 4 LEDs in sequence from the 16 LED 4x4 matrix. ;enter: w=LED.table.position ;exit: w=matrix.tris.value required to light this LED ;time: 4cycles LED4tbl addwf PCL,f ;get Table Value based on entry with W register Delay4 retlw 0 ;delay 4 cycles {call=2, retlw=2}, note: Wreg=0 dt b'11100111',b'11010111',b'10110111',b'01110111' dt b'11101011',b'11011011',b'10111011',b'01111011' dt b'11101101',b'11011101',b'10111101',b'01111101' dt b'11101110',b'11011110',b'10111110' dt b'01111110',0xff,b'01111110' dt b'10111110',b'11011110',b'11101110' dt b'01111101',b'10111101',b'11011101',b'11101101' dt b'01111011',b'10111011',b'11011011',b'11101011' dt b'01110111',b'10110111',b'11010111',b'11100111',0xff LED4end equ $ dt 0xff,0xff ;****************************************************************************** Delay22 goto $+1 ;2,total delay is 22 cycles (include call/retn) goto $+1 ;2 goto $+1 ;2 goto $+1 ;2 goto $+1 ;2 Delay10 goto $+1 ;2 goto $+1 ;2 Delay6 goto Delay4 ;delay 6 cycles {call,goto,retlw}, note: Wreg=0 ;****************************************************************************** ;{10,4,2}cycles x (loops for 2 seconds) ;{ ;LED routine to use less program space while repeatedly showing LEDs total 75x ;enter: LEDprtV[0..2]=port values for LED output,countr ;exit: w=0 ;calls: Delay4,Delay6,Delay10 ;time: 4096cycles+2154cycles=6250cycles ;values located in LEDprtV[0,1,2] ;do this for 2/3. Loop for 1/34*2=2seconds={10,4,2}=freq/4/16/256*2/17/2 * 2/3 LEDrtn movlw freq/24576/LEDs+1 ;1,1/34 and 2/3rd of 2 seconds movwf temp ;1,time=2seconds movlw (freq/96/LEDs & 0xff)+1 ;1,1/34 of 2 seconds movwf temp+1 ;1, LEDrtn1 btfss BUTTON ;1,"fancy" or "simple" LED display goto LEDrtn2 ;2,go do "fancy" LED version goto $+1 ;2,delay, "simple" 1 LED version goto LEDrtn3 ;2,done LEDrtn2 movfw LEDprtV+2 ;1,output LEDPORT=LEDprtV[2] tris LEDPORT ;1, movfw LEDprtV+1 ;1,output LEDPORT=LEDprtV[1] tris LEDPORT ;1, LEDrtn3 movfw LEDprtV+0 ;1,output LEDPORT=LEDprtV[0] (brightest) goto $+1 ;2,delay tris LEDPORT ;1, goto $+1 ;2,delay decfsz temp+1,f ;1,looped 256 times? goto LEDrtn1 ;2,not yet, do more decfsz temp,f ;1,looked long enough? goto LEDrtn1 ;2,not yet, do more ;---------------------------------------------------------------------- ;move next LED pointer to next LED to display movfw LEDprtV+2 ;1,output LEDPORT=LEDprtV[2] tris LEDPORT ;1, movfw LEDprtV+1 ;1,output LEDPORT=LEDprtV[1] tris LEDPORT ;1, movfw LEDprtV+0 ;1,output LEDPORT=LEDprtV[0] goto $+1 ;2, tris LEDPORT ;1, decfsz nxtLEDt,w ;1,point to next LED to glow goto LEDrtn4 ;2,do the opposite of decsz movlw LEDs*2 ;1,if reached end, loop to beginning LEDrtn4 movwf nxtLEDt ;1,update pointer to next LED in table movfw LEDprtV+2 ;1,move LEDs down array movwf LEDprtV+3 ;1 movfw LEDprtV+1 ;1 movwf LEDprtV+2 ;1 movfw LEDprtV+0 ;1 movwf LEDprtV+1 ;1 ;---------------------------------------------------------------------- ;get next LEDprtV[0] value to display movfw LEDprtV+3 ;1,output LEDPORT=LEDprtV[2] tris LEDPORT ;1, movfw LEDprtV+2 ;1,output LEDPORT=LEDprtV[1] tris LEDPORT ;1, movlw freq/49152/LEDs+1 ;1,1/34 and 1/3rd of 2 seconds movwf temp ;1,time=2seconds movfw LEDprtV+1 ;1,output LEDPORT=LEDprtV[0] tris LEDPORT ;1, movlw (freq/192/LEDs & 0xff)+1 ;1,1/34 of 2 seconds movwf temp+1 ;1, movfw nxtLEDt ;1,prepare to collect next new location call LED4tbl ;6,go get next table location movwf LEDprtV+0 ;1,hold new value in LEDprtV[0] ;---------------------------------------------------------------------- ;display 4 LEDs since we are moving to next LED {5,6,3,2} LEDrtn5 movfw LEDprtV+3 ;1,output LEDPORT=LEDprtV[2old] tris LEDPORT ;1, movfw LEDprtV+2 ;1,output LEDPORT=LEDprtV[1old] tris LEDPORT ;1, movfw LEDprtV+1 ;1,output LEDPORT=LEDprtV[0old] nop ;1, tris LEDPORT ;1, goto $+1 ;2, goto $+1 ;2, movfw LEDprtV+0 ;1,output LEDPORT=LEDprtV[0new] tris LEDPORT ;1, decfsz temp+1,f ;1,looped enough? goto LEDrtn5 ;2,not yet, do more decfsz temp,f ;1, goto LEDrtn5 ;2,not yet, do more ;---------------------------------------------------------------------- ;done, exit routine while displaying LEDs movfw LEDprtV+2 ;1,output LEDPORT=LEDprtV[2] tris LEDPORT ;1, movfw LEDprtV+1 ;1,output LEDPORT=LEDprtV[1] tris LEDPORT ;1, movfw LEDprtV+0 ;1,output LEDPORT=LEDprtV[0] goto $+1 ;2, tris LEDPORT ;1, goto Delay10 ;10,done ;****************************************************************************** ;look in a given direction for 2 seconds {2,13,2}cycles = freq/4/17/256*2 LEDlk movlw freq/512/LEDs+1 ;1,look in directionX for 2 seconds movwf temp ;1,time=2seconds clrf temp+1 ;1, LEDlk1 btfss BUTTON ;1,"fancy" or "simple" LED display goto LEDlk3 ;2,go do "fancy" LED version goto $+1 ;2,do "simple" 1 LED version goto LEDlk4 ;2,go reload 1 LED LEDlk3 movfw LEDprtV+0 ;1,output LEDPORT=LEDprtV[0] tris LEDPORT ;1, movfw LEDprtV+2 ;1,output LEDPORT=LEDprtV[2] tris LEDPORT ;1, LEDlk4 movfw LEDprtV+1 ;1,output LEDPORT=LEDprtV[1] (brightest) tris LEDPORT ;1, call Delay4 ;4,delay nop ;1,delay decfsz temp+1,f ;1,looped 256 times? goto LEDlk1 ;2,not yet, do more decfsz temp,f ;1,looked long enough? goto LEDlk1 ;2,not yet, do more retlw 0 ;done, continue ;****************************************************************************** Reset movlw b'00001111' ;set options register option movlw 0 ;Start with all ports as outputs low movwf PORTA ;reset needed for 18 pin 16c54 type chip movwf Aport movlw b'00010000' ;{a3..a0}=N/A, a4=BUTTON=input_N/A tris PORTA movwf Atris movlw b'11111111' ;{b7..b0}=set all LEDs start as off tris PORTB movlw b'00001111' ;direction 4pins=+0V ---> 4pins=+5V movwf PORTB ;---------------------------------------------------------------------- movlw LEDs/2 ;init to point at middle LED to begin glowing movwf nxtLEDt call LED4tbl ;init LEDprtV[0,1,2] before calling routine movwf LEDprtV+0 movlw LEDs/2+1 call LED4tbl movwf LEDprtV+1 movlw LEDs/2+2 call LED4tbl movwf LEDprtV+2 ;---------------------------------------------------------------------- movlw (50*LEDs*2/256)+1 ;loop 100 cycles for the 1st time movwf countB ;approx 2x100 seconds or 1.4 minutes movlw ((50*LEDs*2) & 0xff)+1 movwf countB+1 goto main1 ;------------------------------------------------------------------------------ ;main loop does everything here as a 'state machine' to keep correct timing main movlw (1000*LEDs*2/256)+1 ;loop 1000 cycles movwf countB movlw ((1000*LEDs*2) & 0xff)+1 movwf countB+1 ;---------------------------------------------------------------------- main1 call LEDrtn ;24,glow 3 LEDs ;---------------------------------------------------------------------- ;need to loop while also maintaining synchronized glow pattern decfsz countB+1,f ;done yet? goto main1 ;not yet decfsz countB,f goto main1 ;not yet call LEDlk ;look in directionX for 2 seconds goto main ;reset and do it again ;****************************************************************************** dt "Copyright Jose Da Silva 2009mar20 Vancouver BC" ;****************************************************************************** #ifdef __16C54 org 1FFh goto Reset ;program starts here on reset #endif end |
This circuit is designed to run on a basic pic16c54 type chip, but should be easy to transfer to another PIC chip if you have that instead (this example shows the 14bit PIC 16f84 as an example substitute).
The LED matrix runs from one 8 bit port in a 4x4 configuration, PORTB - 4pins[0..3] are set positive, 4pins[4..7] are set negative.
The original code used RES to reserve RAM locations which works fine with older MPLAB compilers, but new MPLAB compilers don't like RES. You will notice the RMB macro substitution (I haven't found the original source of the RMB macro, but one URL credits Tony Yates - therefore... thanks for the RES replacement - it works as a good substitute).
The LED4tbl table is a list of TRIS outputs to enable one of the 16 LEDs at a time in one direction, then in the other. Delay4 is oddly located in the table, to make it so that we can start the table from [1] instead of [0].
LEDrtn does the work of lighting 3 LEDs and moving to the next LED. The LEDs are pulsed in the ratio of 10/4/2 to give an appearance of a fading-tail as the LEDs scan side to side. The majority of time is spent in this routine. Although this circuit runs at a leisurely 650kHz using an RC oscillator (12k and 100pF), it is still fast enough to rely on persistence of vision so that you do not see the LEDs flicker.
LEDlk does the work of staring in a given direction for 2 seconds while pulsing the LEDs in the ratio of 2/13/2 to give a tapered effect to the sides of the centre LED.
The main program loops repeatedly forever, but every 1000's cycle, does a stop-and-stare for about 2 seconds.
Here's a bit of trivia for anyone who has watched the new re-imaged BSG: Assuming it takes one second to scan left and one second to scan right, and do this 1000 times, the time taken is 2000 seconds, which is approximately 33 minutes. ...then again, maybe it's just a coincidence for one of the episodes to be called 33. |
CIRCUIT COMPONENTS AND HARDWARE
The circuit was built on a perf board. Resistors for the LEDs are 220 ohm. Runs at 4.5v based on 3 batteries.
![]() ![]() |
If you find this code (or sections of this code) useful for yourself, or a project, I will appreciate a little credit for providing it here for your use/project (for example, in your source code comments, or even a web link back to this web page is great if you have a project that uses it that you want to show/demonstrate). Thanks.
Other PIC Related Pages On This Web Site | ||||
---|---|---|---|---|
Home Page | A/B Long Term Timer | ASCII To MorseCode | Clear RAM Macro | Delay Macro |
Random Number Generator (RNG) | 7.96Hz Sinewave Generator | Software RS232 | Table Array FSR Macro | PicDis Disassembler |