Appendix 1: Code Listing

;***EE 476 FINAL PROJECT*****
;***DIGITAL OSCILLOSCOPE*****
;James Blanchette & Rahul Mukerjee

.include "c:\avrtools\appnotes\8535def.inc"


.def AnaLo =r25 ;holds low byte of ADC conversion value
.def AnaHi =r26 ;holds high byte of ADC conversion value
.def loop =r27 ;counter to see if we've done all the samples

.def set_time =r13 ;track to see if we've gone past all possible time/divs

.def temp2 =r22 ;second temp register for misc. calculations
.def isrdone =r24 ;register keeping track of when sampling is done
.def vrmshi =r9 ;holds high byte of the average voltage value
.def vrmslo =r14 ;holds low byte of the average voltage value
.def save =r1 ;used for saving the status register during ISR
.def isrcount=r2 ;counter in ISR for tracking number of samples taken
.def YLo =r3 ;holds low byte of y position during screen conversion
.def YHi =r4 ;holds high byte of y position during screen conversion
.def vrmsmed =r5
.def minL =r6 ;temp storage for (low) minimum voltage
.def minH =r7 ;temp storage for (high) minimum voltage
.def maxL =r8 ;temp storage for (low) maximum voltage
.def maxH =r12 ;temp storage for (high) maximum voltage

.def key =r16 ;encoding for the button pressed on the keypad
.def state =r20 ;current state of the debouncer
.def press =r19 ;hold raw press value
.def butnum =r18 ;final press value
.def time1 =r17 ;counts till 30 ms interrupt
.def temp =r21 ;temporary register


.def TXflash =r23 ;flag to check if string is in flash
.def TXbusy =r29 ;trans busy flag;note duplicate but pushed
.def RXchar =r28 ;received char

;;***** Subroutine Register Variables
;DIVIDE
.def d16s =r28 ;sign register
.def drem16sL =r9 ;remainder low byte 
.def drem16sH =r11 ;remainder high byte
.def drem16s3 =r10
.def dres16s2=r16 ;result middle byte
.def dres16s1=r18 ;result highest byte
.def dres16s3=r17 ;result lowest byte
.def dd16s2 =r16 ;dividend low byte
.def dd16s1 =r18 ;dividend high byte
.def dd16s3 =r17 ;dividend zero byte
.def dv16sL =r19 ;divisor low byte
.def dv16sH =r20 ;divisor high byte
.def dcnt16s =r31 ;loop counter



;Equates
.equ nopress=1 ;state when no button has been pressed
.equ maybe=2 ;detected a button once so far
.equ press=3 ;detected a button pressed at least twice in a row
.equ bounce=4 ;detected a button release once

.equ key0 =0b11101011 
.equ key1 =0b01110111
.equ key2 =0b01111011
.equ key3 =0b01111101 
.equ key4 =0b10110111
.equ key5 =0b10111011
.equ key6 =0b10111101
.equ key7 =0b11010111 
.equ key8 =0b11011011
.equ key9 =0b11011101
.equ keyA =0b01111110
.equ keyB =0b10111110
.equ keyC =0b11011110
.equ keyD =0b11101110
.equ keyILL =0xff ;no button (or multiple buttons) pressed on keypad

.equ baud96 =25 ;Specify constants for switches:
.equ azero ='0'
.equ maxtime =5
.equ mintime=0

.MACRO downer 
ldi ZH, high(xy)
ldi ZL, low(xy)
ldi temp, 27
st Z, temp
adiw ZL,1
ldi temp, '['
st Z,temp
adiw ZL,1
ldi temp, @0
st Z,temp
adiw ZL,1
ldi temp,59
st Z,temp
adiw ZL,1
ldi temp, @1
st Z,temp
adiw ZL,1
ldi temp,'H'
st Z,temp
adiw ZL,1
ldi temp,0x00
st Z,temp
.ENDMACRO

;macro that sets position on screen based on x and y coordinates
;and places cursor relative to the upper left-hand corner of the
;hyperterminal, (i.e. relative to (0,0))
;this macro takes parameters in registers
.MACRO bigdowner 
ldi ZH, high(xy)
ldi ZL, low(xy)
ldi temp, 27
st Z, temp
adiw ZL,1
ldi temp, '['
st Z,temp
adiw ZL,1
mov temp, @0
st Z,temp
adiw ZL,1
mov temp, @1
st Z,temp
adiw ZL,1
ldi temp,59
st Z,temp
adiw ZL,1
mov temp, @2
st Z,temp
adiw ZL,1
mov temp, @3
st Z,temp
adiw ZL,1
ldi temp,'H'
st Z,temp
adiw ZL,1
ldi temp,0x00
st Z,temp

