Ge mig råd angående “multitasking”...

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Ge mig råd angående “multitasking”...

Inlägg av jonte_s »

Tjena.

Japp, som rubriken lyder… Behöver jag lite råd/tips på hur jag ska lägga upp koden när PIC:en ska utföra flera olika saker ”samtidigt”.

Ok. Vi säger att PIC:en tex. skall skicka och ta emot meddelanden (eget kodat, dvs. ej typ inbyggt USART, om det nu spelar någon roll i sammanhanget), polla ingångar, osv.

Hur ska man lägga upp koden? Jag har läst på vissa ställen att man kan göra det utan interrupt och på andra ställen med interrupt, men det känns som man vill använda interrupt!? Eller?
(Dock verkar de program utan interrupt inte så ”tidskritiska”, utan är mer periodiskt återkommande rutiner.)
Många säger att när man använder interrupt, så skall man så snabbt som möjligt lämna interruptrutinen, där man bara skall sätta någon variabel…, medans andra verkar skriva kod som tar ”lång” tid i interruptet.
Tankar kring detta?

Nu ett exempel:
Jag har gjort både en sändare och mottagare av Manchester-kodade meddelanden.
Det jag inte fattar är hur man gör rutiner som är ”tidskritiska”, utan att skriva iaf lite i interruptrutinen. Om man som jag ska skicka signaler med ca 900us mellan, hur gör man det utanför interruptrutinen?
Så som jag har det nu är att när jag får interrupt på TMR0, så har jag hela sändarkoden i interruptrutinen (typ en state-machine som inte ”väntar” någonstans).
Om man ”bara” hade satt en variabel i interruptrutinen som talar om för main-koden att ”nu ska du göra något som måste göras direkt!”, så går ju inte detta!? Hmmm.

Kom gärna med tips och förslag på hur man skall tackla Multitasking med PIC.

Här är min kod i interruptrutinen för sändaren. (Inte helt klart, men det fungerar):

Kod: Markera allt

void interrupt(void){
  //  TMR0 overflow interrupt. on TMR0 interrupt TOIF is set.
  if(INTCON.T0IF == 1){
    TMR0 = 120;    // börja att räkna upp till 444us igen.
    counter444us = counter444us + 1;
    
    if(counter444us == 2){// när vi har det såhär så dröjer det 889us innan start sekvensen börjar...
      counter444us = 0;
      switch(nextState){
        case StartSequence:
          TRISC.F2 = startBits >> counter_in_transmitFkn;     //TRISC.F2 = 1    stänger av PWM, dvs vi får en nolla.
          counter_in_transmitFkn--;
          if(counter_in_transmitFkn < 0){
            nextState = data;
            counter_in_transmitFkn = 15;
          }
        break;
        case Data:
          TRISC.F2 = byte_to_send_encoded_temp >> counter_in_transmitFkn;
          counter_in_transmitFkn--;
          if(counter_in_transmitFkn < 0){
            nextState = StartSequence;
            counter_in_transmitFkn = 3;
          }
        break;
      }
    } //end if(counter444us == 2)
    INTCON.T0IF = 0;      // reset flag
  }
}
mvh Jonas
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> när PIC:en ska utföra flera olika saker ”samtidigt”

Det kan den inte. En PIC kan bara göra *EN* sak i taget.

> så skall man så snabbt som möjligt lämna interruptrutinen,

Efter att ha gjort det som *måste* göras där, ja.

> medans andra verkar skriva kod som tar ”lång” tid i interruptet.

*I allmänhet* fel metod, men inte alltid...

> Om man som jag ska skicka signaler

Vad är en "signal" ???

Det rimliga är att göra det som ska göras "nu" och sedan sätta några
flaggor så att ISR'en vet vad den ska göra "nästa gång".
Det är kankse det du gör, jag vet inte...

EDIT:

> Om man som jag ska skicka signaler med ca 900us mellan,...

En ganska lång tid, för en PIC.

> hur gör man det utanför interruptrutinen?

Gör det i ISR'en. Men ligg inte kvar i ISR'en under hela 900 us intervallet.
Och ingen, vad är en "signal"... ??
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

