Sida 1 av 1
Timer, matematik, asm, pic, RC styrning.
Postat: 20 oktober 2008, 13:16:26
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
Postat: 20 oktober 2008, 13:44:24
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
Postat: 20 oktober 2008, 13:54:42
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.
Postat: 20 oktober 2008, 14:14:36
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

Postat: 20 oktober 2008, 14:21:17
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.
Postat: 20 oktober 2008, 14:46:58
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
Postat: 20 oktober 2008, 14:53:10
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.
Postat: 20 oktober 2008, 19:42:32
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
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

Postat: 20 oktober 2008, 21:40:17
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.
Postat: 20 oktober 2008, 22:10:08
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).
Postat: 31 oktober 2008, 13:37:13
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

Postat: 31 oktober 2008, 13:56:45
av sodjan
Vad kul ! Trevligt att du har fått igång det.