Tijdwaarneming

Arduino specifieke Software
Berichten: 3
Geregistreerd: 24 Nov 2017, 18:17

Tijdwaarneming

Berichtdoor PatrickW » 07 Dec 2017, 13:07

Hoi alle,

Ik ben nieuw op het forum, zal me dus eerst even voorstellen. Mijn naam is Patrick en 45 jaar en heb mijn eerste arduino aangeschaft. In het verleden heb ik wel wat met HTML/CSS/PHP en Javascript gedaan, dus programmeren is niet geheel nieuw voor mij.

Ik ben voor me zelf een project gestart, om een tijdwaarneming bij paarden wedstrijden te maken. Het doel is dat de tijdwaarneming middels een IR lichtsluis (draadloos) gestart en gestopt gaat wordt.
Het is voor mij echt een leer project, het is dus ook zeker niet de bedoeling dat jullie dit volledig voor gaan kauwen. Ik wil het leren door dingen zelf uit te zoeken, en waar iets mij niet duidelijk is een vraag te kunnen stellen.

Heb het project in delen opgesplitst, en als basis begonnen met het tijdwaarnemingsgedeelte.

Dit is wat ik tot nu toe gevonden/geschreven hebt.
Code: Alles selecteren
/* Een Programma om een tijdwaarneming te maken
 * 
 */

unsigned long previousTimer = 0;                // Variable om de laatste tijd in weg te schrijven
unsigned long currentTimer = 0;                 // Variable om de huidige tijd in weg te schrijven

unsigned int hundredthSecond = 0;               // Variable om de 100ste sec in weg te schrijven
unsigned int second = 0;                        // Variable om de secondens in weg te schrijven

const int buttonStart = 2;                      // De startknop aan pin 2 koppelen
const int buttonStop = 3;                       // De stopknop aan pin 3 koppelen
const int buttonReset = 4;                      // De resetknop aan pin 4 koppelen

int timerRun = false;                           // Variable om te kijken of de timer moet lopen of stil staan

void setup() {
  // put your setup code here, to run once:
    pinMode (buttonStart, INPUT);               // De pin van de startknop als ingang te maken
    pinMode (buttonStop, INPUT);                // De pin van de stopknop als ingang te maken
    pinMode (buttonReset, INPUT);               // De pin van da resetknop als ingang te maken
}

void loop() {
  // put your main code here, to run repeatedly:

    timer();                                    // Naar de timer functie sturen
    buttonInput();                              // Naar de buttonInput functie sturen
}

void buttonInput () {
    if (buttonStart == HIGH) {                  // Kijken of de startknop is in gedrukt
        timerRun = true;                        // Variable timerRun op true zetten, de timer gaat nu lopen
    }

    if (buttonStop == HIGH) {                   // Kijken of de stopknop is in gedrukt
        timerRun = false;                       // Variable timerRun op false zetten, de timer moet nu stil gaan staan
    }

    if (buttonReset == HIGH) {                  // Kijken of de resetknop is ingedrukt
        if (timerRun == false) {                // Kijken of de timerRun loopt of stil staat. Als de timer loopt, niks doen. Als de timer stil staat, de variable gaan resetten
            currentTimer = 0;                   // Resetten van de variable currentTimer.
            previousTimer = 0;                  // Resetten van de variable previousTimer.
            hundredthSecond = 0;                // Resetten van de variable hundredthSecond. 100ste secondens weer op 0 zetten
            second = 0;                         // Resetten van de variable second. De secondens weer op 0 zetten
        }
    }
}

void timer() {
  // timer functie

    if (timerRun == true) {
        currentTimer = millis();                      // Variable currentTime de huidige waarden van de millis funtie geven

        if (currentTimer - previousTimer >= 10) {     // Kijken of de currendTimer 10 sec groter is dan de previousTimer.
            previousTimer = currentTimer;             // previousTimer gelijk zetten de currentTimer, om de volgende 10 sec te kunnen verglijken

            hundredthSecond ++;                       // Bij de 100ste secondes 1 optellen

            if (hundredthSecond >= 100) {             // Kijken of de 100ste secondes groter wordt dan 100
                hundredthSecond = 0;                  // Bij groter worden dan 100, terug op 0 zetten
                second ++;                            // Bij de secondes 1 optellen
            }
        }
    }
}

void timeDisplay() {
  // Weergave van de tijd op Led display
   
   
}


En dan nu mijn vragen:
Is de code die ik nu heb een goede basis, ben ik dingen vergeten of kan ik het beter op een andere manier doen?
Kan ik de timer mbv Milles() goed gebruiken of is de timer interrupt een betere keus?


Graag jullie mening, daar kan ik alleen maar van leren.

mvg Patrick

