Timer, matematik, asm, pic, RC styrning.

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
luffare
EF Sponsor
Inlägg: 132
Blev medlem: 4 oktober 2005, 16:25:21
Ort: Uppsala
Kontakt:

Timer, matematik, asm, pic, RC styrning.

Inlägg av luffare »

Håller på att lära mej hur timer funktionen fungerar.
Målet är att kunna mäta hur lång en puls är från RC mottagaren till servo utgången. Ska koppla in en pic i stället för servo och den ska så småningom kunna tända på en raket. Problemet är att jag har svårt att hitta info på hur jag ska räkna, använder den interna klockan i 12F675 (4mhz).
Jag tror(ska kontroll mäta senare) att RCmojängen skickar ut pulser som är 0,5mS för ena ändläget och 1mS för mitten(neutral) och 2mS för det andra ändläget.
När det kommer en puls som är mellan ca 0,4-0,6mS sätter man en port.
När det kommer en puls som är mellan ca 1,9-2,1mS sätter man en annan port.
1. Hur lång tid tar en klockcykel?
2. Vad tycker ni om koden är jag på rätt spår?
3. Hur ska jag skriva koden om jag vill kolla om mätvärdet passar in i ett visst intervall typ 0,4-0,6mS ?

Kod: Markera allt

;****************************************************************
   List   p=12f675 
;****************************************************************    
   include <p12f675.inc> 
   __CONFIG _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_ON &_PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT 
   
cblock 0x21
	tid
	w_temp
	s_temp
endc

;Mclre_on => GP3 = mclr, och ICSP funkar...
;**************************************************************** 
 	org   0x00         ;Start programmet
	goto init
;**************************************************************** 
	org		0x004		;Interupts
	movwf	w_temp			;wreg & status sparas utifall man ändrar i dom under interuptet 
	swapf	STATUS,w
	movwf	s_temp
;kod
	banksel TRISIO			;bank1
	btfss	INTCON, INTF	;om INTF = 1. dvs GP2 interuptad hoppa över "hopp"  
	goto	hopp

	btfss	Option_reg,intedg ;om den är fallande gå dit annars hoppa över.
	call	fall
	btfsc	Option_reg,intedg ;om den är stigande gå dit annars hoppa över.
	call	rise

hopp
	banksel	gpio			;bank0
	swapf	s_temp, W		;Återställer Status & W registren..
	movwf	STATUS
	swapf	w_temp, F
	swapf	w_temp, W	

	retfie					; INTCON,GIE  = 1 och går tillbaka till programet

;****************************************************************
init 
   banksel   trisio     		;Öppnar Bank 1 
   movlw   b'00000000' 
   movwf   ansel      			;Alla portar är digitala(ans0-3=bit0-3) 
   movlw   b'00000100'    
   movwf   trisio     			;Alla portar är utgångar utom gp2 (& gp3..) 
   bcf	   option_reg,t0cs		;Internal TMR klock	
   bsf	   option_reg,psa		;ingen precsale..
	
   bsf	   option_reg,intedg	;Interupt på stigande flank
   bsf     intcon,inte			;GP2 Interupt ON
   bsf	   intcon,gie			;Global Interupt ON


   banksel	gpio      			;Öppnar Bank 0 
   clrf		gpio      			;init GPIO 
   bcf		adcon0,adon			;A/D omvandlare avstängd. 
   movlw	b'00000111' 
   movwf	cmcon     			;Comparator OFF 
;**************************************************************** 
   clrw 
   movwf	tid 
   movwf	w_temp
   movwf	s_temp
start 
   goto		start 
;**************************************************************** 

rise				;Subrutin för stigande flank på GP2
	bcf		INTCON,INTF			; 
	banksel trisio				;Bank1
	bcf		option_reg,intedg	;Ändrar så att interupt sker på fallande flank
	banksel	gpio				;Bank0
	movlw	h'15'				;
	movwf	tmr0				;startar tmr0, 13(hex) instruktioner hit från gotostart +2 för skrivningen till TMR0 
	bsf		gpio,4				;Tänder lysdiod
