Enable Javascript


Last Arduino/ESP8266 project (click to open)

User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

Voor als dit artikel je interesse wekt:
Dan vindt je hier alle Arduino Barebone projecten en andere Arduino artikelen.
Downloads voor Fritzing-bestanden, sketches (programma code) en andere Arduino projecten vindt je op mijn Download pagina


Citaat van http://arduino.cc/en/Reference/Millis:

millis()

Description

Returns the number of milliseconds since the Arduino board began running the current program. This number will overflow (go back to zero), after approximately 50 days.

Het probleem:
De functie millis() geeft een unsigned long terug en een Arduino UNO unsigned long is maximaal 4294967295. De timer zal, zonder tussentijdse start/reset, op de 49e dag een overflow veroorzaken en dan begint de interne timer weer bij 0 (4294967295 + 1 = 0). Dit kan dus eens in de 49 dagen een foute uitkomst opleveren indien je dan toevallig de overgang naar 0 ms mee maakt. Bijvoorbeeld: start bij 4294967000 ms, na 6000 ms geeft dat dan 5704 ms in plaats van 6000 ms terug. Na die ene foute weergave gaat het weer 49 dagen goed.
Voor de functie micros() treed dit probleem reeds na 71 minuten op.
Forums staan vol met de meest ingewikkelde en soms ook wel heel erg vreemde oplossingen.

Mijn oplossingen:
Arduino heeft er geen oplossing voor, maar je kunt natuurlijk wel testen of er overflow heeft plaats gevonden en, zo nodig, dan ook corrigeren.
Theoretisch gaat er nog wat tijd verloren tussen aanroep en uitkomst, maar voor millis() is dat te verwaarlozen (0.008 ms) en voor micros() wordt ook dat gecompenseerd (1 sec = 1.000 ms = 1.000.000 μs).
    unsigned long start = millis();
    ... doe iets ...
    unsigned long verschil = millis() - start;
wordt
    unsigned long start = millis();
    ... doe iets ...
    unsigned long verschil = getMillis(start);
Dat is in het gebruik zelf een gelijk aantal aan tekens.

Bestand timers.ino

/**** Een unsigned long is maximaal 4,294,967,295, verder ophogen
      veroorzaakt een overflow en dan beginnen de timers weer bij 0. 
      De timer functie millis() zal na 49 dagen een overflow veroorzaken.
      De timer functie micros() zal na 71 minuten een overflow veroorzaken.
      Onderstaande functies lossing dit probleem op.
 **** Geeft verschil tussen Start en Stop in ms of μs terug met overflowcompensatie 
 ####   millisStart = millis();
         ... doe iets ... 
        millisVerschil = getMillis(millisStart);
                         =========
 **** In setup() altijd eerst de functie initMicros() aanroepen voor je
      de functie getMicros() gaat gebruiken
 ####   microsStart = micros();
        ... doe iets ...
        microsVerschil = getMicros(microsStart);
                         =========
 **** LET OP bij Arduino's functie micros(): afhankelijk van board kan de resolutie anders zijn
      16 MHz board (bv. UNO) geeft het in stappen van 4 μs terug
      8 MHz board (bv. LilyPad) geeft het in stappen van 8 μs terug
*/

int _microsLostTime; // voor tijdcompensatie van getMicros() en timeCompensatie() 

unsigned long getMillis(unsigned long _start) {
  return timeCompensatie(_start, millis());
}

unsigned long getMicros(unsigned long _start) {
  return timeCompensatie(_start, micros() - _microsLostTime);
}  

unsigned long timeCompensatie(unsigned long _start, unsigned long _stop) {
  if(_stop < _start) // overflow=true, dus aanpassen
    return (unsigned long)4294967295 - _start + _stop + 1;
  else // overflow=false
    return _stop - _start; 
}

void initMicros() { 
  /* In setup() altijd eerst deze functie aanroepen voor je de functie getMicros() gaat gebruiken
     Dit om het tijdverlies van de functies getMicros() en timeCompensatie() te compenseren */ 
  unsigned long _start = micros();
  unsigned long _stop = micros();
  unsigned long _dummy = timeCompensatie(_start, _stop);
  _microsLostTime = micros() - _stop;
}

Bestand timersTesten.ino

void setup(){
  Serial.begin(9600);
  initMicros(); // altijd eerst hier aanroepen voor je de functie getMicros() gaat gebruiken 
}
void loop(){
  unsigned long start = millis(); 
  delay(10);
  unsigned long verschil = getMillis(start);
  Serial.print("millis: ");
  Serial.println(verschil);
  start = micros(); 
  delayMicroseconds(40);
  verschil = getMicros(start);
  Serial.print("micros: ");
  Serial.println(verschil);
  delay(1000);
}

Hier en daar een misser, maar zonder deze functies is dat ook zo.

unsigned long start = millis();
delay(10);
unsigned long verschil =
millis() - start;  //getMillis(start);
Serial.print("millis: ");
Serial.println(verschil);
start = micros(); delayMicroseconds(40);
verschil =
micros() - start;  //getMicros(start);
Serial.print("micros: ");
Serial.println(verschil);