Advertisement

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Tijdwaarneming

Berichtdoor Koepel » 07 Dec 2017, 13:25

Hallo, en welkom op dit forum.

Javascript is een mooie basis voor de 'c' taal. Arduino is 'c' en 'c++', maar dat merk je vanzelf.

Welke editor gebruik je ?
De code voelt aan alsof je niet de Arduino IDE gebruikt.

Kun je beschrijven wat dit doet:
Code: Alles selecteren
  if (buttonStart == HIGH)                    // Kijken of de startknop is in gedrukt

Spoiler: De 'buttonStart' is een variabele. Het is het pin nummer. Het heeft de waarde 2. Ik vermoed dat 2 niet gelijk is aan HIGH. Kijk eens hier: https://www.arduino.cc/reference/en/language/functions/digital-io/digitalread/.

Het gebruik van millis() is goed, maar je hebt iets gemist.
Wie zet de 'previousTimer' als er op de knop wordt gedrukt ?
Het starten van een software timer met millis() bestaat uit twee regels:
Code: Alles selecteren
  if ( ...
  {
    timerRun = true;                        // Variable timerRun op true zetten, de timer gaat nu lopen
    prevousTimer = millis();
  }
Ik noem dat vaak een 'timestamp' van dat moment nemen.

Je gebruikt een 'int' met 'true' en 'false'. Daar is een type voor: boolean.
Code: Alles selecteren
boolean timerRun = false;                           // Variable om te kijken of de timer moet lopen of stil staan


De tijd gaat uit sync lopen.
Wanneer je deze regel doet:
Code: Alles selecteren
      previousTimer = currentTimer;             // previousTimer gelijk zetten de currentTimer, om de volgende 10 sec te kunnen verglijken
Dan krijgt 'previousTimer' de waarde die millis() kort daarvoor had. Stel dat er een interrupt kwam of andere code waardoor millis() even vertraagd wordt. Dan loop je daarna achter. Je kunt in de pas blijven met de tijd, door 'previousTimer' te verhogen met de stap van 10ms.
Code: Alles selecteren
previousTimer += 10;
Op die manier heb je opeens de nauwkeurigheid van het X-tal op het Arduino board.

Om over na te denken: Wat gebeurt er als de code ergens 100 ms vertraagd ? Hoe wordt dan de tijd opgehoogd ?

Berichten: 3
Geregistreerd: 24 Nov 2017, 18:17

Re: Tijdwaarneming

Berichtdoor PatrickW » 07 Dec 2017, 14:50

Hoi Koepel,

Dankje voor het reageren.

Welke editor gebruik je ?
De code voelt aan alsof je niet de Arduino IDE gebruikt.

Ik gebruik Arduino 1.8.5, kun je ook aan geven waarom dat zo voelt?
Is dat de schrijfwijze?
De meerdere Tab's inspringen die ik heb gebruikt op een regel? (Dit doe ik om het voor mezelf duidelijker te maken)


De link naar digitalread ga ik even goed door nemen.


Het gebruik van millis() is goed, maar je hebt iets gemist.
Wie zet de 'previousTimer' als er op de knop wordt gedrukt ?
Het starten van een software timer met millis() bestaat uit twee regels:

Code: Alles selecteren
Alles selecteren
      if ( ...
      {
        timerRun = true;                        // Variable timerRun op true zetten, de timer gaat nu lopen
        prevousTimer = millis();
      }


Ik noem dat vaak een 'timestamp' van dat moment nemen.

Mijn gedachte was, previousTimer (0) - currentTimer (bv. 100) = -100. Maar mijn vergelijk is >= (groter of gelijk aan) , Dus dit gaat inderdaad helemaal niet.


De tijd uit sync lopen, daar was ik ook al bang voor. Daarom ook de vraag of de timer interrupt een betere optie zou zijn.
Maar de optie die jij aangeef vind ik een hele mooie
Code: Alles selecteren
previousTimer += 10;

Hier was ik denk ik niet opgekomen.

Om over na te denken: Wat gebeurt er als de code ergens 100 ms vertraagd ? Hoe wordt dan de tijd opgehoogd ?

Hopen dat de code nooit meer dan 100ms vertraagt wordt! :D
Dit is ook nog een punt waar ik mee zit, moet hier nog een goed over nadenken.

Gebruikers-avatar
Berichten: 631
Geregistreerd: 15 Nov 2015, 11:54

Re: Tijdwaarneming

Berichtdoor Gij Kieken » 07 Dec 2017, 16:36

Hou ook rekening met contact dender. Dit kun je hardware dan wel software oplossen.

Berichten: 3
Geregistreerd: 24 Nov 2017, 18:17

Re: Tijdwaarneming

Berichtdoor PatrickW » 07 Dec 2017, 18:28

Hoi Gij Kieken,

Denk jij dat heel veel invloed zou kunnen hebben?

Ik had hier over al het een en ander gevonden, maar was in de veronderstelling dat dit hier niet zoveel invloed zou hebben.
Om dat met de schakelaars alleen de variable timerRun op true of false zet, hooguit dat deze de eerst volgende keer weer
door de if regel gaat en weer op true of false gezet wordt.

Maar als jullie veronderstellen dat dit wel invloed gaat hebben, hoor ik dit graag.


mvg Patrick

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Tijdwaarneming

Berichtdoor Koepel » 07 Dec 2017, 18:39

Het waren inderdaad de tabs waardoor ik dacht dat je iets anders gebruikte :lol:
Ik heb een andere stijl van de code: https://gist.github.com/Koepel/b70f81c71a52d8d6d3da86b9fe56d50e.
De manier van het gebruik van '{' en '}' vind ik veel duidelijker en mooier op de manier zoals ik het doe (dat vind ik ;) ).

Ga er maar van uit dan de schakelaars alle kanten op denderen.
Ik adviseer altijd de Bounce2 library, die zit al in de Arduino IDE bij "bibliotheek beheer". De Bounce2 kun je later altijd nog toevoegen.

De millis() geeft een waarde terug van 0x00000000 tot 0xFFFFFFFF. En daarna rolt hij door van 0xFFFFFFFF naar 0x00000000 (een "rollover").
Wanneer je dit doet "millis() - previousMillis" met unsigned long dan gaat het altijd goed. Zelfs tijdens het moment van een rollover komt er een correct positief getal uit.

Dus dit:
Code: Alles selecteren
unsigned long previousMillis;

void setup()
  ...

void loop()
{
  if( millis() - previousMillis >= 10)
  {
    previousMillis += 10;

    // verhoog de teller
    ...
  }
}
Dat gaat gegarandeerd altijd goed. 100%.

Eerst unsigned long currentMillis = millis(); doen is natuurlijk prima. Dat heeft soms zelfs voordelen, omdat die waarde dan tijdens de loop() hetzelfde blijft.

Als er ergens een delay tussen zit van 100ms, dan loopt het 100ms achter. Het is eenvoudig te beredeneren wat er gebeurt. De if-statement is natuurlijk waar, dus verhoogd 'previousMillis' met 10. Dan loopt het 90ms achter. Enzovoorts.

Kan ik nog een stapje verder gaan?
Stel dat je iedere seconde iets draadloos wilt versturen. Dan kun je beter niet previousMillis += 1000; doen, want dan zouden de berichten meteen achter elkaar verstuurd kunnen worden na een lange delay. Dan is het beter om altijd de pauze er tussen op 1 seconde te houden, dus dan is previousMillis = millis(); of previousMillis = currentMillis; beter.

Als je dit begrijpt, dan ben je meteen een Arduino deskundige ;)

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Tijdwaarneming