return
;**************************************************************** 

fall				;Subrutin för fallande flank på GP2
	bcf		INTCON,INTF			; 
	banksel trisio				;Bank1
	bsf		option_reg,intedg	;Ändrar så att interupt sker på stigande flank
	banksel	gpio				;Bank0
	movf	tmr0,w				;sparar tiden hit.
	movwf	tid
	;ska ta bort 10(hex) instruktioner vilket det tar från gotostart hit(dvs när pulsen faller)
	movlw	h'10'
	subwf	tid,f
	bcf		gpio,4				;Släcker lysdiod
return

end
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

Klockan till timern är inte 4MHz om PIC's oscillator är 4MHz. PIC delar den
med 4, så detär alltså 1MHz som timern räknar med.

Pulsen från de flesta RC-anläggningar är 1.5ms i neutralläge och ändras
sedan +/- 0.5ms i ändlägena. Alltså 1..2ms puls beroendepå läge. Finns
fabrikat som avviker lite från detta.

Vill Du ha en enkel till/från så sätt bara en enda gräns och bestäm om den
är över eller under. Är det ett problem om det blir "fladder" när pulsen är
nära gränsenså flytta denna vid omslag så att det uppstår en viss hysteres.

Skall Du ha tillslag i ena läget och frånslag i andra så sätt två gränser. En
som betyder till och en som betyder från.

Testa pulsen flera gånger innan den reagerar, detta för att få viss
störsäkerhet. Annars kan (läs kommer) den att reagera på störningar lite då
och då.

Är Du ny på detta så undvik interrupt i början tills Du känner Dig säker på att
programmera utan.

Du skall helt enkelt läsa av porten om den är 0 eller 1 och sedan vänta till
önskad flank. Skriv då noll i timern och vänta på den andra flanken. Läs
timern och Du har ett mått på pulstiden som sedan kan bearbetas vidare.

Det här är långsamma signaler, repetitionsfrekvensen är ju bara c:a 50Hz
och det lämnar 20ms mellan pulserna. Det är massor av tid för den
bearbetning som behövs.

Det finns prescalers för timern, använd denna för att få en lagom
räknehastighet. Välj en prescaler på 16 så blir det nog ganska lagom. Med 8
är Du allt för nära att räknaren slår runt vid längsta pulstiden. Du behöver
inte större upplösning än vad 16 ger för denna applikation.


Edit: Såg inte med en gång att Du tänkt ha den till en modellraket. Då skall
Du definitivt testa om pulsen ligger inom ett visst fönster. Det finns ingen
anledning att sätta upp något villkor för "frånläge", allt som inte är "till" är
"från"

Räkna upp en räknare när den är "till" och nolla den när den är "från". När
räknaren når ett visst värde så initiera tändningen. Det bör ge tillräcklig
störsäkerhet.

Lägg även av säkerhetsskäl en tidsfördröjning med varningssignal när den
skall till att tända och som är så lång att Du hinner bryta/springa innan den
tänds.

Edit2: Hårda radslut
Senast redigerad av Marta 20 oktober 2008, 15:06:44, redigerad totalt 2 gånger.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Nja, allt finns i databladet (så klart)... :-)

> 1. Hur lång tid tar en klockcykel?

Sidan 69, en bit ner på sidan :
One instruction cycle consists of four oscillator periods;
for an oscillator frequency of 4 MHz, this gives a normal
instruction execution time of 1 us.
Själva räkningen kan ju göra på lite olika sätt.
Ett sätt kan vara :

Vänta på start av en puls.
När den kommer, starta en timer i lämplig fart (d.v.s prescaler o.s.s).
Vänta på slut på puls.
Stoppa timern, och kolla hur långt den kom.
Om du sätter TMR1 prescaler till 8 så kommer dina tider att
motsvaras av :