En annan sak...

> TMR0 = 120; // börja att räkna upp till 444us igen.

Notera att *om* TMR0 redan har räknat en bit, beroende på hur länge sedan
det var som den slog runt h'FF' -> h'00, så kommer tiderna inte att bli stabila.
Du kan ju ha andra interrupt som ibland fördröjer bahandlingen av TMR0.

Det normala sättet är att *lägga till* ett värde till TMR0, då räknas automatiskt det
som den redan har gått av från totalen och du får mycket mindre variationer i tiderna.

> TMR0 = TMR0 + 120; // börja att räkna upp till 444us igen.

eller något i den stilen. Om TMR0 redan t.ex har räknat till 10, så kommer den
nu att sättas till 130 istället, och kommer lite snabbare till h'FF'...
Användarvisningsbild
Chribbe76
EF Sponsor
Inlägg: 1167
Blev medlem: 17 januari 2004, 22:43:17
Ort: Stockholm

Inlägg av Chribbe76 »

Hur mycket interruptrutinerna ska utföra är väldigt olika beroende på vad som ska göras.
Mina projekt är iaf i regel uppbyggda med några få interrupt för det tidskritiska och huvudloopen tar över och forsätter processerna som interrupten startat.

Om man har ett interrupt som ska göra något tidskritiskt som ska trigga en ny process men man inte vill polla triggningen i huvudloopen kan man ganska snyggt låta högprio-int sätta flaggan till ett lågprio-int så att det nya interruptet "tar över" efter att högprio-int har avslutats.

Om man har flera interruptkällor som man vill tilldela olika prioritet så har Pic18 högprio och lågprio i hårdvaran.
Dessa 2 prio-nivåer räcker oftast men behöver man fler går det att göra det med mjukvara.

I vissa fall kan det vara nödvändigt att helt enkelt ha en högfrekvent tidsinterrupt där en rad olika funktioner pollar diverse signaler för att allt ska jobba "samtidigt".

Om du har en specifik applikation som du behöver hjälp med så kan du säkert få svar på hur man kan lägga upp det, om du förklarar exakt vad som ska göras och vilka timingkrav du har.
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

En liten kommentar till det jag skrev tidigare...

> TMR0 = TMR0 + 120; // börja att räkna upp till 444us igen.

För att det där ska fungera bra så krävs det att compilern verkligen
gör en "ADDWF TMR0, F" och inte först läser TMR0 till en temp-variabel
som sedan skrivs tillbaka till TMR0. Då blir det fel igen.

Förutsatt att timingen är tillräckligt kritisk för att det ska spela någon roll.

Vad compilern gör ser man i LST eller ASM filen, vad den nu skapar...
Användarvisningsbild
Icecap
Inlägg: 26623
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

"Det jag inte fattar är hur man gör rutiner som är ”tidskritiska”, utan att skriva iaf lite i interruptrutinen."

Precis som sodjan skriver ska man ANVÄNDA ISR'n till att göra det som ska göras. Exempel: Jag håller ju på med en pelletsbrännare och där är ju en sjukt massa processer som kör men ALL reglering, motorer av/på osv. styrs från timer interrupt-rutinen!

Det är samtidig den rutin med flest rader i hela jävla programmet!

Ändå är den mycket snabb, helt enkelt för att det INTE finns en enda "vänta på något", ska något aktiveras när "det är klart" sätter jag en flagga istället och sedan får main-delen tugga på det. Samma timer-interrupt tar hand om knappsats, ett antal time-out'er osv. så det är inte bara en lite snudd.
Användarvisningsbild
persika
EF Sponsor
Inlägg: 1540
Blev medlem: 31 juli 2006, 22:14:37
Ort: Österlen, Skåne

Inlägg av persika »

Gjorde en gång ett program för PIC 12F629 som stryde 3 pwm-utgångar och tog emot seriell-data (RS232) på en ingång, allt stårt av interrupt från timer, funkade bra.
Noggranna tidsfördröjningar kan man inte ha i huvudprogrammet om man har interrupt, isf fall får det oxå styra från timer på nåt sätt.
Rollo
Inlägg: 217
Blev medlem: 2 januari 2004, 19:23:29