.ENDMACRO


;macro that sets position on screen based on x and y coordinates
;and places cursor relative to the upper left-hand corner of the
;hyperterminal, (i.e. relative to (0,0))
;this macro takes in hard-coded values as opposed to values 
;already pre-defined in registers

.MACRO bigdowners 
ldi ZH, high(xy) ;store macro in text string
ldi ZL, low(xy) ;for the UART to understand
ldi temp, 27 ;27 is 'Esc'
st Z, temp 
adiw ZL,1
ldi temp, '['
st Z,temp
adiw ZL,1
ldi temp, @0
st Z,temp
adiw ZL,1
ldi temp, @1
st Z,temp
adiw ZL,1
ldi temp,59
st Z,temp
adiw ZL,1
ldi temp, @2
st Z,temp
adiw ZL,1
ldi temp, @3
st Z,temp
adiw ZL,1
ldi temp,'H'
st Z,temp
adiw ZL,1
ldi temp,0x00
st Z,temp

.ENDMACRO

;macro used to completely erase the hyperterminal window
.MACRO clearscreen
ldi ZH, high(clr)
ldi ZL, low(clr)
ldi temp, 27
st Z, temp
adiw ZL,1
ldi temp, '['
st Z,temp
adiw ZL,1
ldi temp,'2'
st Z,temp
adiw ZL,1
ldi temp,'J'
st Z,temp
adiw ZL,1
ldi temp,0x00
st Z,temp

.ENDMACRO
;*********************************************************
.dseg

;string of sampled wave generation samples 
samples: .byte 160 ;array storing our digital samples
xy: .byte 10 ;array storing xy coordinate string off macro
value: .byte 5 ;temp array for storage voltages after hex-to-ascii conv.
clr: .byte 5 ;array storing clr string off macro


;**********************************************************
.cseg
.org $0000
rjmp RESET
reti
reti
reti
reti
reti
rjmp TIMER1A
reti
reti
rjmp TIMER0
reti
rjmp RXdone
rjmp TXempty
rjmp TXdone
reti
reti
reti

;Here are the various characters and labels seen 
;on the screen; the "star" is what we use for our 
;voltage samples. The other labels are pretty
;self-explanatory.

star : .db "*",0x00
timediv : .db "Time/Div:", 0x00 
amp : .db "Vave:", 0x00
vpp : .db "Vpp:", 0x00 
dc: .db "DC off:",0x00
grid1: .db "|",0x00
grid2: .db "+",0x00
grid3: .db "-",0x00
mv: .db " mv",0x00

;time1 and time2 store the high and low byte, respectively
;of the sampling rate, which we use in our OCR1A compare match

time1: .db 0x9C,0x4E,0x1F,0x0F,0x00,0x00
time2: .db 0x40,0x20,0x40,0xA0,0xC8,0x50
time_labels:.db ".1 sec",0x00
.db " 50 ms",0x00
.db " 20 ms",0x00 
.db " 10 ms",0x00
.db " 5 ms",0x00
.db " 2 ms",0x00

RESET: ldi temp, low(RAMEND)
out SPL, temp
ldi temp, high(RAMEND)
out SPH, temp

;setup timer 1 for reset on compare match at full clock rate
ldi temp,0b00001000
out TCCR1B,temp
ldi temp, 0xf4 ;set the match A register to
out OCR1AH, temp ;62500 since 62500*16microsec=1sec
ldi temp, 0x24 ;62500 = 0xf424
out OCR1AL, temp
;setup timer 0 for overflow once every mSec
ldi temp, 3 ;prescale timer by 64
out TCCR0, temp
ldi temp,256-62 ;preload timer since
out TCNT0, temp ;62.5 x (64x.25) microSec = 1.0 mSec.


ldi temp, 0b00010001
out TIMSK, temp

;setup UART
ldi temp, 0b10111000
out UCR, temp

;set baud rate to 9600 baud
ldi temp, baud96
out UBRR, temp

clr TXbusy ;start our not busy on transmission
clr RXchar 


;initial conditions
ldi time1, 30 ;set time1 for 30 mSec
ldi state, nopress ;set initial state to nopress
clr temp
mov set_time,temp
clr press