0,4 ms : 50
0,6 ms : 75
1,9 ms : 237
2,1 ms : 262

Notera dock (som Marta skrev) att tiderna verker lite "ostandard"...

Eller TMR0 med prescaler 1:16, så slipper man värdet > 255 för 2,1 ms...

Sedan är det bara att kolla i vilket intervall TMR1 eller TMR0 hamnade
och göra vad som ska göras...

Om detta är det enda den ska göra, så kan man skriva det "rakt på".
Om processorn även håller på med annat, så kanske man får göra
en lite snyggare lösning med interrupt o.s.v.

För att minska risken för störningar kan du vänta på 5 eller 10
tiden inom samma intervall innan du "triggar" på det.
Användarvisningsbild
luffare
EF Sponsor
Inlägg: 132
Blev medlem: 4 oktober 2005, 16:25:21
Ort: Uppsala
Kontakt:

Inlägg av luffare »

Då ska vi se om jag har fattat rätt, en instruktion tar alltså 1/10^6 dvs. 0,001ms ? och från att interupt sker till timern startar tar det 0,021ms?
Hur ska jag räkna med prescaler? delar jag den tiden jag fick med t.ex 16?

Är det bara den interna osc som delas med 4? eller är det även externa? vad används resten till?

Du har nog rätt med att det är 1-2ms

Jag ska ha två olika portar som startar och är igång en viss tid(olika raketer)
Lysdiodgrejen ska bort den hade jag bara för att testa.

Hade tänkt kolla om värdet är detsamma tio gånger på raken innan den aktiverar porten, för att slippa skjuta av misstag, tror ni det räcker?

Det där med att skita i interupten och läsa av porten, reagerar den på positiv flank eller ska man ställa in det nånstans?

Tack för hjälpen
:D
Användarvisningsbild
luffare
EF Sponsor
Inlägg: 132
Blev medlem: 4 oktober 2005, 16:25:21
Ort: Uppsala
Kontakt:

Inlägg av luffare »

Sodjan du svarade visst samtidigt som jag skrev förra inlägget :)
måste dra och handla ska testa med prescale och utan interupt när jag kommer hem.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

Skippa interrupt, det är ingen mening i denna applikation. Ställer bara till
krångel och ökar risken för felfunkton.

Prescaler är något Du ställer in i programmets initieringsdel och som får
timern att räkna långsammare. Med t.ex. prescaler 1:16 och 4 MHz klocka
så får Du först en delning med 4 till 1MHz som alltid finns där och inte kan
väljas bort. Sedan delar prescalern ytterligar med 16 till 62.5kHz som blir
den frekvens som stegar räknaren. Multiplicera pulstiden i millisekunder
med 62.5 så får Du värdet som timern står på efter denna tid.

Starta timernen gång för alla i programmets initiering. Det finns ingen orsak
att starta och stoppa den vid mätningarna, det bara orsakar krångel. Det är
en 8-bit timer som Du startar om genom att helt enkelt skriva 0 till den.
Finns en speciell instruktion just för att skriva noll.

Gör så att Du väntar på pulsens början, helt enkelt genom att testa
ingångsbiten och loopa tills den står så. Skriv då noll i timern. Vänta på
samma sättigen, men denna gång på den andra flanken. Läs nu timern.

I detta läge har Du massor av tid till att bearbeta värdet innan nästa puls
kommer.

Gör testutgångar med LED's som reagerar direkt när pulsen ligger inom
önskade gränser. Då kan Du lätt prova det hela och känna på marginalerna
för att därefter justera gränsvärdena om det behövs. Försök inte att räkna
på dessa i detalj, det är bättre att prova. När Du räknar på de ungefärliga
värdena så lägg inte arbete på att räkna instruktionstider, dessa är
försumbara i sammanhanget.