Berichtdoor shooter » 07 Dec 2017, 19:16

die ingangen moeten dus met digitalRead(startbutton)== HIGH worden.
dan moet je ook gelijk kijken of de timer al runt, en dan dus niet weer restten of zo.
dat ook doen bij de andere buttons.
wat je doet met dat bijtellen enzo snap ik helemaal niet.
verder moet je rekening houden da die millis() niet precies is, dus als dit concept werkt, dan over gaan op een echte RTC, en die millis() gebruiken om de korte tijden erbij te doen,
paul deelen
shooter@home.nl

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: Tijdwaarneming

Berichtdoor Koepel » 07 Dec 2017, 22:06

@shooter, een kleine aanvulling:
In de ISR zit een correctie voor millis: https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring.c.
Timer0 loopt met 976.5625 Hz of zo iets, het verschil wordt gecorrigeerd.

Als millis() gebruikt wordt om de seconden te tellen, of zelfs als de 10ms wordt geteld zoals PatrickW doet, dan klopt het volgens mij precies. Dan krijg je de nauwkeurigheid van het X-tal. Op die manier kun je er dus een minuut in jaar naast zitten, maar dat is alleen de onnauwkeurigheid van het X-tal.

Als de Arduino niet wordt uitgezet, dan kan dus ook bijvoorbeeld de TimeLib gebruikt worden zonder RTC. Dan wordt millis() gebruikt (https://github.com/PaulStoffregen/Time).

De DS3231 RTC is nauwkeuriger dan een X-tal, en een RTC gaat natuurlijk verder als de Arduino wordt gereset of uitgezet.

Terug naar Arduino software

Wie is er online?

Gebruikers in dit forum: RussellAlets en 15 gasten