;set up analog converter to read channel zero
ldi temp, 0
out ADMUX, temp


;set up PORTB for diagnostic LEDs
ldi temp,0b10101010 ;Turn on four LEDs
out PORTB,temp
ldi temp,0xFF ;Make port B pin all outputs
out DDRB,temp
ldi temp,0xFF ;Turn off all LEDs
out PORTB,temp

sei
rcall SET_TIME_INITIAL ;sets the initial time/div to 0.1 sec

;*************************** 
Sched: 
tst time1 ;test for first task ready
brne Sched ;if not then loop
rcall debounce

tskend: rjmp Sched


;*************************** 
debounce:
ldi time1, 30 ;reset for another 30 mSec
cpi state, nopress
breq _nopress
cpi state, maybe
breq _maybe
cpi state, press
breq _press
cpi state, bounce
breq _bounce
error: 
rjmp error


_nopress:
rcall keybd
cpi butnum, keyILL ;check if nothing is pressed
breq _nopressY
mov press, butnum
ldi state, maybe
_nopressY:
ret


_maybe: rcall keybd
mov temp,butnum
com temp
cp press, butnum
breq _maybeY
ldi state, nopress
ret 
_maybeY:rcall gotkey 
ldi state, press
ret 


_press: rcall keybd
cp press, butnum
breq _pressY
ldi state, bounce
_pressY:ret


_bounce:rcall keybd
cp press, butnum
breq _bounceY
ldi state, nopress
ret
_bounceY:
ldi state, press
ret


;*************************** 
GOTKEY: cpi press,0x0a
breq TAKE_SAMPLE ;ready to take a sample
cpi press,0x0c
breq SET_TIME_UP_NOW ;set time/div higher
cpi press,0x0d
breq SET_TIME_DOWN_NOW ;set time/div lower
GOTEND: ret 

SET_TIME_UP_NOW: 
rjmp SET_TIME_UP ;used because branch was too long


SET_TIME_DOWN_NOW:
rjmp SET_TIME_DOWN ;again branch jump was too long


TAKE_SAMPLE: 
clearscreen
clr vrmslo
clr vrmsmed


ldi ZL, low(clr) 
ldi ZH, high(clr) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait ;chill until done 

rcall DRAW_SCREEN
rcall set_time_initial
ldi ZL, low(samples)
ldi ZH, high(samples)

clr isrdone
ldi temp,80 ;set isrdone=0
mov isrcount,temp ;set isr count=80 

ldi temp,0x0b00111111 
mov minH,temp
mov minL,temp
clr maxH
clr maxL
;setup timer 1 for reset on compare match at full clock rate
ldi temp, 0b00001001
out TCCR1B, temp ;turn on timer1 isr

S_LOOP: ldi temp,1 ;loop until isrdone=1
cp isrdone,temp ;if temp equals isrdone, it means we're done sampling
brne S_LOOP ;so we jump out of the S-LOOP and turn off timer1a

ldi temp, 0b00001000 ;timer1a is off
out TCCR1B, temp 

ldi loop,1

rjmp S_START

S_EXIT: rcall OUT_VPP ;once finished sampling, we are ready to get the
rcall OUT_RMS ;peak-to-peak and average voltages of the waveform
;rcall OUT_DC
ret


S_START:cpi loop,79 ;here we check to see if the all samples have been
breq S_EXIT ;read out of our samples array
clr temp
cli


ldi ZL, low(samples) ;load the samples into Z; these samples are already
ldi ZH, high(samples) ;stored in memory after the ADC conversion
add ZL,loop
adc ZH,temp 
add ZL,loop
adc ZH,temp 
ld AnaHi,Z
adiw ZL,1
ld AnaLo,Z


inc loop 
push r9
push d16s ;due to duplicate usage of registers we decided 
push dres16s2 ;to push our divide routine registers noticing
push dres16s1 ;that they are only used here to format
push dres16s3 ;the screen to the correct voltage.
push dd16s2 
push dd16s1
push dd16s3
push dv16sL
push dv16sH
push dcnt16s
ldi dd16s1,0 
mov dd16s2,AnaHi
mov dd16s3,AnaLo

ldi dv16sL,200 ;divide by 200, based upon the number voltage
ldi dv16sH,0 ;divisions we could fit on the hyperterminal window

rcall div16s
mov temp, dres16s3
neg temp
subi temp,-20
pop d16s 
pop dres16s2 ;pop the divide registers once complete with division
pop dres16s1 
pop dres16s3
pop dd16s2
pop dd16s1
pop dd16s3
pop dv16sL
pop dv16sH
pop dcnt16s
pop r9