Skippa inte varningssignaler om Du står i ett sådant läge när kretsen
aktiveras att det kan innebära en risk. Detta bör Du för övrigt helst inte
göra, det är IMHO mycket oklokt att ha något annat än en garanterat säker
brytare på betryggande avstånd som måste slås till för att aktivera det hela.
Direktkopplad givetvis, inte bara en signal som sedan går genom processor
eller annan elektronik.

Edit: Hårda radslut
Senast redigerad av Marta 20 oktober 2008, 15:08:22, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Sodjan du svarade visst samtidigt som jag skrev förra inlägget...

Inte alls samtidigt !
Jag svarade *20 minuter innan* du postade ditt inlägg. :-)
Så det fanns massor av tid att se mitt inlägg innan du tryckte på "sänd".
En snabb "Förhandgranska" innan du postade hade visat mitt inlägg direkt...

> Är det bara den interna osc som delas med 4? eller är det även externa?

Fcyc = Fosc / 4. Var Fosc kommer från är inte intressant.
Alltså är Tcyc = Tosc * 4 (alltså tiden för en intruktionscykel).

> ...vad används resten till?

Vilken "rest" ?

> Det där med att skita i interupten och läsa av porten, reagerar den på positiv flank...

Om du läser porten så får du kolla flanker precis som du vill.
Det finns inget som "reagerar" på något (förrutom logiken i din kod).

> Hade tänkt kolla om värdet är detsamma tio gånger på raken innan den aktiverar porten, för att slippa skjuta av misstag, tror ni det räcker?

Inte en aning ! Du får väl prova... :-)

Martas förslag med en säkerhetsbrytade på ett säkert avstånd är också bra.
Användarvisningsbild
luffare
EF Sponsor
Inlägg: 132
Blev medlem: 4 oktober 2005, 16:25:21
Ort: Uppsala
Kontakt:

Inlägg av luffare »

Ok nu har jag gjort om det hela, men det känns lite buggit t.ex

Kod: Markera allt

wait
	btfsc	gpio,2	;Slutar pulsen?
	goto	wait		;Nej
	movf	tmr0,w
Om jag är på rad "goto" när pulsen kommer/slutar så kommer timern ticka en gång mer än om jag är på rad "btfsc" eller tänker jag fel?
och det gör det lite svårt att tajma in t.ex 10 likadana pulser på raken.

I databladet står det nåt om att prescale resettas när man läser och skriver till timern, testade men det ändras inte, så vad menar dom?

Kan man på något smidigt sätt ändra värdet i timern när man simulerar? tog ett litet värde när jag testade men även det är lite jobbigt

Angående säkerheten så är det små raketer som brukar säljas i 10pack (barn brukar få skjuta dom). Raketerna ska sitta på ett RC plan, picen och rc prylarna startas samtidigt med en brytare på planet, raketerna kommer bara vara inkopplade när man är ute på en äng för att testa eller flyga.
Det är därför jag vill ha 10 eller i värsta fall fler likadana pulser innan dom avfyras precis som ni säger, servorna brukar ju få lite ryck när man slår på strömmen speciellt om radion är av :lol:
Har inte hunnit fundera så mycket på hur dom ska tändas men en ide vore att ta en glödlampa och sno "glödtråden" och linda runt stubinen, men först måste det här funka med lysdioder så här kommer den nya koden:

Kod: Markera allt

;****************************************************************
   List   p=12f675 
;****************************************************************    
   include <p12f675.inc> 
   __CONFIG _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_ON &_PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT 
   
cblock 0x21
	tid
	test
	antal
endc

;**************************************************************** 
 	org   0x00        
