Subject:
As promised, my ugly code
From:
David Willmore ####@####.####
Date:
19 Mar 2004 05:30:16 +0000
Message-Id: <200403190530.i2J5U7sU031746@localhost.localdomain>
Let's just see if this list accepts this as an attachment.
If not, email me directly and I'll ship you off a copy
of the code. Let's just take it as read that the code
is under the GPL.
Keep in mind, this is the *first* spin of the code. I've
made no effort to make it compact nor clever. FYI, NJQRP
is the New Jersey low power amateur radio club and the
Packrats are a VHF/UHF/microwave contesting radio club
in NJ/PA (around Trenton,NJ).
The display is an extension of an idea from a Microchip
application note for low pin count micros. They show
how to drive N^2-N LEDs with N signal lines (by setting
them to +/-/float in clever combinations. It's an 8x8
grid of LEDs with the diagonal missing (can't drive both
the anode and cathode of a diode with the same signal
and expect it to do anything). Then you take one half
(trianle) and move it up and over one to make it a nice
grid that's 7 wide and 8 high. For a 4x4:
a b c d
e f g h
i j k l
m n o p
Remove the diagonal:
b c d
e g h
i j l
m n o
And shift the parts back together:
b c d
e g h
i j l
m n o
An 8x8 grid (8x7) is left as an exercise for the student--
who had better be patient and good with a soldering iron.
The display looks pretty cool. :)
Cheers,
David
processor p16f628
include p16f628.inc
include test.def
radix dec
__CONFIG _BODEN_OFF & _CP_OFF & _DATA_CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _MCLRE_OFF & _INTRC_OSC_NOCLKOUT
globals EQU 0x70 ; a 'name' to use for the global variable bank
irq_vars EQU 0xA0 ; same thing for the interupt routine vars
common_vars EQU 0x20 ; and for the run of the mill vars
cblock 0x70 ; globals
W_tmp ; temporary storage for W register in interupt
endc
cblock 0xA0 ; interupt temporary variables
STATUS_tmp ; STATUS temp
FSR_tmp ; FSR temp
IRQ_timer ; timer for body to interupt connunications
led_counter ; counter for value to display on LEDs
tmp_offset ; temporary offset for display calculations
display_buffer:8 ; storage buffer for display
display_tris:8 ; storage buffer for tris data
endc
cblock 0x20 ; variables in bank 0
PCL_tmp ; temporary variable for table lookups
msg_offset ; offset into message for display
offset ; temporary value for calculations
loop_tmp ; loop counter
F_tmp ; '1's for the diagonal
tmp ; just a normal temporary variable
in_p ; input pointer
out_p ; output pointer
disp_in:7 ; bytes to shuffle into display
disp_out:8 ; data to go to display
endc
;constants
num_rows EQU 0x08 ; number of rows in the display
wait_count EQU -0x40 ; how many interupts to count between pixel scrolls
VARIABLE message_len=(message_end - data_table) ; well, how long *is* it?
org 0x0
goto startup
org 0x4
interupt:
movwf W_tmp ; save off W register
swapf STATUS,w ; grab off status register swapping nibbles
BANKSEL irq_vars ; set the bank to the interupt variables
movwf STATUS_tmp ; save off nibble swapped status
movf FSR,w ; load in FSR
movwf FSR_tmp ; save off in temp register
decf led_counter,w ; load in the counter - 1
addlw display_buffer ; offset pointer into buffer
movwf FSR ; set FSR to point to buffer
BANKSEL TRISB ; set bank to TRISB
movlw 0xff
movwf TRISB ; set to inputs
movf INDF,w ; load in the buffer data
BANKSEL PORTB ; point to port B register
movwf PORTB ; set outputs
movlw 0x08 ; offset from port buffer to tris buffer
addwf FSR ; move the FSR
BANKSEL TRISB ; point back to the TRISB bank
movf INDF,w ; load the tris data
movwf TRISB ; store tris data
BANKSEL irq_vars ; back to the variables
decfsz led_counter,w ; decrement and skip if zero
goto interupt_bail ; get out
movlw num_rows ; load in the number of rows
interupt_bail:
movwf led_counter ; write back the counter
incfsz IRQ_timer,w ; increment counter and lock at 0xff
movwf IRQ_timer ; write back incremented value
BANKSEL INTCON
bcf INTCON,T0IF ; clear timer0 interupt pending bit
; restore program context
BANKSEL irq_vars
movf FSR_tmp,w ; load in FSR save value
movwf FSR ; save it back
swapf STATUS_tmp,w ; swap nibbles of saved STATUS and save into w
movwf STATUS ; move w into STATUS register
swapf W_tmp,f ; swap nibbles in W_tmp
swapf W_tmp,w ; swap nibbles in W_tmp and save into w
retfie
startup:
BANKSEL CMCON
movlw b'00000111' ; disable comparators and set inputs to digital mode
movwf CMCON
BANKSEL VRCON
movlw b'00000000' ; clear out the voltage reference unit
movwf VRCON
BANKSEL OPTION_REG
movlw b'11000010' ; setup TIMR0
movwf OPTION_REG
BANKSEL led_counter
movlw num_rows
movwf led_counter
BANKSEL TRISA ;
clrf TRISA ; all PORTA to output
BANKSEL irq_vars
movlw b'10000000'
movwf display_buffer
movlw b'01000000'
movwf display_buffer+0x01
movlw b'00100000'
movwf display_buffer+0x02
movlw b'00010000'
movwf display_buffer+0x03
movlw b'00001000'
movwf display_buffer+0x04
movlw b'00000100'
movwf display_buffer+0x05
movlw b'00000010'
movwf display_buffer+0x06
movlw b'00000001'
movwf display_buffer+0x07
movlw b'00110111'
movwf display_tris+0x00
movlw b'10010111'
movwf display_tris+0x01
movlw b'11000111'
movwf display_tris+0x02
movlw b'11100111'
movwf display_tris+0x03
movlw b'11100011'
movwf display_tris+0x04
movlw b'11101001'
movwf display_tris+0x05
movlw b'11101100'
movwf display_tris+0x06
movlw b'00000000'
movwf display_tris+0x07
BANKSEL INTCON
movlw b'10100000' ; setup interupts for TIMR0
movwf INTCON
; goto $-1 ; loop forever
main:
BANKSEL msg_offset ;
clrf msg_offset ; start at the beginning
top:
movlw wait_count ; start counter before we get to work
BANKSEL irq_vars ; set to the right bank
movwf IRQ_timer ;
BANKSEL common_vars ; look at the normal stuff again
clrf F_tmp ; get some zero bits
comf F_tmp ; set'em all!
movf msg_offset,w ; start at msg_offset
movwf offset ; store it off
movlw 0x7 ; bytes to grab from message
movwf loop_tmp ; stuff them in the loop counter
movlw disp_in ; point the indirect register at the disp_in buffer
movwf FSR ;
read_top:
movf offset,w ; get offset
call data_lookup ; get the data
movwf INDF ; save it off in disp_in buffer
incf FSR,f ; point to next byte in disp_in buffer
incf offset,f ; point to next index in message table
movf offset,w ; read it in
sublw message_len ; are we ready to wrap?
btfsc STATUS,Z ; skip if we're !=
clrf offset ; wrap to zero
decfsz loop_tmp,f ; we done?
goto read_top ; nope, go back and do it again.
disp_shuffle:
; loop_tmp is already zero because of read loop (exit condition)
movlw disp_out ; set output pointer to disp_out
movwf out_p ;
movlw 0x8 ; 8 bytes to output
movwf offset ; just a comparison for the diaginal construction
disp_byte:
movlw disp_in ; set input pointer to disp_in
movwf in_p ;
movlw 0x8 ; 8 bits in a byte
movwf loop_tmp ; set counter for 'bits left'
disp_bit:
movf offset,w ; load in the offset
subwf loop_tmp,w ; subtract off the current bit counter
btfss STATUS,Z ; skip if equal
movf in_p,w ; point at disp_in
btfsc STATUS,Z ; skip if not equal
movlw F_tmp ; point at 1 bits
movwf FSR ; set pointer
rlf INDF,f ; get a bit
movf out_p,w ; point to disp_out
movwf FSR ;
rlf INDF,f ; put it in the output buffer
movf offset,w ; load in the offset
subwf loop_tmp,w ; subtract off the current bit counter
btfss STATUS,Z ; skip if equal
incf in_p,f ; set pointer to next input byte
decfsz loop_tmp,f ; take one down...
goto disp_bit ; pass it around...
incf out_p,f ; set pointer to next output byte
decfsz offset,f ; for diagonal calculation
goto disp_byte ; more to do
movlw 0x8 ; 8 output bytes to copy/invert
movwf loop_tmp ; set the loop conter
movlw disp_out ; point in_p to disp_out
movwf in_p ;
movlw display_tris ; point out_p to display_tris
movwf out_p ;
copy_invert:
movf in_p,w ; point INDF to input byte
movwf FSR ;
comf INDF,w ; invert and load
movwf tmp ; save it in the temp var
movf out_p,w ; point INDF to output byte
movwf FSR ;
movf tmp,w ; load it back
movwf INDF ; store it in output
incf in_p,f ; advance pointer
incf out_p,f ; advance pointer
decfsz loop_tmp,f ; loop test
goto copy_invert ; do the next byte
BANKSEL irq_vars ; look at irq variables
disp_wait:
incfsz IRQ_timer,w ; are we ready to do the next one?
goto disp_wait ; busy wait
BANKSEL common_vars ; back to reality
comf PORTA ; toggle bits in port A
incf msg_offset,f ; increment point to start of message
movf msg_offset,w ; load it in
sublw message_len ; are we ready to wrap?
btfsc STATUS,Z ; skip if we're !=
goto main ; start all over
goto top ; around and around we go
data_lookup:
movwf PCL_tmp
movlw LOW data_table ; load in the low byte of the table data start address
addwf PCL_tmp,f
movlw HIGH data_table ; load in the high byte of the table data start address
btfsc STATUS,C ; skip if carry clear
addlw 1 ; stuff in the carry bit
movwf PCLATH ; stick it in the high byte PC latch
movf PCL_tmp,w ; load in the PCL value
movwf PCL ; jump
data_table:
message_data: ; "Welcome to the Packrats!!"
; Char 1 'W'
retlw b'01111110'
retlw b'10000000'
retlw b'01111000'
retlw b'10000000'
retlw b'01111110'
retlw b'00000000'
; Char 1 'e'
retlw b'01110000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'00010000'
retlw b'00000000'
; Char 1 'l'
retlw b'10000010'
retlw b'11111110'
retlw b'10000000'
retlw b'00000000'
; Char 27 'c'
retlw b'01110000'
retlw b'10001000'
retlw b'10001000'
retlw b'10011000'
retlw b'00000000'
; Char 28 'o'
retlw b'01110000'
retlw b'10001000'
retlw b'10001000'
retlw b'10001000'
retlw b'01110000'
retlw b'00000000'
; Char 1 'm'
retlw b'11111000'
retlw b'00001000'
retlw b'11110000'
retlw b'00001000'
retlw b'11110000'
retlw b'00000000'
; Char 1 'e'
retlw b'01110000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'00010000'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 't'
retlw b'00001000'
retlw b'01111100'
retlw b'10001000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'o'
retlw b'01110000'
retlw b'10001000'
retlw b'10001000'
retlw b'10001000'
retlw b'01110000'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 't'
retlw b'00001000'
retlw b'01111100'
retlw b'10001000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'h'
retlw b'11111100'
retlw b'00010000'
retlw b'00010000'
retlw b'11100000'
retlw b'00000000'
; Char 1 'e'
retlw b'01110000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'00010000'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'P'
retlw b'10000010'
retlw b'11111110'
retlw b'10010010'
retlw b'00010010'
retlw b'00001100'
retlw b'00000000'
retlw b'00000000'
; Char 1 'a'
retlw b'01000000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'11110000'
retlw b'00000000'
; Char 1 'c'
retlw b'01110000'
retlw b'10001000'
retlw b'10001000'
retlw b'10011000'
retlw b'00000000'
; Char 1 'k'
retlw b'11111110'
retlw b'00100000'
retlw b'01010000'
retlw b'10001000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'r'
retlw b'10001000'
retlw b'11110000'
retlw b'10001000'
retlw b'00001000'
retlw b'00000000'
; Char 1 'a'
retlw b'01000000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'11110000'
retlw b'00000000'
; Char 1 't'
retlw b'00001000'
retlw b'01111100'
retlw b'10001000'
retlw b'00000000'
; Char 1 's'
retlw b'10010000'
retlw b'10101000'
retlw b'10101000'
retlw b'01001000'
retlw b'00000000'
; Char 1 '!'
retlw b'00000000'
retlw b'10111110'
retlw b'00000000'
retlw b'00000000'
retlw b'10111110'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
message_end:
; Char 1 'W'
retlw b'01111110'
retlw b'10000000'
retlw b'01111000'
retlw b'10000000'
retlw b'01111110'
retlw b'00000000'
; Char 1 'e'
retlw b'01110000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'00010000'
retlw b'00000000'
; Char 1 'l'
retlw b'10000010'
retlw b'11111110'
retlw b'10000000'
retlw b'00000000'
; Char 27 'c'
retlw b'01110000'
retlw b'10001000'
retlw b'10001000'
retlw b'10011000'
retlw b'00000000'
; Char 28 'o'
retlw b'01110000'
retlw b'10001000'
retlw b'10001000'
retlw b'10001000'
retlw b'01110000'
retlw b'00000000'
; Char 1 'm'
retlw b'11111000'
retlw b'00001000'
retlw b'11110000'
retlw b'00001000'
retlw b'11110000'
retlw b'00000000'
; Char 1 'e'
retlw b'01110000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'00010000'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 't'
retlw b'00001000'
retlw b'01111100'
retlw b'10001000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'o'
retlw b'01110000'
retlw b'10001000'
retlw b'10001000'
retlw b'10001000'
retlw b'01110000'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 't'
retlw b'00001000'
retlw b'01111100'
retlw b'10001000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'h'
retlw b'11111100'
retlw b'00010000'
retlw b'00010000'
retlw b'11100000'
retlw b'00000000'
; Char 1 'e'
retlw b'01110000'
retlw b'10101000'
retlw b'10101000'
retlw b'10101000'
retlw b'00010000'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'N'
retlw b'11111110'
retlw b'00000110'
retlw b'00011000'
retlw b'01100000'
retlw b'11111110'
retlw b'00000000'
retlw b'00000000'
; Char 1 'J'
retlw b'01100000'
retlw b'10000000'
retlw b'10000000'
retlw b'10000010'
retlw b'01111110'
retlw b'00000010'
retlw b'00000000'
retlw b'00000000'
; Char 1 'Q'
retlw b'00111000'
retlw b'01000100'
retlw b'10000010'
retlw b'10100010'
retlw b'01000100'
retlw b'10111000'
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'R'
retlw b'10000010'
retlw b'11111110'
retlw b'00010010'
retlw b'00110010'
retlw b'11001100'
retlw b'10000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 'P'
retlw b'10000010'
retlw b'11111110'
retlw b'10010010'
retlw b'00010010'
retlw b'00001100'
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
; Char 1 '!'
; Char 1 '!'
retlw b'00000000'
retlw b'10111110'
retlw b'00000000'
retlw b'00000000'
retlw b'10111110'
retlw b'00000000'
; Char 1 ' '
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
retlw b'00000000'
end