tickräknare problem

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

tickräknare problem

Inlägg av dangraf »

Jag håller på och programmerar periodiska funktioner och har just nu stött på lite problem som jag inte riktigt blir klok på hur jag ska gå runt.

koden skall göra en given sak t.ex varje 0.5 sekund. Det är en massa andra grejjer som skall göras samtidigt vilket har gjort att jag valt att använda en global tickräknare.

Kod: Markera allt

//16Hz Counter

timerinterrupt(void)
{
  wTicks++;
}

jag har även en funktion som ser i stort sätt ut som:

Kod: Markera allt

void function(void)
{
  static int Deadline;
  
  if(wTicks == Deadline)
  {
    do_something();
   }
}
eftersom det finns risk att jag missar min deadline så skulle jag vilja skriva:

if(wTicks>=Deadline)

Men detta fungerar ju inte när tickräknaren slår över från 0xffff->0x0000

Jag är lite trött i huvudet nu och kommer inte på några smarta sätt att gå runt detta problem.

Hur hade ni gjort??
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

Varför sätter du inte interruptets period till 0,5 s då, eller sätter din tickräknare i ISRen?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Processor ?
Utv verktyg ?

Gärna i ämnesraden, så att man inte i onödan öppnar "fel" trådar... :-)
henkebenke
Inlägg: 516
Blev medlem: 31 maj 2003, 10:42:37
Ort: Helsingborg

Inlägg av henkebenke »

Kolla deadline i ISRen, sätt en global variabel typ deadLineReached = 1 och nollställ räknaren. Kolla sedan deadLineReached i main-loopen istället.
Användarvisningsbild
AndLi
Inlägg: 18274
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Inlägg av AndLi »

sodjan skrev:Processor ?
Utv verktyg ?

Gärna i ämnesraden, så att man inte i onödan öppnar "fel" trådar... :-)
Är inte detta problem generellt för alla processorer och utv verktyg? Det känns som rätt överflödig information.. (Visst det kan ju hjälpa och veta om man kan sätta timern till så långa tidsintervall som 0.5 sek, men annars känns den informationen överflödig)

Jag skulle rösta på henkebenkes förslag för övrigt, om du nu behöver timern till andra saker också med andra intervall...
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

jag använder mig av en pic16f88 där det bara finns en interrupt (inga lager).
Interrupten används till en högre prioriterad process (radio med TDMA) där det är väldigt viktigt att man håller tiderna.
Jag vet att man egentligen skulle använda sig av ett RTOS för att lösa problemet lättast, men jag tror inte att det går i detta fallet eftersom jag inte har tid/pengar eller kunskap att skiva/köpa ett sådant till pic processorer.

Däför har jag valt att bara ticka upp en räknare i interrupten vilket går väldigt kvickt. Jag hade väldigt gärna viljat hitta ett sätt att använda den på ett vettigt sätt, för att i slutändan går det inte att hitta en tickräknare som inte slår över.

Jag vill helst använda endast en global tickräknare som jag kan anvädnda av flera olika processer istället för att ha en variabel som tickar ner för varje process, vilket tenderar till en massa olika tickräknare och en interrupt som går trögare o trögare.

Om jag skulle nollställa tickräknaren så tappar väl resten av mina processer tidsuppfattningen, eller finns det nått smart sätt att lösa det på oxå?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> jag använder mig av en pic16f88 där det bara finns en interrupt (inga lager).

16F88 har 12 olika interrupt, Dock *en* vektor och *en* prioritet, dessa får man fixa själv.

> Interrupten används till en högre prioriterad process...

Jag är inte säker på vad du mernar här. Interruptet används ju inte till speciellt mycket alls. På vilket sätt då prioriterad ?

> Jag vet att man egentligen skulle använda sig av ett RTOS för att lösa problemet lättast,

Det finns ingenting som ett RTOS (vilket låter som en väldig over-kill på en 16F88 i alla fall) som du inte kan göra själv. Ett RTOS tillför inte processorn något nytt, snarare bara en massa overhead. Om processorn inte har tillräckligt med cykler nu, så blir det inte bättre med ett RTOS. Det som skulle kunna ge dig mer flexibilitet och möjlighet att trimma saker och ting bättre, är att köra det hela i assembler.

När det gäller att göra saker i ISRen eller inte, så finns det två olika aspekter på det.

Först "latency", alltså hur länge kan main-koden vänta på att interruptet skall köra klart ? Och gäller detta *hela* main koden ? interruptet körs ju rellativt sällan (bara 16 gr/sek), så om det finns kristikt kod i main, så kan man tillfälligt stänga av interrupten. Detta ger lite "jitter" i wTicks och jag vet inte hur mycket som kan accepteras.

Sedan är det ju så att processorn bara har ett visst antal instruktions cykler. Man kan alltså inte få mer gjort (totalt sätt) genom att flytta kod till eller från ISR'en. Så om punkt 1 ovan inte är något problem, så kan det ofta vara bättre att lägga kod som i alla fall skall köras i samband med interruptet, just i ISR'en.