;**************************************************************** 
init 
   banksel   trisio     		;Öppnar Bank 1 
   movlw   b'00000000' 
   movwf   ansel      			;Alla portar är digitala(ans0-3=bit0-3) 
   movlw   b'00000100'    
   movwf   trisio     			;Alla portar är utgångar utom gp2 (& gp3..) 

   bcf	   option_reg,t0cs		;Internal TMR klock	
   bcf	   option_reg,psa		;precsale tmr0
   bcf	   option_reg,ps0		;1:16
   bcf	   option_reg,ps1		;
   bsf	   option_reg,ps2		;

   banksel	gpio      			;Öppnar Bank 0 
   clrf		gpio      			;init GPIO 
   bcf		adcon0,adon			;A/D omvandlare avstängd. 
   movlw	b'00000111' 
   movwf	cmcon     			;Comparator OFF 
;**************************************************************** 
   clrw 
   movwf	tid 
   movwf	test
   movwf	antal
start 
	btfss	gpio,2		;kommer pulsen?
   	goto	start 		;Nej
	movlw	h'02'		;Tänker jag rätt?
	movwf	tmr0
wait
	btfsc	gpio,2		;Slutar pulsen?
	goto	wait		;Nej
	movf	tmr0,w
	movwf	tid
	xorlw	h'7d'		;62500hz*0,002s
	btfsc	status,z	;Om dom är samma så är den lång
	call	long

	movf 	tid,w
	xorlw	h'3e'		;62500hz*0,001s ~ 62 
	btfsc	status,z	;Om dom är samma så är den kort
	call	kort

	;om inte 
;	clrf	tid
;	clrf	test	;senste pulsen var varken kort eller lång.
	goto	start
	
;**************************************************************** 

long					;Subrutin för lång puls
	incf	antal		;Antal pulser
	btfss	test,0		;Var den senaste lång?
	goto	nej1		;Nej
	movf	antal,w 	;Kollar om det är tio långa pulser på raken.
	xorlw	h'09'
	btfss	status,z	;
	goto	slut1
	bsf		gpio,4		;Ja vi har tio på raken tänd led.
	clrf	test
	clrf	antal
return
nej1
	movf	antal,w 	;Kollar om det är den första pulsen.
	xorlw	h'01'
	btfss	status,z	;
	clrf	antal		;Nej något är fel
slut1
	movlw 	b'00000001';Denna puls har varit lång.
	movwf	test	
return
;**************************************************************** 

kort				;Subrutin för kort puls
	incf	antal		;Antal pulser
	btfss	test,1		;Var den senaste kort?
	goto	nej2		;Nej
	movf	antal,w 	;Kollar om det är tio korta pulser på raken.
	xorlw	h'09'
	btfss	status,z	;
	goto	slut2
	bsf		gpio,5		;Ja vi har tio på raken tänd led.
	clrf	test
	clrf	antal
return
nej2
	movf	antal,w 	;Kollar om det är den första pulsen.
	xorlw	h'01'
	btfss	status,z	;
	clrf	antal		;Nej något är fel
slut2
	movlw 	b'00000010';Denna puls har varit kort.
	movwf	test	
	
return
;**************************************************************** 

end
btw tack för att ni tar er tid det uppskattas :tumupp:
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

Du behöver inte alls tänka på att räknaså noga som enskilda klockpulser. Det
kommer ändå inte att fungera på det sättet. Använd instruktionen för att skriva
noll för att nolla timern. Prescalern gör att det går 16 1-klockas instruktioner
mellan varje gång timern stegas, men det är inget att tänka på hellre.

När Du jämför resultatet så måste Du ha en fönsterkomparator, Du kan inte
förvänta Dig att träffa ett exakt värde. Det kommer att fladdra plus/minus
några timersteg hela tiden.

Du kan inte hellre förvänta Dig en sådan upplösning att Du kan styra 10 olika
utgångar på detta sättet med någon säkerhet. Kan gå att få till att fungera,
men tveksamt.

Antar att Du tänkt Dig att använda en överföringsfunktion med ett reglage
som stannar kvar i sitt läge. När Du sedan skjuter/vrider detta så skall den
avfyra raketer en efter en?

