Flytande medelvärde i avr

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
exile
EF Sponsor
Inlägg: 496
Blev medlem: 21 oktober 2005, 23:32:07

Inlägg av exile »

Nja, du kan inte få "overflow" på 16bitar talet efter som 255*8 (i ditt fall) 2040 vilket ryms i 16bitars tal.

Nu har det här inte så stor betydelse, då du vet om problemet ^^
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

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
Användarvisningsbild
exile
EF Sponsor
Inlägg: 496
Blev medlem: 21 oktober 2005, 23:32:07

Inlägg av exile »

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 ^^
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

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,"#"


Användarvisningsbild
exile
EF Sponsor
Inlägg: 496
Blev medlem: 21 oktober 2005, 23:32:07

Inlägg av exile »

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:

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
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 ^^
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

Tack för tipsen, det är verkligen kanon!
Skillnaden mellan OUT och STS var något jag läste lite om i går kväll när jag stötte på problem. Då upptäckte jag just de begränsningar i vilka register de kunde använda. Ska gå igenom koden framöver och "städa" lite sådana grejor.

Mvh
Nils
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4700
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

AVR tips

Inlägg av Swech »

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

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

Eller söka efter -1 i en tabell

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
Jonas /Swech
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

Swech -> Jo, det är också en metod. Sparar en instruktion här och där. Dock så vill jag inte gärna låsa upp några register till att alltid vara noll respektive -1. Blir jobbig om man helt plötsligt upptäcker att de skulle behövts till något annat.

Mvh
Nisse
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4700
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

med 32 register så är det mycket osannolikt att du skulle sakna 2-3 styck
Särskilt som reg 1-15 är såpass begränsade att de är i praktiken är värdelösa..

m.v.h
Jonas /swech
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

Tja, det är väl en bedömning vi gör olika i så fall. :)
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

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.

Bild

Bild

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 :)
Användarvisningsbild
Andax
Inlägg: 4373
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Inlägg av Andax »

Sniffa upp polonium 210 :?:
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

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 :lol: 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
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4700
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

lite fler tips...

Inlägg av Swech »

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

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  
Då försvinner risken med att dubbeldeklarera ramadresser.
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
Användarvisningsbild
Nisse
Inlägg: 908
Blev medlem: 9 juli 2006, 23:25:46
Ort: Kumla

Inlägg av Nisse »

Ska ta och titta igenom dina tips ordentligt när jag får tid Swech, tackar.

Men vad det gäller punkt 1. Hur skulle det kunna råka genereras ett interupt? Det är väl bara de interupt jag väljer att aktivera som kan inträffa, eller har jag missuppfattat?

Mvh
Nisse
Skriv svar