Korta delayer (1-10ms) i PIC - "Bästa" sättet?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Korta delayer (1-10ms) i PIC - "Bästa" sättet?

Inlägg av JimmyAndersson »

Har märkt att MikroBasic har problem med korta delayer (mellan 1-10ms) när man kör med vdelay_ms().
Antingen blir de längre eller så ignoreras de, beroende på längden man knappar in i koden. Tittar man i Hjälpen för MikroBasic så står det mycket riktigt: "VDELAY_MS(). Generated delay is not as precise as the delay created by Delay_ms." :?

Hur gör ni fördröjningar i den här storleken? Timer?
Eventuellt kod-exempel behöver inte vara i MikroBasic, det fungerar även med C eller i "värsta fall" asm-kod. :)

edit: Hm, att använda timern blir nog lite knepigt. Jag vill enkelt kunna ändra tiden med en variabel. Ska förresten använda fördröjningen till att fixa en PWM-puls på en PIC12F675 (med intern klocka), så andra tips kring detta är också välkomna.

I princip är det detta jag ska göra:
*Sätta en utgång hög
*Vänta ett tag (mellan 1-40ms)
*Göra samma utgång låg
*Vänta ett tag (mellan 0-40ms)
och till början igen..

Känner att det börjar bli dags att byta programmeringspråk... :)
Användarvisningsbild
Xerxes
Inlägg: 248
Blev medlem: 25 januari 2004, 22:55:05
Ort: Lund
Kontakt:

Inlägg av Xerxes »

Kika på den här och se om du kan modda;
http://www.piclist.com/techref/piclist/ ... /delay.htm
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

En lösning är att överge BASIC-skiten och börja med assembler, då har man bättre koll.

Hursomhelst, ponera följande:
Initiera vid att starta en timerinterrupt på 10KHz, alltså en interrupt var 0,1ms.
Det ska finnas 3 variabler som håller hhv. '1'-tiden och '0'-tiden samt Arbetstiden.

I timer-ISR'n:
* Nolla timer-interrupt-bitten
* Räkna ner 'Arbetstiden'
* Kolla om 'Arbetstiden' är noll
* Vid 0:
* Byt läge på ut-pinnen
* Ladda data från '0'/'1'-variablen till 'Arbetstiden'
* Avslut ISR

Då kan du, vid att variera '0'-tiden och '1'-tiden styra PWM-utgången i steg om 0,1ms. Såklart kan du välja en annan upplösning och klara dig med kanske 1 byte till varje variabel, i mitt exempel behöver du att kunna spara upp till 410 (41ms * 10) men den delen kan du fila på själv.
ClasseMan
Inlägg: 176
Blev medlem: 9 juli 2004, 15:21:02
Ort: Karlskrona
Kontakt:

Inlägg av ClasseMan »

Kan du inte använda Delay_ms istället då om den är mer exakt eller är inte den heller bra?
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

ClasseMan: Delay_ms klarar inte variabler, men annars fungerar den bra.
Det går visserligen att löa med att man har olika delay_ms-rader som "aktiveras" (t.ex med en IF-rad), men den lösningen drar aningen för mycket kraft för att det ska vara en stabil lösning.

Icecap: Det låter mycket smidigt!

Xerxes: Har testat den varianten tidigare. MikroBasic har inline-asm, men med något begränasade asm-möjligheter. Har för mig att dessa delay-rutiner inte fungerade så bra.


Funderar på allvar att börja köra assembler, åtminstone till tidskritiska program, för MikroBasic börjar tyvärr kännas lite för begränsat och jag gillar att ha koll på vad som händer. Det mesta *går* visserligen att fixa i Basic, men på bekostnad av CPU-kraft.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Först,
Korta delay : 10-20 us.
Långa delay : > 1 ms.

:-)

Långa delays hanteras bäst med timers.

> *Vänta ett tag (mellan 1-40ms)
> *Vänta ett tag (mellan 0-40ms)

Menar du :

