Sida 2 av 6
Postat: 21 oktober 2006, 16:04:04
av sodjan
OK, bara så att du inte får overflow i summan...
Förklara vad du menar med :
> problemet som det ser ut just nu är att summan liksom aldrig hinner "byggas upp".
När då ? Och byggas upp till vadå ?
Och angående din kod, kommentera *varje* rad, så att det framgår vad *du tror* att du gör.
Det är inte säkert att det stämmer överens med vad koden faktiskt gör...

Postat: 21 oktober 2006, 16:09:05
av sodjan
> Summan blir alltså alltid lika med sista värdet.
> Hur kommer jag runt det?
Jag kan inte AVR kod, men är du säker på att du får
indexerad adressering med den kod du har ?
Och ger X+ post- eller pre-increment ? Måste vara post för att det ska fungera...
Är "buff_length" verkligen *längden* på bufferten ?
Inte *adressen* till sista position+1 ?
(Jag kan ha missförstått hur cpi fungerar...)
Postat: 21 oktober 2006, 16:25:30
av Nisse
X+ ger post increment.
CPI jämför register
buff_length är satt till 8.
.equ buff_length = 8
Det är ju iof ett mer än verkliga längden eftersom man börjar på 0, men efter som det är post increment så blir det rätt.
> problemet som det ser ut just nu är att summan liksom aldrig hinner "byggas upp".
Jo, sum skall ju vara summan av alla åtta värden. Men eftersom det första jag gör är att drar ifrån det gamla värdet summeras aldrig alla värden in.
Eller vänta nu..... Hmmm, tankevurpa... I början är ju de gamla värdena som dras ifrån 0. Alltså skall det ju funka. Vad är det då som blir galet. Hmmm, kanske skall fylla på lite i glaset som skymtar på föregående bild....
Kod: Markera allt
timer1: ; Interupt som utförs en gång per sekund med hjälp av timer1 match A
ld temp, X ; Hämtar gammalt värde som finns i adress X
sub sum, temp ; Drar ifrån gammalt värde från summan
st X+, cps ; Stoppar in aktuellt (nytt) värde på det gamla värdets plats och flyttar fram pekaren
add sum, cps ; Lägger till aktuellt (nytt) värde till summan
cpi XL, buff_length ; Jämför pekaren med buffertlängden
brne _timer1 ;Är bufferten inte slut? Hoppa till timer
ldi XL, avg_buff_L ; Annars återställ pekaren
_timer1:
mov avg, sum ; Flytta summan till avg
ror avg ; Dividera med 8 genom att dividera med två tre gånger.
clc
ror avg
clc
ror avg
clc
reti
Postat: 21 oktober 2006, 16:30:44
av Nisse
Här är definitionerna också
Kod: Markera allt
.def data = r0
.def temp = r16
.def temp2 = r17
.def cps = r18
.def avg = r19
.def hex = r20
.def dig1 = r21
.def dig2 = r22
.def dig3 = r23
.def sum = r24
.equ avg_buff_H = 0x01
.equ avg_buff_L = 0x00
.equ buff_length = 8
ldi XH, avg_buff_H
ldi XL, avg_buff_L
Mvh
Nils
Postat: 21 oktober 2006, 16:34:38
av Rohan
Nollställer du verkligen alla data i ringbufferten först? Det måste du nog göra för att vara säker.
Postat: 21 oktober 2006, 16:44:06
av sodjan
Det bör vara så att det är viktigt att "sum" från början verkligen
stämmer överens med den faktiska summan i hela bufferten
(oavsett om den är noll eller något annat). Annars fär man ju fel
utgångsvärde och det blir en "skevhet" som kommer att följa med hela tiden.
Jag skulle börja med att "nolla" hela bufferten och sätta sum = 0.
I och för sig speler det igentligen ingen roll vad som ligger i bufferten
från början, bara det stämmer överens med startvärdet på "sum".
Men, eftersom din sum inte kan hålla summan av alla tänkbara
värden i bufferten (d.v.s max 255 x

, så är det bättre att initiera
det hela till ett känt läge...
Postat: 21 oktober 2006, 16:47:09
av Nisse
->Jag skulle börja med att "nolla" hela bufferten och sätta sum = 0.
Jo, det tyckte jag med, så det gör jag.
Börjar bli fundersam på om jag använder något register ovarsamt någonstans i koden. Här är hela koden:
Kod: Markera allt
.include "m88def.inc"
; 8 MHz external chrystal
.org 0x000
rjmp Reset
.org INT0addr ; Interuptvector external INT0
rjmp count
.org OC1Aaddr ; Interuptvektor timer 1 match A
rjmp timer1
;--------------------------
; initialise Stack Pointer
;--------------------------
reset:
ldi r16, low(RAMEND)
out SPL, r16
;--------------------------
; Set definitions
;--------------------------
.def data = r0
.def temp = r16
.def temp2 = r17
.def cps = r18
.def avg = r19
.def hex = r20
.def dig1 = r21
.def dig2 = r22
.def dig3 = r23
.def sum = r24
.equ avg_buff_H = 0x01
.equ avg_buff_L = 0x00
.equ buff_length = 8
ldi XH, avg_buff_H
ldi XL, avg_buff_L
ldi temp, 0
zero_buffer:
st X+, temp
cpi XL, buff_length
brne zero_buffer
ldi XH, avg_buff_H
ldi XL, avg_buff_L
ldi sum, 0
;--------------------------
; 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 interupts
;--------------------------
ldi temp, (1<<INT0) ; Extern interupt INT0
out EIMSK, temp
ldi temp, (1<<ISC01)|(1<<ISC00) ; Rising edge
sts EICRA, temp
ldi temp, 75 ; Sätter timer compare
ldi temp2, 255 ; 75 ger ungefär 2,5 sek
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
;--------------------------
; Timer interupt 1
;--------------------------
timer1:
;Provar medelvärdesbildning....
ld temp, X
sub sum, temp
st X+, cps
add sum, cps
cpi XL, buff_length
brne _timer1
ldi XH, avg_buff_H
ldi XL, avg_buff_L
_timer1:
mov avg, sum
ror avg
clc
ror avg
clc
ror avg
clc
;Slut prov medelvärdesbildning
;Presentera på 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_crlf*2) ;set Low memory pointer
ldi ZH, HIGH(text_crlf*2) ;set High memory pointer
rcall transmitt
ldi cps, 0
reti
;--------------------------
; Transmitt via RS232
;--------------------------
transmitt:
rcall ready_tx
lpm
mov temp, data
cpi temp, '#'
breq transmitt1
sts UDR0, data
adiw ZL,1
rjmp transmitt
transmitt1:
ret
;--------------------------
; Count pulse
;--------------------------
count:
inc cps
reti
;--------------------------
; 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
;--------------------------
; waits for tx ready
;--------------------------
ready_tx:
lds temp, UCSR0A
sbrs temp, UDRE0
rjmp ready_tx
ret
;--------------------------
; Dialog text
;--------------------------
.CSEG
text_cps:
.db "cps: #"
text_cpsavg:
.db " cps avg: #"
text_crlf:
.db 10,13,"#"
Postat: 21 oktober 2006, 16:49:59
av sodjan
Måste du inte "nolla" cps i timer-interruptet ?
Annars kommer den väll bara att "räkna på"...
EDIT: Äh, du gör ju det, det låg bara inte där *jag* hade lagt det...
EDIT2: En annan sak...
Jag skulle inte lägga något som tar så rellativt lång tid som UART
kommunikation i timer-interruptet. Bättre att ha det i main, så att du
inte missar någon puls.
Postat: 21 oktober 2006, 17:04:00
av Nisse
Förmodligen kommer main-loopen vara smockfull med annat jox innan detta är klart. Utadatat kommer förmodligen skickas från en egen interuptrutin som körs på egen timer och utförs betyligt mer sällan, kanske var 20 sekund eller så. Alternativt kollar jag statusen på en in-pinne och skriver bara ut när den är aktiverad.
Men jag blir knäpp, varför funkar det inte?

