Sådär nu har jag rotat runt lite i koden igen.
Vad det gället att spara undan register på stacken har jag en fundering. Det finns väl inget som hindrar att man skapar två subrutiner, en för att spara ut på stacken och en för att hämta från stacken? Dessa anropar man sedan först i rutinen, respektive precis innan RETI. Skulle underlätta en del om man gör så. Har interuptrutiner som kan sluta på flera ställen och skulle man vilja ändra vilka register man sparar undan så kan man lätt missa på något ställe. Får prova helt enkelt.
Nu har det uppstått en annan fråga. Det gäller programmets presentation på RS232. När jag skrev ihop de bitar som skickar ut text via seriedata så läste jag ett exempel och använde det mer eller mindre rakt av. Därför uppstår nu en lite fråga kring följande
Passar återigen på att rikta ett stort tack till alla som tar sig tid att komma med förslag, ideér, synpunkter, osv. Det är helt ovärderligt. TACK!
Kod: Markera allt
.include "m88def.inc"
; 8 MHz external chrystal
.org 0x000
rjmp Reset ; Reser Vector
.org INT0addr ; Interuptvector external INT0
rjmp startcalib
.org OC1Aaddr ; Interuptvektor timer 1 match A
rjmp timer1
;--------------------------
; initialise Stack Pointer
;--------------------------
reset:
ldi r16, low(RAMEND)
out SPL, r16
ldi r16, high(RAMEND)
out SPH, r16
;--------------------------
; Set definitions
;--------------------------
.def data = r0 ; Used when Data is read from Flash
.def calibtime = r14 ; Counts down calibration time > 0 means calibration running
.def switch = r15 ; CPS switchpoint
.def temp = r16 ; Temp
.def temp2 = r17 ; Temp
.def cps = r18 ; Counts per second
.def avg = r19 ; Avrage counts per second over 8 seconds
.def hex = r20 ; hex value to convert to ascii (could be substiuted for temp)
.def dig1 = r21 ; Digit 1 of ascii value
.def dig2 = r22 ; Digit 2 of ascii value
.def dig3 = r23 ; Digit 3 of ascii value
.def sum = r24 ; The sum of all numbers in buffer. Used to calculate avrage
.equ buff_length = 8 ; Length of buffer
;--------------------------
; Set buffer pointers and zero buffer
;--------------------------
ldi XH, high(avg_buffer) ; Set buffer pointers
ldi XL, low(avg_buffer)
ldi temp, 0 ; Set temp to Zero
zero_buffer:
st X+, temp ; Load 0 into buffer and increase pointer
cpi XL, buff_length ; Check if buffer end
brne zero_buffer ; Repeat if not end
ldi XH, high(avg_buffer) ; Set buffer pointers
ldi XL, low(avg_buffer)
ldi sum, 0 ; Set sum to zero
;--------------------------
; USART init
;--------------------------
;set baudrate
ldi temp, (0<<U2X0)
sts UCSR0A, temp
ldi temp, 51 ; 51 - 9600 Baud @ 8 MHz
sts UBRR0L, temp
;enable transmitter
ldi temp, (1<<TXEN0)
sts UCSR0B, temp
;set frame format 8n1
ldi temp, (1<<UCSZ00)|(1<<UCSZ01)
sts UCSR0C, temp
;--------------------------
; Set timer 0 to count CPS via pin T0
;--------------------------
ldi temp, (1<<CS02)|(1<<CS01)|(1<<CS00) ;Pin T0 on rising edge
out TCCR0B, temp
ldi temp, 0
out TCNT0, temp
;--------------------------
; Set interupts
;--------------------------
; Extarnal interupt 0 used to start calibration
ldi temp, (1<<INT0) ; Extern interupt INT0
out EIMSK, temp
ldi temp, (1<<ISC01)|(1<<ISC00) ; Rising edge
sts EICRA, temp
; Timer 1 compare interupt used for seconds
ldi temp, 30 ; Set timer compare
ldi temp2, 255 ; 30x255 gives about 1 second @ 8 MHz
sts OCR1AH, temp
sts OCR1AL, temp2
ldi temp, (1<<OCIE1A) ; Timer match A interupt
sts TIMSK1, temp
ldi temp, (1<<CS12)|(1<<CS10)|(1<<WGM12) ; Timer1 prescaler 1024 & CTC
sts TCCR1B, temp
sei ; Global interupt on
;--------------------------
; Main program
;--------------------------
main:
rjmp main
;--------------------------
; Calilbration routine
;--------------------------
; During 32 seconds counts are read each second from counter 0
; and added to register YL, YH that serves as a 16 bit register together.
; After 32 seconds the sum in YL, YH is divided in 32 to get an avrage
; and then divided in 2 to get the switchpoint
calibrate:
in cps, TCNT0 ;Get pulse count from counter 0
ldi temp, 0
out TCNT0, temp ;Clear counter 0
add YL, cps
adc YH, temp
ldi ZL, LOW(text_cps*2) ;set Low memory pointer
ldi ZH, HIGH(text_cps*2) ;set High memory pointer
rcall transmitt
mov hex, cps
rcall bcd
ldi ZL, LOW(text_seconds*2) ;set Low memory pointer
ldi ZH, HIGH(text_seconds*2) ;set High memory pointer
rcall transmitt
mov hex, calibtime
rcall bcd
ldi ZL, LOW(text_crlf*2) ;set Low memory pointer
ldi ZH, HIGH(text_crlf*2) ;set High memory pointer
rcall transmitt
dec calibtime
ldi temp, 0
cp calibtime, temp
breq calibrate_1
pop temp ; Get vital registers back from stack
out SREG, temp
pop temp2
pop temp
reti
calibrate_1: ;Calculate average and divide by 2 to get switchpoint
clc
ror YH
ror YL
clc
ror YH
ror YL
clc
ror YH
ror YL
clc
ror YH
ror YL
clc
ror YH
ror YL ; Avrage after divide by 2,5 times (2^5=32)
clc
ror YH ; Divide by 2 to get switchpoint
ror YL
mov switch, YL
pop temp ; Get vital registers back from stack
out SREG, temp
pop temp2
pop temp
reti
;--------------------------
; Timer interupt 1
;--------------------------
; In this interupt most of the action is.
; The counter is read and zeroed, the rotating buffer is keept updated and avrage CPS is calculated
; Presentation och RS232.
; And if Calibflag is < 0 the calibration is done
timer1:
push temp ; Push vital registers to stack
push temp2
in temp, SREG
push temp
ldi temp, 0
cp calibtime, temp
brne calibrate
in cps, TCNT0 ;Get pulse count from counter 0
ldi temp, 0
out TCNT0, temp ;Clear counter 0
; Avrage using rotating buffer
ld temp, X ;fetch old value from buffer
sub sum, temp ;subtract from sum
st X+, cps ;store new value in buffer and increase pointer
add sum, cps ;add new value to sum
andi XL, buff_length - 1 ;check if pointer reached buffer end
mov temp, sum
; Divide by 8
lsr temp
lsr temp
lsr temp
mov avg, temp
; Present via RS232
ldi ZL, LOW(text_cps*2) ;set Low memory pointer
ldi ZH, HIGH(text_cps*2) ;set High memory pointer
rcall transmitt
mov hex, cps
rcall bcd
ldi ZL, LOW(text_cpsavg*2) ;set Low memory pointer
ldi ZH, HIGH(text_cpsavg*2) ;set High memory pointer
rcall transmitt
mov hex, avg
rcall bcd
ldi ZL, LOW(text_cpsswitch*2) ;set Low memory pointer
ldi ZH, HIGH(text_cpsswitch*2) ;set High memory pointer
rcall transmitt
mov hex, switch
rcall bcd
ldi ZL, LOW(text_crlf*2) ;set Low memory pointer
ldi ZH, HIGH(text_crlf*2) ;set High memory pointer
rcall transmitt
pop temp ; Get vital registers back from stack
out SREG, temp
pop temp2
pop temp
reti
;--------------------------
; Transmitt via RS232
;--------------------------
transmitt:
rcall ready_tx
lpm temp2, Z+
cpi temp2, 0
breq transmitt1
sts UDR0, temp2
rjmp transmitt
transmitt1:
ret
;--------------------------
; waits for tx ready
;--------------------------
ready_tx:
lds temp, UCSR0A
sbrs temp, UDRE0
rjmp ready_tx
ret
;--------------------------
; Hex to ascii and out rs232
;--------------------------
;input: hex = 8 bit value 0 ... 255
;output: dig1, dig2, dig3 = digits
bcd:
ldi dig1, -1 + '0'
_bcd1:
inc dig1
subi hex, 100
brcc _bcd1
ldi dig2, 10 + '0'
_bcd2:
dec dig2
subi hex, -10
brcs _bcd2
sbci hex, -'0'
mov dig3, hex
rcall ready_tx
cpi dig1, '0'
brne _bcd3
ldi dig1, ' '
_bcd3:
sts UDR0, dig1
rcall ready_tx
cpi dig2, '0'
brne _bcd4
cpi dig1, ' '
brne _bcd4
ldi dig2, ' '
_bcd4:
sts UDR0, dig2
rcall ready_tx
sts UDR0, dig3
ret
;--------------------------
; Calibration start
;--------------------------
; Set the flag calibtime to start the calibration routine.
startcalib:
push temp ; Store the register on the stack
ldi temp, 32 ; Count pulses during 32 seconds
mov calibtime, temp
pop temp ; Get the register from stack
reti
;--------------------------
; RAM address
;--------------------------
.DSEG
avg_buffer: .BYTE buff_length
;--------------------------
; Dialog text
;--------------------------
.CSEG
text_cps:
.db "cps: ",0
text_cpsavg:
.db " cps avg: ",0
text_cpsswitch:
.db " cps switch: ",0
text_seconds:
.db " seconds: ",0
text_crlf:
.db 10,13,0