Millis()

Fra Holstebro HTX Wiki
Skift til: navigering, søgning

millis()[1] er en grundlæggende struktur i Arduino-miljøet, hvor man kan få en tidsmåling i millisekunder.

Funktionen har en opløsning på 1ms og den returnerer en variabel i en unsigned long, hvilket betyder at de løber over efter ca. 50 dage, det er man nødt til at tage højde for, hvis programmet skal fungere i længere tid.

Hvis man måler for den tid det tager at foretage et kald til millis(), så vil det i gennemsnit tage 1,19μs. Dette er man nødt til at tage med, hvis man ønsker at måle relativt præcist ved hjælp af kode. I denne tidsmåling er der taget højde for at loop-instruktionen tager 0,312μs for hvert loop.

Koden anvendt til denne test ligger i Denne ZIP-fil.

Overflow af millis()

Enhver variabel der tælles opad vil overflowe på et tidspunkt

Typen millis() returnerer er unsigned long fordi den lagres i 2^32 bits og kan således tælle fra 0 til 4294967295.

Hvis man regner på det, så er det 49,710 dages, altså 49 dage, 17 timer, 2 minutter og 47 sekunder, så det er ikke noget man vil opleve i en normal test, men produkter der skal kunne fungere i længere tid er nødt til at tage højde for det.

Håndtering af millis() omkring overflow[2]

Den umiddelbare måde at skrive koden på, er at man sætter en variabel til det tidspunkt hvor det næste overflow sker, og tester om millis() bliver større.

Det fungerer også fint, lige indtil man er omkring tidspunktet for overflow.

Dette har dog en uheldig sideeffekt når man lægger intervallet til og det næste tidspunkt giver overflow, så er det et lille tal, og så vil millis() være større indtil den løber over, så det vil gøre at man får lagt intervallet til hver gang man kommer forbi, hvilket virker meget uheldigt. Det vil rette sig ind igen når millis() er løbet over, men der vil gå den tid som er blevet lagt i de ekstra gange koden er kommet forbi.

Løsningen er at man i stedet trækker start-tidspunktet fra millis() og så sammenligner med intervallet. Denne subtraktion vil altid give et lille tal, også selvom millis() er løbet over.

Koden kan se ud som følger:

unsigned long startTid = 0;
const unsigned long interval = 1000;

....

  if ((millis() - startTid) > interval) {
    startTid += interval;
    ....
  }

Nulstilling af millis()[3]

Normalt vil det svaret på hvordan man nulstiller millis() være det gør man ikke. Man udnytter de teknikker der er angivet ovenfor, for at kunne håndtere tingene korrekt, så vil det ikke være nødvendigt at nulstille.

Skulle man alligevel have ønsket om at kunne gøre det, så kan man tiltvinge sig adgang - man skal bare sørge for at gøre det korrekt.

Den interne variabel man skal have fat i skal erklæres inden setup(). Dette gøres i følgende kode:

extern volatile unsigned long timer0_millis;

Når man vil nulstille denne variabel kan man ikke bare sætte den = 0, da millis() bliver opdateret af interrupt og variablen består af flere bytes, så man kan risikere at man kun får nulstillet en del af variablen. Dette forhindre ved at nulstille på følgende måde:

noInterrupts ();
timer0_millis = 0;
interrupts ();

Referencer

  1. Arduino reference om millis()
  2. millis Overflow fra Gammon Forum
  3. Resetting millis() to zero fra Arduinos forum