> Jag vill helst använda endast en global tickräknare som jag kan anvädnda av flera olika processer istället för att ha en variabel som tickar ner för varje process...

Men, behöver inte desa olika "processer" ha en variabel som "tickar ner" i alla fall ? Jag ser inte vad du förlorar på att låta ISR'en ticka ner dom, det borde i alla fall inte bli fler räknare.

> och en interrupt som går trögare o trögare.

Men å andra sidan behöver ju resten av koden göra lite mindre, vilket borde ta ut varandra.

En sak, jag antar att du kör i 20 Mhz ?

Det är lite svårt att säga mer utan att känna till mer om hela applikationen, men det känns som om ISR'en kanske skulle kunna göra lite mer. D.v.s att hålla reda på de olika variablerna/ner-räknarna, och sätta flaggor när "tiden är inne" för de olika processerna. Main-loopen kan sedan ligga och polla dessa flaggor och anropa de olika processerna vid behov (när resp flagga är satt).
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Jag har inte full koll på koden till TDMA eftresom jag inte skrivitprotokollet själv. Jag har inte lust att ändra något som redan fungerar.

Det finns bara en interrupt, där man får maska ut vilken interrupt som man vill åt, det var så jag menade.

Jag har antagligen en hel massa tid för att köra min kod, men jag vet inte exakt när. Vilket betyder att jag kan inte ha en fet interrupt som stör hela tiden när TDMA funktionerna är igång och kör.

Processorn kör på en 4Mhz oscillator, för att inte dra för mycket ström.

Om jag lägger tickräknarna utanför ISRen så gör processorn det den ska utan att timerinterruptet stör.
De andra processerna som skall hålla tiden är inte alls lika kritiska. de utför åtgärder som att blinka med en lysdiod, kolla hur länge en knapp varit nertryckt osv.

Dessutom får man en mycket mer flexibel kod om man vill lägga till/ ta bort en funktion om man har en enda variabel som styr allt. Man slipper gå in på en massa ställen och initiera, definiera och lägga till/tabort tickräknare på olika ställen ikoden.

Om det är möjligt att ha en enda global tickräknare, så föredrar jag det. Någon som vet hur man skulle kunna göra?

Jag har funderat på nån flagga som skall nollställas om tickräknaren slår över. Eller på nått sätt lura tickräknaren genom att lägga till konstant och sen jämföra eller nått. Men har inte kommit på nått bra.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Hm... TDMA... Nu blev jag nyfiken! ;)

Mvh
speakman
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

OK.

> "Jag har inte full koll på koden till TDMA eftresom jag inte skrivit protokollet själv. Jag har inte lust att ändra något som redan fungerar."

OK, inte ändra kanske, men utan en bra bild av vilka krav som TDMA funktionen ställer, så är det lite svårt att designa övriga delar så att de "spelar ihop" utan att trampa på varandra.

> "en fet interrupt som stör hela tiden"

"Hela tiden" ?? Det körs ju bara 16 gånger per sekund ? Och vi talar bara om några tiotal mikrosekunder (med reservation för att jag inte vet vilken overhead som C kompilatorn lägger till...)

> "Processorn kör på en 4Mhz oscillator, för att inte dra för mycket ström."

En extern oscillator eller menar du kristall ? Är det höga krav på exakt frekvens ? Har du tittat på oscillatorn i F88'an ? Du har många möjigheter att t.ex "växla" hastigheten upp och ner allt eftersom behovet av processor cykler varierar. På så sätt kan man få mer fart när det behövs, och lägre strömförbrukning när det är OK. Är det batteridrivet ?

De tillfällen då "TDMA funktionerna är igång och kör", hur långa perioder är det ? Och hur ofta kommer de ? Eller vet man inte det ?

En annan sak, i ditt första inlägg har du en exempel funktion "function". *Inne* i denna kollas wTicks och Deadline, men hur och när anropas "function" ? Den måste ju anropas oavsett om Deadline är uppnådd eller inte, eller hur ? Och dessutom ganska ofta för att inte få för långa fördröjningar efter att Deadline är uppnådd (eller att missa Deadline helt). Det verkar som om det blir mycket overhead med denna lösning.
Min tanke är att kollen av (t.ex) Deadline ligger i main koden, och att "function" bara anropas om "Deadline" är uppnådd, inte annars.

> "Om det är möjligt att ha en enda global tickräknare, så föredrar jag det. Någon som vet hur man skulle kunna göra?"