;cli

rcall CONVERT_SCREEN ;converts the screen to the right y-coordinates
mov YLo,AnaLo ;based on our "bigdowner" macro
mov YHi,AnaHi

mov temp,loop
rcall CONVERT_SCREEN ;converts the screen to the right x-coordinates


;now call "bigdowner" to place voltage sample at the proper position
bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r5, Z
out UDR, r5
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 


ldi ZL, LOW(star<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(star<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt

rcall TXwait ;chill until done 

rjmp S_START


SET_TIME_UP:

ldi temp,5
cp set_time,temp ;check to see if we can go to a lower
;time/division value
brne SET_UP_SKIP ;if so, we go display that value
ret

SET_UP_SKIP:
inc set_time
ldi ZL, low(time1<< 1) ;display current time/divison
ldi ZH, high(time1<< 1) ;based on the index provided by "set_time"
ldi temp,0
add ZL,set_time
adc ZH,temp
lpm
mov temp,r0 ;the index provided by "set_time" corresponds
out OCR1AH,temp ;to the address pointed to by Z, which is the
;compare-match value of the time/division
ldi ZL, low(time2<< 1)
ldi ZH, high(time2<< 1)
ldi temp,0
add ZL,set_time ;As a result, OCR1AH and OCR1AL get the 
adc ZH,temp ;the values stored in time2 and time1, respec.
lpm
mov temp,r0
out OCR1AL, temp

in temp,OCR1AL
com temp
out PORTB,temp

;note, here is an example where we hard-code in the position we want
bigdowners 0x32,0x34,0x31,0x31
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait ;chill until done 


ldi ZL, low(time_labels<< 1) ;routine to display the time_label
ldi ZH, high(time_labels<< 1) ;we chose from "SET_UP_SKIP"
mov temp,set_time
clc
rol temp
rol temp
rol temp
subi temp,1

clr temp2
add ZL,temp
adc ZH,temp2

lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait 


ret


SET_TIME_DOWN: ;this routine is similar to the
ldi temp,0 ;"SET_TIME_UP" routine mentioned above
cp set_time,temp ;refer to those comments for more detail
brne SET_UP_DOWN_SKIP ;essentially, here we do opposite by 
ret ;checking if there are any higher time/div vals.

SET_UP_DOWN_SKIP:
dec set_time
ldi ZL, low(time1<< 1) ;if higher time/div values, then display them
ldi ZH, high(time1<< 1)
ldi temp,0
add ZL,set_time
adc ZH,temp
lpm
mov temp,r0
out OCR1AH,temp

ldi ZL, low(time2<< 1)
ldi ZH, high(time2<< 1)
ldi temp,0
add ZL,set_time
adc ZH,temp
lpm
mov temp,r0
out OCR1AL, temp

com temp
out PORTB,temp


bigdowners 0x32,0x34,0x31,0x31
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait ;chill until done 


ldi ZL, low(time_labels<< 1) ;print selected time/div label
ldi ZH, high(time_labels<< 1) 
mov temp,set_time
clc
rol temp
rol temp
rol temp
cpi temp,0
breq Z_SKIP
subi temp,1

Z_SKIP: clr temp2
add ZL,temp
adc ZH,temp2

lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait 

ret

SET_TIME_INITIAL: ;rountine that hard codes in the label
;for .1 sec as a default time/div
ldi ZL, low(time1<< 1)
ldi ZH, high(time1<< 1)
ldi temp,0
add ZL,set_time
adc ZH,temp
lpm
mov temp,r0
out OCR1AH,temp

ldi ZL, low(time2<< 1)
ldi ZH, high(time2<< 1)
ldi temp,0
add ZL,set_time
adc ZH,temp
lpm
mov temp,r0
out OCR1AL, temp

bigdowners 0x32,0x34,0x31,0x31
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait ;chill until done 


ldi ZL, low(time_labels<< 1)
ldi ZH, high(time_labels<< 1) 
mov temp,set_time
clc
rol temp
rol temp
rol temp
cpi temp,0
breq M_SKIP
subi temp,1

M_SKIP: clr temp2
add ZL,temp
adc ZH,temp2

lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait 

ret

OUT_VPP:cli
mov AnaHi,maxH ;move values obtained in timer1 ISR
mov AnaLo,maxL

sub AnaLo,minL ;perform peak-to-peak calculation 
sbc AnaHi,minH ;based on max and min values



rcall hexascii ;do conversion from hexademical to ascii

;position of Vpp label
bigdowners 0x32,0x34,0x35,0x30
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0 
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done
cli 
;write out ascii value to designated position
ldi ZL, LOW(value) ;shifted becuase pgm memory is words 
ldi ZH, HIGH(value) 
ld r0,Z ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
clr TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
;write out "millivolt" label
cli
ldi ZL, LOW(mv<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(mv<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
ret

OUT_RMS:cli ;average voltage approximation
;done through a series of right-rotations,
clc ;(i.e. divisions,)
ror vrmshi 
ror vrmsmed
ror vrmslo

clc
ror vrmshi 
ror vrmsmed
ror vrmslo

clc
ror vrmshi 
ror vrmsmed
ror vrmslo

clc
ror vrmshi 
ror vrmsmed
ror vrmslo

clc
ror vrmshi 
ror vrmsmed
ror vrmslo

clc
ror vrmshi 
ror vrmsmed
ror vrmslo

mov AnaLo,vrmslo
mov AnaHi,vrmsmed

com vrmsmed
out PORTB,vrmsmed

rcall hexascii ;do conversion from hexademical to ascii

;again, this is the position of Vave on screen
bigdowners 0x32,0x34,0x33,0x32
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0 
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done
cli 
;obtain the appropriate ascii value from the value array
ldi ZL, LOW(value) ;shifted becuase pgm memory is words 
ldi ZH, HIGH(value) 
ld r0,Z ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
clr TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
;the millivolt label
cli
ldi ZL, LOW(mv<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(mv<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
ret

;Note that this commented out section was supposed to represent the
;DC-offset voltage. We wished to add it in the end as an extra 
;feature, but were unsuccessful to completely implement it, due to
;time,hence we left our attempt at this in the commented section below.
;OUT_DC: cli


; sub maxL,minL
; sbc maxH,minH
; mov AnaHi,maxH
; mov AnaLo,maxL


; rcall hexascii ;do conversion from hexademical to ascii

; bigdowners 0x32,0x34,0x37,0x31

; ldi ZL, low(xy)
; ldi ZH, high(xy) 
; ld r0, Z
; out UDR, r0 
; clr TXflash ;string is NOT in flash memory
; ser TXbusy ;and set the TX busy flag
; sbi UCR, UDRIE ;enable the TXempty interrupt
; sei
; rcall TXwait ;chill until done
; cli 
; ldi ZL, LOW(value) ;shifted becuase pgm memory is words 
; ldi ZH, HIGH(value) 
; ld r0,Z ;put the char in r0
; out UDR, r0 ;put the character in the UART buffer
; clr TXflash ;string is in flash memory
; ser TXbusy ;and set the TX busy flag
; sbi UCR, UDRIE ;enable the TXempty interrupt
; sei
; rcall TXwait ;chill until done 

; cli
; ldi ZL, LOW(mv<<1) ;shifted becuase pgm memory is words
; ldi ZH, HIGH(mv<<1) 
; lpm ;put the char in r0
; out UDR, r0 ;put the character in the UART buffer
; ser TXflash ;string is in flash memory
; ser TXbusy ;and set the TX busy flag
; sbi UCR, UDRIE ;enable the TXempty interrupt
; sei
; rcall TXwait ;chill until done 
; ret


;*************************** 
keybd: ldi temp, 0x0f ;set lower four lines to output
out DDRC, temp
ldi temp, 0xf0 ;and turn on the pullups on the inputs
out PORTC, temp
nop ;Need some time for the pullups to
nop ;charge the port pins
nop
nop
in temp, PINC ;read the high nibble
mov key, temp ;and store it (with zeros in the low nibble)


ldi temp, 0xf0 ;set upper four lines to outputs
out DDRC, temp
ldi temp, 0x0f ;and turn on pullups on the inputs
out PORTC, temp

nop ;As before wait for the pin to charge
nop 
nop
nop
in temp, PINC ;read the low nibble
or key, temp ;combine to make key code

;At the point the raw key code should have exactly one zero each in 
;the lower and upper nibbles. Any other number of zeros indicates
;either no-button pressed or multiple-button pressed.

;to avoid using Z (it is used by the timer1 interrupt) we do a series
;of comparisons instead of a table lookup

;testing stuff 


clr butnum
cpi key, key0
breq tbldone

inc butnum
cpi key, key1
breq tbldone

inc butnum
cpi key, key2
breq tbldone

inc butnum
cpi key, key3
breq tbldone

inc butnum
cpi key, key4
breq tbldone

inc butnum
cpi key, key5
breq tbldone

inc butnum
cpi key, key6
breq tbldone

inc butnum
cpi key, key7
breq tbldone

inc butnum
cpi key, key8
breq tbldone

inc butnum
cpi key, key9
breq tbldone

inc butnum
cpi key, keyA
breq tbldone

inc butnum
cpi key, keyB
breq tbldone

inc butnum
cpi key, keyC
breq tbldone

inc butnum
cpi key, keyD
breq tbldone
ldi butnum, keyILL

tbldone:ret
;********************************************************
CONVERT_SCREEN:
push temp2
ldi temp2,0
CONVERT_LOOP:
cpi temp,10 ;check if current position is less than ten
brlt CONVERT_DONE
subi temp,10
inc temp2
rjmp CONVERT_LOOP

CONVERT_DONE: subi temp,-0x30 ;conversion to ascii so it can be interpretted by
subi temp2,-0x30 ;UART for correct display to screen
mov AnaLo,temp
mov AnaHi,temp2 
pop temp2 
ret
;***************************************************************
;TIMER0 ISR
;Enters every 1.0 mSec

TIMER0:push temp
push save
in save, SREG
ldi temp,256-62 
out TCNT0, temp ; keeps clock ticking at 1 mSec 
tst time1
breq TIMEREXIT
dec time1


TIMEREXIT: 
out SREG, save
pop temp
pop save
reti ;back to backgound tasks


;*****************************************************

TIMER1A: 
;**** timer 1 compare A match 1/sec

in save, SREG
push temp

ldi temp, 0b11000101 ;start A to D conversion
out ADCSR, temp


ISRLOOP:in temp, ADCSR ;wait for A to D done
andi temp, 0b01000000 ;by checking ADSC bit
brne ISRLOOP ;this bit is cleared by the AtoD hardware
in AnaLo, ADCL ;read the voltage
in AnaHi, ADCH
lsl AnaLo ;shift to the left twice
rol AnaHi ;to multiply by four so
lsl AnaLo ;final hex value represents
rol AnaHi ;number in mV
mov temp,isrcount



cpi temp,75
brge ISR_J
cpi temp,11
brlt ISR_J

ldi temp,0
add vrmslo,AnaLo
adc vrmsmed,AnaHi
adc vrmshi,temp

cp maxL,AnaLo ;test to see whether or not
cpc maxH,AnaHi ;there is a new maximum or
brge MAX_SKIP ;new minimum sample
mov maxL,AnaLo
mov maxH,AnaHi
MAX_SKIP:
cp minL,AnaLo
cpc minH,AnaHi
brge MIN_SKIP
rjmp ISR_J
MIN_SKIP:mov minL,AnaLo
mov minH,AnaHi

ISR_J:
st Z, AnaHi ;store the high ADC value into Z
adiw ZL,1 ;increment the address by 1
st Z, AnaLo ;and store the low ADC value into Z
adiw ZL,1

dec isrcount
tst isrcount ;check to see if you have taken the
brne EXIT ;final sample
ldi temp,1 
mov isrdone,temp

EXIT: pop temp
out SREG, save
reti 

;**********************************************
div16s: clr d16s ;clear sign register
tst dd16s1 ;if dividend negative, set sign register
brge div_0
ser d16s
com dd16s1 ; change sign of dividend
com dd16s2 
subi dd16s2,low(-1)
sbci dd16s2,high(-1)


div_0: clr dd16s3 ;make 24-bit #

clr drem16sL ;sets remainder to 0
clr drem16sH

ldi dcnt16s, 0x18 ;sets counter at 24

div_1: clc

rol dres16s3 ;shift dividend left
rol dres16s2
rol dres16s1

rol drem16sL ;shift remainder left + carry in from dividend
rol drem16sH

sub drem16sL, dv16sL ;remainder = remainder - divisor
sbc drem16sH, dv16sH

brcc div_2 ;negative?
add drem16sL, dv16sL ; restore remaidner
adc drem16sH, dv16sH
rjmp div_3

div_2: ori dres16s3, 0x01 ;positive --> Q0 = 1

div_3: dec dcnt16s ;count--
brne div_1

tst d16s
brge div_end
com dres16s2 ; change sign of result
com dres16s3
subi dres16s3,low(-1)
sbci dres16s2,high(-1)


div_end: ret

;*****************************
;interrupt routines

; UART needs a character
TXempty:in save, SREG ;save processor status
tst TXflash ;Is the string in flash memory?
breq TXram ;If not, it is in RAM
inc ZL ;get the next char from flash 
lpm ;and put it in r0
rjmp TXfls
TXram: inc ZL ;get the next char from RAM
ld r0,Z
TXfls: tst r0 ;if char is zero then exit
breq TXend 
out UDR, r0 ;otherwise transmit it
rjmp TXexit ;exit until next char
TXend: clr TXbusy ;no more chars
cbi UCR, UDRIE ;clear the TXempty interrupt
TXexit: out SREG, save ;restore proc status
reti ;back to pgm

; TX done -- buffer is empty -- unused here
TXdone: in save, SREG ;save processor status
out SREG, save ;restore proc status
reti ;back to pgm

; UART read a character
RXdone: in save, SREG ;save processor status 
in RXchar, UDR ;get the character
out SREG, save ;restore proc status
reti ;back to pgm

;*****************************
;subroutine

TXwait: tst TXbusy ;now wait for the tranmission to finish
brne TXwait
ret

;********************************************************************************


;These next few routines draws the grid for the scope, so that voltage readings
;can be seen more clearly and accurately. The screen is drawn using the "grid"
;1,2,and 3 characters as listed in the labels at the beginning. The "FIRST_LINE"
;through to the "FIFTH_LINE" draw the horizontal grid lines and the "FIRST_VLINE"
;to the "NINTH_VLINE" draw the vertical grid lines, all at their respective positions. 

;Notice how in between reading grid lines onto the screen that we clear and set
;interrupts repeatedly, because without these cli's and sei's, other routines were
;apparently interrupting as the grid line was printed, which resulted in random
;junk being displayed, occasionally. The appropriate calls of cli and sei remedies
;this minor problem

DRAW_SCREEN: 

clr r5 ;used r5 because temp kept on getting changed
mov temp,r5
ldi temp2,0x30
mov YHi,temp2
ldi temp2,0x30
mov YLo,temp2

FIRST_LINE: 
cli
rcall CONVERT_SCREEN

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid3<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid3<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli

inc r5 ;increment until whole horizontal line is filled up
mov temp,r5
cpi temp,80
brne FIRST_LINE

;next line 
clr r5
mov temp,r5
ldi temp2,0x30
mov YHi,temp2
ldi temp2,0x35
mov YLo,temp2

SECOND_LINE:
cli
rcall CONVERT_SCREEN
bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid3<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid3<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli

inc r5
mov temp,r5
cpi temp,80
brne SECOND_LINE 

clr r5
mov temp,r5
ldi temp2,0x31
mov YHi,temp2
ldi temp2,0x30
mov YLo,temp2

THIRD_LINE:
cli
rcall CONVERT_SCREEN

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid3<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid3<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli

inc r5
mov temp,r5
cpi temp,80
brne THIRD_LINE


clr r5
mov temp,r5
ldi temp2,0x31
mov YHi,temp2
ldi temp2,0x35
mov YLo,temp2

FOURTH_LINE:
cli
rcall CONVERT_SCREEN

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid3<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid3<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
inc r5
mov temp,r5
cpi temp,80
brne FOURTH_LINE


clr r5
mov temp,r5
ldi temp2,0x32
mov YHi,temp2
ldi temp2,0x30
mov YLo,temp2

FIFTH_LINE:
cli
rcall CONVERT_SCREEN
bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid3<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid3<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
inc r5
mov temp,r5
cpi temp,80
brne FIFTH_LINE

;end of horizontal lines, now we're ready for the vertical lines

clr r6
mov temp,r6

FIRST_VLINE:
cli 
rcall CONVERT_SCREEN

mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x30
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne FIRST_VLINE


clr r6
mov temp,r6

SECOND_VLINE:
cli 
rcall CONVERT_SCREEN

mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x31
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2


bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne SECOND_VLINE


clr r6
mov temp,r6

THIRD_VLINE:
cli 
rcall CONVERT_SCREEN

mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x32
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2


bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne THIRD_VLINE

clr r6
mov temp,r6

FOURTH_VLINE:
cli
rcall CONVERT_SCREEN
mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x33
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2


bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne FOURTH_VLINE

clr r6
mov temp,r6

FIFTH_VLINE:
cli
rcall CONVERT_SCREEN

mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x34
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne FIFTH_VLINE

clr r6
mov temp,r6

SIXTH_VLINE:
cli
rcall CONVERT_SCREEN
mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x35
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli

ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne SIXTH_VLINE

clr r6
mov temp,r6
SEVENTH_VLINE:
cli
rcall CONVERT_SCREEN

mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x36
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne SEVENTH_VLINE

clr r6
mov temp,r6
EIGHTH_VLINE:
cli
rcall CONVERT_SCREEN

mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x37
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2

cli
bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne EIGHTH_VLINE

clr r6
mov temp,r6

NINTH_VLINE:
cli
rcall CONVERT_SCREEN

mov YHi,AnaHi
mov YLo,AnaLo
ldi temp2,0x38
mov AnaHi,temp2
ldi temp2,0x30
mov AnaLo,temp2

bigdowner YHi,YLo,AnaHi,AnaLo 
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid1<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid1<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
inc r6
mov temp,r6
cpi temp,20
brne NINTH_VLINE

;we're done printing the main grid; this next character is just used to show a
;crossbar, (a '+') in the middle of the grid

NEXT_LINE1:
cli
bigdowners 0x31,0x30,0x34,0x30
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

cli
ldi ZL, LOW(grid2<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(grid2<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli

;Time/Div label
bigdowners 0x32,0x34,0x30,0x30
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli

ldi ZL, LOW(timediv<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(timediv<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli

;Average voltage position
bigdowners 0x32,0x34,0x32,0x34
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli
;Average voltage label
ldi ZL, LOW(amp<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(amp<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli

;V Peak to Peak Label
bigdowners 0x32,0x34,0x34,0x34
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli

ldi ZL, LOW(vpp<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(vpp<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 


;DC-Offeset Label
bigdowners 0x32,0x34,0x36,0x32
ldi ZL, low(xy)
ldi ZH, high(xy) 
ld r0, Z
out UDR, r0
clr TXflash ;string is NOT in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 
cli

ldi ZL, LOW(DC<<1) ;shifted becuase pgm memory is words
ldi ZH, HIGH(DC<<1) 
lpm ;put the char in r0
out UDR, r0 ;put the character in the UART buffer
ser TXflash ;string is in flash memory
ser TXbusy ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
sei
rcall TXwait ;chill until done 

ret

hexascii:
push temp
clr temp ;use temp as our counter
ldi ZL, LOW(value) ;ptr to RAM
ldi ZH, HIGH(value)

loop1000:
cpi AnaHi,0x03 ;compare high byte to see if > or < 1000
brlo end1000 ;we're less than 3 so therefore less than 1000
breq testLo 
inc1000:
inc temp ;If >= 1000, add 1 to counter
subi AnaLo,0xe8 ;Subtract 1000 from Ana
sbci AnaHi,0x03
rjmp loop1000
testLo:
cpi AnaLo,0xe8 ;test low byte of Ana
brsh inc1000 

end1000:
subi temp,-48 ;convert decimal char to ascii and store
st Z, temp 
adiw ZL,1 
clr temp 

loop100:
cpi AnaHi,0 ;make sure the upper bits are clear
brne inc100 ;if AnaHi is non-zero, we want to increment temp 
cpi AnaLo,0x64 ;compare Low byte to see if > or < 100
brlo end100 

inc100:
inc temp ;If >= 100, add 1 to counter
subi AnaLo,0x64 ;Subtract 100 from Ana
sbci AnaHi,0x00
rjmp loop100

end100:
subi temp,-48 ;convert decimal char to ascii
st Z, temp ;store ascii value to ram
adiw ZL,1 ;increment the pointer
clr temp 

loop10:
cpi AnaLo,0x0a ;compare Low byte to see if > or < 10
brlo end10 ;we're less than 0x0a so therefore less than 10:
inc temp ;If >= 10, add 1 to counter
subi AnaLo,0x0a ;Subtract 10 from Ana
sbci AnaHi,0x00
rjmp loop10

end10:
subi temp,-48 ;convert decimal char to ascii
st Z, temp 
adiw ZL,1 
clr temp 
subi AnaLo,-48 ;Convert the 1's digit to ASCII
st Z,AnaLo ;Store it in the string
adiw ZL,1
clr temp ;NULL terminate the string
st Z,temp
pop temp
ret

;END OF CODE

Main