Flytande medelvärde i avr
Fick nu äntligen lite tid över till att pyssla med detta.
Tänkte nu rodda om programmet att använda Timer2 för att räkna pulser från GM-röret. Stötte dock på patrull direkt. Så som jag läser databladet så är den ingång som skall användas TOSC1. Det funkar ju inget bra då jag har kristallen kopplad där... Eller är det jag som fattat fel?`
Mvh
Nisse
Tänkte nu rodda om programmet att använda Timer2 för att räkna pulser från GM-röret. Stötte dock på patrull direkt. Så som jag läser databladet så är den ingång som skall användas TOSC1. Det funkar ju inget bra då jag har kristallen kopplad där... Eller är det jag som fattat fel?`
Mvh
Nisse
Det stämmer att timmer2 använder TOSC1 och TOSC2, de ingången (samt utgången) är till för att driva en kristall och inte räkna pulser. (som jag inte tänkte på när gav exemplet)
Där imot så T0 och T1 just till för att räkna pulser.. dock så är dessa ingångar koplade till timmer0 och timmer1.. vilket gör att du få bytta runt lite för att få det att passa , vilket inte bör vara några problem ^^
Där imot så T0 och T1 just till för att räkna pulser.. dock så är dessa ingångar koplade till timmer0 och timmer1.. vilket gör att du få bytta runt lite för att få det att passa , vilket inte bör vara några problem ^^
Nu änvder programmet Timer/Counter 0 för att räkna pulser istället för interupt.
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
;--------------------------
; Set buffer pointers and zero buffer
;--------------------------
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 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
;--------------------------
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:
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
;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
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
;--------------------------
; 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
;--------------------------
; Dialog text
;--------------------------
.CSEG
text_cps:
.db "cps: #"
text_cpsavg:
.db " cps avg: #"
text_crlf:
.db 10,13,"#"
Ja tänkte ge några tips...
När man anväder "" så noll termineras (sitta teknet är 0x00) de delvis så är # onödigt (använd 0x00 istället)
Om man vill spara ström (exempel i en battrei driven sak) så kan man använda ide (sleep i main funktionen) så spar man lite stöm
Jag såg att du använde:
lpm
mov temp, data
Vilket kan om man vill ersättas med
lpm temp, Z
Desutom kan du ta bort adiw ZL,1
Om du använder lpm temp, Z+
Exemple:
Jag ser att du använder STS mycket istället för out.
De gör sama saker men har lite olika begränsningar
STS tar 2cyckler att utföra samt tar 4byte och kan addressera 16bitar (om man inte anväder en AVR med störe addres buss)
OUT tar 1cyckel att utföra och tar 2byte men kan bara addressera 0 till 0x3f
För komma till rätta med "problemet" (nu spelar det inte så stor roll) kan man använda ett makro
exempel:
Mer om macron går att läsa bland annat Application Notes 001
Det här jag nu har tagit upp nu är till för att vissa vad man kan göra, men som inte är nödvändigt utan mer ska ses som "roligt att veta" ^^
Edit:
Ja just det som det är nu så avrundar "flyttande medelvärdet" neråt
exempel:
du får 1 puls vid varje mät värde 7 gånger och ingen puls 1gång
då blir summan 7. men 7 = b00000111 shiftat tre gånger blir b00000000 = 0 det önsk värda resultatet skulle "enligt min mening" vara 1.
Det kan man lösa ganska enkel genom att addera 4 (halav man delar med) innan man delar ^^
När man anväder "" så noll termineras (sitta teknet är 0x00) de delvis så är # onödigt (använd 0x00 istället)
Om man vill spara ström (exempel i en battrei driven sak) så kan man använda ide (sleep i main funktionen) så spar man lite stöm
Jag såg att du använde:
lpm
mov temp, data
Vilket kan om man vill ersättas med
lpm temp, Z
Desutom kan du ta bort adiw ZL,1
Om du använder lpm temp, Z+
Exemple:
Kod: Markera allt
transmitt1:
out UDR0, temp
transmitt:
rcall ready_tx
lpm temp,Z+
cpi temp,'#' // eller 0 om man vill använda nollterminering
brne transmitt1
ret
Jag ser att du använder STS mycket istället för out.
De gör sama saker men har lite olika begränsningar
STS tar 2cyckler att utföra samt tar 4byte och kan addressera 16bitar (om man inte anväder en AVR med störe addres buss)
OUT tar 1cyckel att utföra och tar 2byte men kan bara addressera 0 till 0x3f
För komma till rätta med "problemet" (nu spelar det inte så stor roll) kan man använda ett makro
exempel:
Kod: Markera allt
.MACRO STORE ;Arguments: Address, Register
.if @0>0x3F
sts @0, @1
.else
out @0, @1
.endif
.ENDMACRO
//ex
STORE portb,r16
Det här jag nu har tagit upp nu är till för att vissa vad man kan göra, men som inte är nödvändigt utan mer ska ses som "roligt att veta" ^^
Edit:
Ja just det som det är nu så avrundar "flyttande medelvärdet" neråt
exempel:
du får 1 puls vid varje mät värde 7 gånger och ingen puls 1gång
då blir summan 7. men 7 = b00000111 shiftat tre gånger blir b00000000 = 0 det önsk värda resultatet skulle "enligt min mening" vara 1.
Det kan man lösa ganska enkel genom att addera 4 (halav man delar med) innan man delar ^^
- Swech
- EF Sponsor
- Inlägg: 4700
- Blev medlem: 6 november 2006, 21:43:35
- Ort: Munkedal, Sverige (Sweden)
- Kontakt:
AVR tips
Kan inte hjälpa att komma med lite tips om AVR...
Jag reserverar alltild två register som jag kallar för S_ZERO samt S_VOID
Lämpligt är r2,r3... register r1-r15 är relativt begränsade och oftast använder man dem inte...
Börja programmen med att sätta S_ZERO till 0 samt S_VOID till -1
T.ex för att indexera en X pekare
Eller söka efter -1 i en tabell
Jonas /Swech
Jag reserverar alltild två register som jag kallar för S_ZERO samt S_VOID
Lämpligt är r2,r3... register r1-r15 är relativt begränsade och oftast använder man dem inte...
Börja programmen med att sätta S_ZERO till 0 samt S_VOID till -1
T.ex för att indexera en X pekare
Kod: Markera allt
;R16=index
Ldi XL,low(buffer)
Ldi XH,High(buffer)
Add xl,r16
ldi r16,0
adc xh,r16
Kan ersättas med
;R16=index
Ldi XL,low(buffer)
Ldi XH,High(buffer)
Add xl,r16
Adc xh,S_Zero
Kod: Markera allt
Ldi ZL,low(table*2)
Ldi ZH,High(table*2)
.
Loop:
lpm
adiw zl,1
cp r0,s_void
brne Loop
.
.
Table:
.db "hello",void
Det går sakta frammåt.
Har skaffat mig ytterligare en liten strålkälla här hemma vilket gör att jag nu kan köra programmet i full fart och ändå få önskvärda pulsrater. Det medför också att GM-röret kan köras ytterligare lite försiktigare samt att medelvärdena blir lite bättre.
Dippen i mitten kommer sig av att jag flyttade strålkällorna från GM-röret en stund.
Det har även dykt upp något helt nytt, nämligen "Cps switch". Det värdet beräknas fram som ett medelvärde över 32 sekunder, som sedan delas på två. Den medelvärdesberäkningen triggas av ett externt interupt, vilket kommer bli en knapp på appareten.
Vid det här laget kanske någon kan börja lista ut vad det hela kan användas till
Har skaffat mig ytterligare en liten strålkälla här hemma vilket gör att jag nu kan köra programmet i full fart och ändå få önskvärda pulsrater. Det medför också att GM-röret kan köras ytterligare lite försiktigare samt att medelvärdena blir lite bättre.
Dippen i mitten kommer sig av att jag flyttade strålkällorna från GM-röret en stund.
Det har även dykt upp något helt nytt, nämligen "Cps switch". Det värdet beräknas fram som ett medelvärde över 32 sekunder, som sedan delas på två. Den medelvärdesberäkningen triggas av ett externt interupt, vilket kommer bli en knapp på appareten.
Vid det här laget kanske någon kan börja lista ut vad det hela kan användas till
Polonium 210 har blivit ett populärt samtalsämne på senare tid. Höll en kurs i grundläggande strålskydd i Torsdags. Tidigare fick man alltid massor av Tjernobylfrågor, nu var det hälften Tjernobyl och andra hälften Polonium Ingen av de båda har med vad kursen handlade om....
Nja, ska man sniffa Polonium finns det bättre verktyg än vanliga GM-rör, speciellt så okänsliga som det jag använder. Det hela är tänkt att bli en nivåvakt. exempel: http://www.berthold.com/ww/en/pub/proze ... switch.cfm
Nja, ska man sniffa Polonium finns det bättre verktyg än vanliga GM-rör, speciellt så okänsliga som det jag använder. Det hela är tänkt att bli en nivåvakt. exempel: http://www.berthold.com/ww/en/pub/proze ... switch.cfm
- Swech
- EF Sponsor
- Inlägg: 4700
- Blev medlem: 6 november 2006, 21:43:35
- Ort: Munkedal, Sverige (Sweden)
- Kontakt:
lite fler tips...
Tittade på ditt program och har en hög med tips...
1. Definiera upp alla interrutpvektorer. Hela högen, De du inte använder
sätter du till RETI. På detta sätt så undviker du kaos om någon pinne eller t.ex Uart skulle råka generera ett interrpt som du inte vill ha.
2. Du laddar bara SPL, men 88 har ju 1k minne. Ladda även SPH
LDI sph, high(ramend) - annars får du din stack någinstans mellan 0-255
3 . Istället för att definiera en buffer adress med avg_buff_H och
avg_buff_L använd low(avg_buff) och high(avg_buff). Det blir mycket enklare att flytta omkring kod på detta sätt.
3b Definiera Ram adresser med
.DSEG
Då försvinner risken med att dubbeldeklarera ramadresser.
För att adressera AVG_BUFFER ovan så skriv
4. Din interruptrutin sparar inte undan statusregistret... inte heller några andra register.... Så länge du inte gör något annat i din Main loop
så är det ok..men du kommer snart att vilja göra mer saker samtidigt med interruptrutinen
Om intresse finns så återkommer jag gärna med fler tips.
Jonas
Swech Trading
1. Definiera upp alla interrutpvektorer. Hela högen, De du inte använder
sätter du till RETI. På detta sätt så undviker du kaos om någon pinne eller t.ex Uart skulle råka generera ett interrpt som du inte vill ha.
2. Du laddar bara SPL, men 88 har ju 1k minne. Ladda även SPH
LDI sph, high(ramend) - annars får du din stack någinstans mellan 0-255
3 . Istället för att definiera en buffer adress med avg_buff_H och
avg_buff_L använd low(avg_buff) och high(avg_buff). Det blir mycket enklare att flytta omkring kod på detta sätt.
3b Definiera Ram adresser med
.DSEG
Kod: Markera allt
.DSEG
R_START_CLEAR: ;endast som exempel
R_TENTH_PRE: .BYTE 1 ;endast som exempel
R_60_PRE: .BYTE 1 ;endast som exempel
R_60HZ: .BYTE 1 ;endast som exempel
AVG_BUFFER: .BYTE buff_length
För att adressera AVG_BUFFER ovan så skriv
Kod: Markera allt
ldi XH, high(avg_buffer)
ldi XL, low(avg_buffer)
ldi temp, 0
zero_buffer:
st X+, temp
cpi XL, low(avg_buffer+buff_length)
brne zero_buffer
; skall man vara helt säker så bör man även
cpi XH, High(avg_buffer+buff_length)
brne zero_buffer
4. Din interruptrutin sparar inte undan statusregistret... inte heller några andra register.... Så länge du inte gör något annat i din Main loop
så är det ok..men du kommer snart att vilja göra mer saker samtidigt med interruptrutinen
Om intresse finns så återkommer jag gärna med fler tips.
Jonas
Swech Trading