Om så är fallet så kan Du nog het enkelt skifta värdet åt höger ett par, tre
gånger för att få bort fladdret. Pröva även med prescaler 8 för att få mera
upplösning. Blir detproblem med att den går runt så gör en liten
fördröjningsloop innan den nollas så att dödtiden på 1ms tas bort från det
den behöver räkna.

Eller har Du kanske tänkt Dig att ena ändläget så skjuter denen raket under
ena vingen och det andra en under den andra? Sedan har Du i så fall
räknare som räknar upp och avgör vilken som står i tur att skjutas av. Det är
ett bättre sätt som tåler mycket mera störningar. I det fallet har Du en
fönsterkomparator för att känna av om kontrollen står i ett ändläge.

Lusläsning av koden för att säga om allt stämmer ärmera arbete än att
skriva programmet. Detta måste Du göra själv genom att prova och åter
prova. Det är så programmering går till

Skippa simulatorn och kör på den riktiga processorn, det är det enda raka
när det gäller sådant där timers o.dyl. är inblandat. Simulering kan man
testa matematiska algoritmer med, men inte realtidsapplikationer.


För att få tråd att tända med så köp en tunn motståndstråd, krossa inte
lampor. Tråden är med stor säkerhet en engångsvara, som bränns sönder
när den används. Det hela måste kanske även göras skyddat på något sätt
beroende på hur mycket fartvinden kyler.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> lite svårt att tajma in t.ex 10 likadana pulser på raken.

Du ska bara avgöra om det kommer 10 pulser *inom ramen* i följd.
D.v.s om det t.ex är 10 st "tänd" pulser i följd.
Det exakta värdet är inte intressant, bara om det ligger "över eller under ribban".

Notera att 10 pulser betyder att spaken måste stå i "tändläge" minst
0.2 sek, det kanske är lite kort tid. Så kanske du ska invänta fler
"tänd" pulser i följd. Det är en avvägning mellan säkerhet mot feltändning
och svarstid från spaken.

Notera också att timern räknar med en prescaler. Om den t.ex är satt
till 16 (som vi diskuterade tidigare) så hinner processorn köra knappt
16 instruktioner (lite beroende på hur stor andel 2 cykel instruktioner
det blir) mellan varje "steg" på timern. Så en eller två extra instruktioner
kommer sannolikt inte att märkas alls på timerns värde.

> I databladet står det nåt om att prescale resettas när man läser och skriver till timern,
> testade men det ändras inte,...

Det är alltså inte *inställning* av prescaler som resettas (d.v.s om det
är 1:8 eller 1:16 eller något annat, utan prescaler-räknaren själv (d.v.s
om den har hunnit räkna till t.ex 13 av de 16 cyklerna).
Användarvisningsbild
luffare
EF Sponsor
Inlägg: 132
Blev medlem: 4 oktober 2005, 16:25:21
Ort: Uppsala
Kontakt:

Inlägg av luffare »

Har haft fullt upp ett tag så jag har inte hunnit leka med projektet förens nu. Testade med lite gamla rc prylar och det funkade förvånansvärt bra, behövde bara justera tiderna så att det skulle passa bättre.

Picen mäter tio likadana pulser på raken och tänder en av två lysdioder i några sek, beroende på om det var långa eller korta pulser.
Har testat starta upp utan radion igång och låtit den stå ett tag men den har inte tänt någon lysdiod utan att jag velat göra det via radion, den tänder ingenting om jag drar lite snabbt till ett läge och tillbaka, så jag tror 10pulser är lagom. Nu återstår att byta ut lysdioderna mot någon tråd som kan glöda och sen testa med dom riktiga rc grejerna på måndag(dom ligger i skolan).

Tack för förklaringarna nu börjar några av pussel bitarna sakta hamna på plats :D
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Vad kul ! Trevligt att du har fått igång det.
Skriv svar