Inlägg av Rollo »

sodjan skrev:En annan sak...

> TMR0 = 120; // börja att räkna upp till 444us igen.

Notera att *om* TMR0 redan har räknat en bit, beroende på hur länge sedan
det var som den slog runt h'FF' -> h'00, så kommer tiderna inte att bli stabila.
Du kan ju ha andra interrupt som ibland fördröjer bahandlingen av TMR0.

Det normala sättet är att *lägga till* ett värde till TMR0, då räknas automatiskt det
som den redan har gått av från totalen och du får mycket mindre variationer i tiderna.

> TMR0 = TMR0 + 120; // börja att räkna upp till 444us igen.

eller något i den stilen. Om TMR0 redan t.ex har räknat till 10, så kommer den
nu att sättas till 130 istället, och kommer lite snabbare till h'FF'...
Sodjan, det är nog ingen fara.

Om jag inte misstar mig så har den kommentaren bara råkat hamna på fel rad. Raden nedanför står det "counter444us = counter444us + 1; " vilket verkar stämma bättre in på vad kommentaren beskriver.

Och en sista grej :)
Var denna kommentaren verkligen nödvändig?

> när PIC:en ska utföra flera olika saker ”samtidigt”

Det kan den inte. En PIC kan bara göra *EN* sak i taget.



Ha det!
Användarvisningsbild
Icecap
Inlägg: 26623
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag anser att den kommentar är essentiell, en del fattar inte hur det egentligen fungerar.

Det svåra är inte att göra ett program som fungerar med interrupt osv. det svåra är att få kommunikationen till att fungera mellan de olika delarna, speciellt med tanke på att ett interrupt kommer när som helst under programexekveringen.
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Alltså, om man inte förstår skillnaden mellan "samtidigt" och t.ex
"inom 100us" (eller whatever) så kommer man *aldrig* att få till det.

Att säga att något ska ske "samtidigt" är en fullständigt värdelös
uppgift när man ska fundera på en lösning på ett problem. Och det visar
bara att frågaren inte har "tänkt klart" innan frågan ställdes...

Så "samtidigt" måste kvantifieras i reela termer normalt uttryckt i någon
lämplig tidsenhet.

> Sodjan, det är nog ingen fara.

Det, och resten, förstår jag inte alls...

> Raden nedanför står det "counter444us = counter444us + 1;
> " vilket verkar stämma bättre in på vad kommentaren beskriver.

Det tror jag inte alls.
Variablen counter444us räknar *antalet* 444 us perioder, inte längden
på 444 us perioden i sig, vilket är det som min kommentar handlar om.
Rollo
Inlägg: 217
Blev medlem: 2 januari 2004, 19:23:29

Inlägg av Rollo »

Sodjan! Jag ber om ursäkt för mitt inlägg angående "counter444us = counter444us + 1; ". Helt och hållet mitt fel.

Däremot håller jag fortfarande inte dig (eller Icecap) angående jontes definition på "samtidigt". I och med hans "" förstår man att han är medveten om att en PIC bara kan göra EN sak samtidigt.

Då jonte inte nämner några krav på under vilken tidsperiod allt skall hinna exekveras, kan vi ju dra slutsatsen av att det inte spelar någon roll ("inom 100us" (eller whatever) som du själv uttryckte det :)). Givetvis är målet att denna tidsperiod skall bli så kort som möjligt.

Kanske är jag som inte tar hans inlägg tillräckligt bokstavligt. Men jag hoppas vi alla kan vara vänner ändå! :wink:
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> angående jontes definition på "samtidigt"...

Problemet är att det *saknas* definition av vad Jonte menar med "samtidigt".

> Då jonte inte nämner några krav på under vilken tidsperiod allt skall hinna exekveras,

Precis, där är problemet.

> kan vi ju dra slutsatsen av att det inte spelar någon roll...

Det gör det alltid... :-)

> Givetvis är målet att denna tidsperiod skall bli så kort som möjligt.