> *Vänta ett tag (mellan 1, 2, 3 ... 40ms)
> *Vänta ett tag (mellan 0, 1, 2 ... 40ms)

Förtydliga.

Icecap's lösning är så klart "rätt" om man ska köra programvaru PWM.
Och genom att använda timers och en snygg design på koden, så
blir inte en ASM lösning speciellt mycket krångligare en en "fixad"
Basic variant.

Icecap's lösning är även mycket enkel att utöka till flera utgångar. Det
blir väldigt lite extra kod i ISR'en för varje "kanal".

Själv håller på med en design som kommer att ha 30 oberoende
PWM utgångar (LED-dimmning) på en PIC18 processor, jag skulle
inte försöka fixa det i Basic... :-)
Användarvisningsbild
EagleSpirit
Inlägg: 1288
Blev medlem: 27 maj 2003, 23:15:48
Ort: Västerås
Kontakt:

Inlägg av EagleSpirit »

Jag testade en variant förut där jag räknade satte ett timerinterrupt på en smidig frekvens, t.ex. 10khz som Icecap. Sen hade jag en variabel (arbetstiden) som räknade ner varje gång den kom till interruptet. Varje gång arbetstiden blev 0 så satte den alla PWM-utgångar till 1. Därefter så jämfördes arbetstiden med alla PWM-variabler. Om de var lika så ändrades utgången till 0.

Lite lättare beskrivning:
Resetta timern
Räkna ner arbetstiden
Om arbetstiden = 0 så sätt alla utgångar till 1
Om arbetstiden = PWM duty 1 så sätt utgång 1 till 0
Om arbetstiden = PWM duty 2 så sätt utgång 2 till 0
....
Om arbetstiden = PWM duty 100 så sätt utgång 100 till 0
Avsluta interruptet

Metoden borde fungera som den ska men det kan vara så att den tar lite längre tid än Icecaps förslag i assembler eftersom en jämförelse tar några extra instruktioner. Jag körde det på en 18F så jag kunde använda compare file-instruktionen.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

> Korta delay : 10-20 us.
> Långa delay : > 1 ms.

sodjan:
Ok, då vet jag det. :)

> Förtydliga.

Gärna: :)
Förresten är max-tiden 39ms. Tänkte fel. :oops:
Men det jag menade var att "väntetiden" kan vara mellan 1-39ms lång. Dvs:

Kortaste duty-ration:
*Sätta en utgång hög
*Vänta 1ms
*Göra samma utgång låg
*Vänta 39ms
och till början igen..

Längsta duty-ration:
*Sätta en utgång hög
*Vänta 39ms
*Göra samma utgång låg
*Vänta 1ms.
och till början igen..


> Långa delays hanteras bäst med timers.

Då gör jag så. Tack för all "input".

Eaglespirit: Smidigt! Tack!
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Men det jag menade var att "väntetiden" kan vara mellan 1-39ms lång.

Det var ju helt uppenbart, men inte om det ska vara :

1, 2, 3 ... 37, 38, 39 ms, eller :

1.0, 1.1, 1.2, 1.3 .. 38.8, 38.9, 39.0 ms, eller kanske :

1.00, 1.01, 1.02, 1.03 ... 38.98, 38.99, 39.00 ms.

Är det också så att hela cykeltiden ör fast vid 40 ms ?
I så fall behöver du inte den ena variablen i Icecaps exempel.
Den andra tiden är ju alltid 40 minus den första tiden...
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Aha, det var så du menade. :)

Det ska vara 1, 2, 3 .... osv, ms. Om det sedan varierar med upp till några hundra µs gör ingenting.

Hela cykeltiden är fast vid 40ms.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

OK, en 1 ms timer-ISR räcker och "bara" 40 olika
PWM nivåer med andra ord. En fast cykeltid gör
att du enbart behöver antingen "1" eller "0"
variablen, den andra är ju "resten" upp till 40 ms...
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Låter mycket bra. Ska jobba med detta under kvällen så att jag kan det "flytande".
Skriv svar