Tja, i princip är det väll som du har gjort (eventuellt med en flytt av "if(wTicks == Deadline)" till main(), men det är ingen snygg lösning...

Slutligen, jag har utgått från att du kommer att ha fler än en "deadline" ! Om det inte är så, så hamnar det hela i lite annat läge...
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

Ja, det är många olika deadlines som skall hållas.

if(wTicks == Deadline)" håller inte eftersom jag har testat och ibland så hinner inte processorn fram till if-satsen efter att tickräknaren räknat upp 2ggr och då skiter sig allt.

jag kör på den interna oscillatorn i denna applikationen, men den är inte speciellt exakt. Och om man skulle växla frekvenser så tar det tydligen lite tid innan den nya frekvensen uppnåtts vilket ger ännu mindre exakthet i tidsmätningen.

16ggr är inte många gånger per sekund, men om man har många tickräknare och funktioner som skall köras vid varje timerinterrupt samtidigt som radioprotokollet skall hållas, så tar det tillräckligt lång tid för att störa, jag har testat, och det fungerar inte.

Men om jag hade lyckats fixa till raden med att :

if(wTicks>=deadline)

så hade många av mina problem lösts utan att jag egentligen behöver skriva om särskillt mycket kod
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

Vad var det för fel på henkebenke förslag?
Kolla även om räknaren slagit över i din ISR. När den slår över sätter du en status-bit till 1, som sedan avläses i main-loopen och nollställs när du utför rätt sak. Hela kalaset tar inte många instruktioner extra i asm räknat.
dangraf
Inlägg: 530
Blev medlem: 9 juni 2003, 15:30:56
Ort: göteborg

Inlägg av dangraf »

problemet med henkebenkeslag att kolla deadlinen i ISRen är:

Vilken av alla mina deadlines skall jämföra med? om jag nollställer tickräknaren när den nått närmsta deadline kommer den aldrig nå de högre "dödslinjerna". Alternativt kommer jag få räkna om alla mina deadlines.

Dessutom så tar den inte hänsyn till tidsförskjutningen. Låt säga att jag missar min deadline med 2 ticks, innan jag kommer till funktionen och når if-statsen "deadline_reached"
Eftersom jag inte har koll på hur längesedan jag nådde min deadline, kan jag inte kompsensera för detta när jag sätter min nya deadline. Min periodiska funktion kommer att bli 2 ticks förskjuten i tiden vilket kan bli en ganska grov föskjutning i slutändan.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Vilken av alla mina deadlines skall jämföra med?

Jämföra ?
Varje "deadline" är en räknare som räknar ner mot noll.
När en deadline = 0, så har du "nått deadline". Gör det som skall göras och återställ aktuell deadline = nästa intervall.

> om jag nollställer tickräknaren

Alltså wTicks ? Den behövs inte alls, så vitt jag kan förstå...

> Dessutom så tar den inte hänsyn till tidsförskjutningen.

Vilken tidsförskjutning ?

> Låt säga att jag missar min deadline med 2 ticks,

Du *kan* inte missa en deadline ! Alla deadlines kollas i "ticks-ISRen". Det är ju just det som är fördelen !

> Eftersom jag inte har koll på hur längesedan jag nådde min deadline, kan jag inte kompsensera för detta när jag sätter min nya deadline. Min periodiska funktion kommer att bli 2 ticks förskjuten i tiden vilket kan bli en ganska grov föskjutning i slutändan.

Men, varje "ticks" går ju bara 16 gr/sek. Du har alltså ca 62.500 instruktionscykler (vid 4 Mhz) på dig att komma från ISR'en till anrop av din funktion.

Hur sätts de nya deadline ? Är det ett fast intervall för varje deadline ? I så fall är det väll bara att ladda om deadline-räknaren i ISR'en !? Om inte så kommer ju de två "extra" ticksen hur som heslt att räkna ner deadline räknarna två extra steg och det är bara att lägga till det när det är dags att beräkna en ny deadline.

Så när du sätter en ny deadline så ser du ju om det har gått ett eller ett par ticks extra sedan förra deadline "gick ut" genom att deadline har blivit -1 eller -2. Plussa bara på ditt nya deadline, så kommer det att kompesneras automatiskt. Du behöver faktiskt inte ha någon speciell kod som kollar om du har missat ticks, additionen kommer att fixa det automatiskt.

Men, hela detta resonemang kan ju falla p.g.a någon egenhet i din applikation som jag inte känner till. Jag kan bara gå på vad du har berättat hittills... :-)
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg av vfr »

Visst är det lösbart!

Deadline måste givetvis räknas upp med periodtiden efter varje gång tiden löpt ut (typ Deadline += Period), men det vet du säkert. Förutsätter man det så skulle man kunna göra något liknande det här:

Kod: Markera allt

function()
{
   if((wTicks - DeadLine) < Period)
   {
      // Doyourstuff;
      Deadline += Period;
   }
}
OBS! Denna kod är egentligen pseudokod baserad på att aritmetiken sker osignerat. Troligen enklast att implementera i asm eftersom C brukar utföra all aritmetik signerat. Har själv kört liknande detta i asm många ggr.

Jag håller med dangraf att vid vissa tillfällen är detta smidigt. Största fördelen enligt mig, är att man kan bygga en enkel ISR som man sedan inte behöver pilla i överhuvudtaget när man lägger till flera deadlines samtidigt som den inte kan "missas" som i ursprungsexemplet. D.v.s det är lätt att bygga fristående moduler. Däremot vet jag inte om den är absolut bäst vad gäller latency och CPU-cykler, troligtvis inte.
Skriv svar