Nej, det är det inte.
Den ska vara *tillräckligt* kort ( för att resten av applikatione ska fungera).
Vad som är "tillräckligt" måste analyseras och bestämmas.

"Så kort som möjligt" är ett lika dåligt kreterium som "samtidigt". :-)
Och lika värdelöst att designa en applikation utifrån. Man måste ju veta
när "det räcker", så att säga...

> Kanske är jag som inte tar hans inlägg tillräckligt bokstavligt.

Finns det något annat sätt på ett *skriftligt* forum ? :-)
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Oj, oj, här är diskussionen i full gång…

Mitt inlägg var mer en undran hur ”man”, eller hur folk brukar lösa detta med multitasking i en PIC rent allmänt. Sedan gav jag kanske ett dumt exempel på vad jag själv försökte lösa (manchester-sändare…).

Jag vet att en PIC ej kan göra olika saker samtidigt. Med ”samtidigt” menade jag alltså så att det ”ser ut som att den gör flera saker samtidigt”. Jag gav inga direkt timingkrav eftersom jag inte ens tänkt så långt…

Sodjan:
Hmm, dåligt uttryckt av mig, men med signaler menade jag att jag ska skicka ettor och nollor med 900us mellanrum. Hoppas du förstår.
Tack för tipset med ” TMR0 = TMR0 + 120”.
Jag ligger alltså inte kvar i interruptrutinen hela 900us, utan det som görs där tar uppskattningsvis runt 30us.

Tack för tipsen från övriga skribenter…
Hittade denna sida:http://www.microchipc.com/Hi-Tech_C_multitask som förklarar en hel del.
Jag testar sidans ”programskal” just nu till sändar-applikationen. Återkommer med fler specifika frågor när jag har funderat och programmerat lite mer.

Kom gärna med fler tips och råd, gärna lite exempelkoder eller länkar.

mvh Jonas

(Jag programmerar i C (mikroC), men kan väl assembler någorlunda bra, och använder just nu PICF887A. Om någon undrar)
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Oj, oj, här är diskussionen i full gång…

Ja visst är det härligt !! :-)

> ...att jag ska skicka ettor och nollor med 900us mellanrum.

Japp, "nästan" en hel ms, *massor* av tid, med andra ord. :-)

Jag tror att du gör helt rätt i att ha ett par flaggor som
talar om för ISR'en vad den gjorde förra gången och vad den
ska göra denna gång. Gör det som behövs, och lämna sedan ISR'en.

Men som det ser ut så kommer du ju tillbaka till ISR'en varje (ca)
433 us, men det är bara varannan gång som du faktiskt gör något.
Är det p.g.a av att du inte hittade ett sätt att konfigurera TMR0 för
rätt intervall dirtekt ? Har du kollat om någon annan timer skulle
kunna fungera bättre, TMR1 som kan köras som 16 bitar t.ex ?

Dessutom, om det alltid är varannan gång det sha hända något, så
räcker det med en bit-flagga 1/0 för att hålla reda på det. Då blir det
lite mindre med uppräkningar och jämförelser med "2"...

Jag ser att det är en 887A, och den har ju bra med resurser, så detta ska
inte vara något problem att fixa.

Sidan du länkade till verkar väl vettig, även om jag tror att Salvo kanske
är att "ta i" lite för just denna applikation. Det finns ju också alltid en risk
med dessa "mini-OS" att man tappar kontrollen över timing m.m...

Det finns en sak på sidan som jag inte riktigt är överens om.
*Jag* tycker att koden i main() är "foreground" och interruptet är "background".
Men andra tycker tvärtom... :-)
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Japp. Anledningen till att jag använder en räknare är för att jag inte lyckades få TMR1 att fungera, men nu har jag fått det! Så skönt! Har försökt få igång den så #!%& länge. Så i mitt nuvarande program använder jag TMR1. (Använder iof andra räknare till annat...)
Ska posta kod lite senare...
Jag använder alltså inte Salvo, utan koden som står på den sidan. Men Salvo eller något liknande verkar ju ganska skönt att använda (kanske till lite kraftigare PIC:ar), men det får bli vid ett senare tillfälle.
Skriv svar