Nä. nu är det dags att raka sig och se om duschen vill ta imot mig. Lika bra att ge upp nu och titta med "färska ögon" vid ett senare tillfälle.
Och till alla som skrivit svar: Mycket tack! Jag lär mig massor. Fler svar och ideér är mycket välkomna.
Mvh
Nils
Postat: 21 oktober 2006, 17:37:03
av sodjan
Ett tips, "simulera" medelvärdesberäkningen med en liten buffert (säg 4 pos)
med papper och penna...
En annan detalj, har du provat med en extra clc före första ror ?
Jag antar att du har med clc för att ror inte ska shifta in "skräp"... (?)
En annan liten detalj...
Jag tror inte att du behöver ladda om XH mer än i initialiseringen,
XH kommer väl aldrig att räknas upp ?
Men det låter konstigt att summan (sum) alltid är samma som *sista* värdet...
Nä, jag är "lost"...

Postat: 21 oktober 2006, 20:43:43
av Andax
Eftersom buffern alltid är en potens av 2, pga av den enkla divisionen då, behöver du inte ha en jämförelse och återladdning utan det går att lösa med ett AND #07h (för length

etc.
Sedan vet jag inte om om count interrupten har lägre prioritet än timer1. Om inte kan cps teoretiskt ändras mellan då du lagrar undan cps i buffern och du addedar cps till sum.
Sedan, precis som Sodjan sa, behövs nog ett clc innan första ror också...
Postat: 22 oktober 2006, 00:19:55
av Nisse
-> Sedan, precis som Sodjan sa, behövs nog ett clc innan första ror också...
TACK! Där satt problemet. Jag hade ju en clc till varje ror, men hade dom efter istället för före *Doooh*. Då kom ju carry-biten med likaförbaskat i första svängen.
-> utan det går att lösa med ett AND #07h
Okej, om det är någon som ser en herrelös tankeförmåga som springer runt kan ni väl hänvisa den till mig. Andax, det där får du gärna förklara närmare.
-> Jag tror inte att du behöver ladda om XH mer än i initialiseringen,
XH kommer väl aldrig att räknas upp ?
Nepp, men jag satte in den som någon form av desperat åtgärd för att se om det var problemet
Återigen,
Tack för alla svar!
Fortsätt gärna komma med ideér och synpunkter, jag suger i mig kunskaper som en svamp.
Mvh
Nils
Postat: 22 oktober 2006, 00:24:32
av Nisse
Andax skrev:Sedan vet jag inte om om count interrupten har lägre prioritet än timer1. Om inte kan cps teoretiskt ändras mellan då du lagrar undan cps i buffern och du addedar cps till sum.
Som jag förstått databladet så stängs alla interupt av medans ett interupt körs. Först när instruktionen RETI utförs aktiveras de igen. Kan någon verifiera att jag fattat rätt?
Det är därför timer1-interuptet skall innhålla så lite kod som möjligt, som sodjan påpekade, för att inte riskera att tappa pulser. Men å andra sidan är det långsamma förlopp och väldigt få pulser, så risken är liten. Och även om det händer tappar man aldrig mer än 1 puls vilket inte syns i den statistiska variationen från strålkällan.
Skulle det bli kritiskt kan jag gå upp till 20 MHz kristall och få lite mer overhead.
Mvh
Nils
Postat: 22 oktober 2006, 00:34:12
av sodjan
> Som jag förstått databladet så stängs alla interupt av medans ett interupt körs.
Utan att känna till AVR i detalj, så verkar det rimligt, ja.
> Det är därför timer1-interuptet skall innhålla så lite kod som möjligt
Ja, och att bara plocka bort UART delen gör en *väldig* skillnad.
Du har ju en wait-loop i ready_tx där en massa instruktioner kommer
att "brännas av" i interruptet...
> Och även om det händer tappar man aldrig mer än 1 puls
Eller 2, eller 3. Det kan du inte veta. Men visst, rent statistiskt händer
det inte ofta, så i kurvorna kanske det inte märks.
> -> utan det går att lösa med ett AND #07h
Du gör AND mellan XL och '00000111', så när XL kommer till '00001000'
så blir resultatet '00000000'.
En fördel (kan *ibland* vara viktigt) är att koden *alltid* tar exakt samma
antal instruktioner...
Postat: 22 oktober 2006, 00:48:50
av Nisse
Tack Sodjan, nu fattar jag.
Byter jämförandet och vilkorshoppet till:
andi XL, buff_length - 1
Så nu är koden riktigt civiliserad
Kod: Markera allt
ld temp, X
sub sum, temp
st X+, cps
add sum, cps
andi XL, buff_length - 1
mov avg, sum
clc
ror avg
clc
ror avg
clc
ror avg
Edit: *Kanske skall ändra så att buff_length blir "rätt", dvs börjar på noll. Slipper ju dra bort 1 vid ANDI då* Nää nu skall jag sova.
Mvh
Nils