hoe werkt de functie Attache Interrupt / PulseHandler

Projecten die niet passen in bovenstaande onderwerpen
Berichten: 2
Geregistreerd: 11 Jan 2014, 19:13

hoe werkt de functie Attache Interrupt / PulseHandler

Berichtdoor Deesse » 28 Mrt 2015, 17:42

Ik ben een beginner, maar heb mbv stukjes codes al een projectje in elkaar gedraaid om de snelheid te meten van een wiel
hiervoor gebruik ik een reedcontact van een fietscomputer
In principe werkt het wel, maar niet helemaal goed, daarom mijn vraag of iemand een stukje code kan lezen en kan aangeven wat ik nu fout doe?
bij voorbaat dank.

ARDUINO UNO met LCD 16x4

Hoe werkt het commando AttacheInterrupt / PulseHandler ??

De bedoeling is om m.b.v. een reedcontact de snelheid te meten van een draaiend wiel
Hiervoor worden de pulsen geteld
en vervolgens omgerekend naar de snelheid in km/uur
De snelheid moet op een LCD display getoond worden.

om ervoor te zorgen dat de pulsen altijd geteld worden en niet verstoord worden door de routine om de display aan te sturen
wordt de functie PulseHandler gebruikt

Echter het werkt niet naar behoren

bij de start verschijnt op de display de waarde 572 km/u en P krijgt meteen de waarde 1
Zodra de pulsen gedetecteerd worden telt de pulseteller prima, geen last van bouncing
De km/u echter gaat met sprongen van 3-5 km/u omhoog of omlaag, ook bij heel langzaam de snelheid aan te passen.
of te wel: hij wil de tussenliggende waarden niet printen.

Als ik via de seriele monitor kijk, krijg ik een overload aan pulsen gemeld (uiteraard)
zet ik vervolgens een delay er achter van 1000 msec dan gaan ook de pulsen met meerdere eenheden omhoog
of te wel de pulsehandler heeft last van de delay die in de voidloop zit.

Dit is wat ik gemaakt heb, wat doe ik fout ??

Code: Alles selecteren

#include <LiquidCrystal.h>                 // include the library code:
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);     // deze verwijst de library naar de pins van de lcd (RS, E, DB4, DB5, DB6, DB7)
long P=0;                                  // P = aantal pulsen van de reedcontact
long ms = 0, last_ms = 0;                  // de lopende tijd wordt eerst op 0 gezet
int Spd = 0;                               // de snelheid wordt op 0 gezet
int Circ = 2077;                           // wielomtrek in mm
long dTme = 0;                             // delta-tijd


void setup(){
  Serial.begin(9600);                      // zet de seriele monitor aan, alleen voor testen.
  lcd.begin(16, 4);                        // definieer aantal kolommen en rijen op de display op 16x4:
  pinMode(2, INPUT_PULLUP);                // maakt pin 2 input and enable the internal pull-up resistor
  attachInterrupt(0, PulseHandler, FALLING);   // interrupt 0 (zit op Pin2), de routine PulsHandler wordt gestart,
                                               // Faling geeft aan dat hij triggert als het signaal weg valt.

                                               
  intro();                                 // er wordt een introductie gestart als de SuperTwin opgestart wordt
}
//=== einde setup ===

void intro(){                              // Introscherm
  lcd.setCursor(0, 0);
  lcd.print("Speed_v992");           
  delay(4000);
  lcd.clear();
  }

// === einde Intro ===



void loop(){

  //display regel 1
  if (Spd < 10) {                        // trucje om het getal rechts uit te lijnen
    lcd.setCursor(4, 0);
    lcd.print("   ");
    lcd.setCursor(6, 0);
    lcd.print("- ");
  }
  if (Spd >9 && Spd < 100) {
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(5, 0);
    lcd.print(Spd);
  }
  if (Spd > 99) {
    lcd.setCursor(4, 0);                // set the cursor to column 1, line 0 (2e kolom. 1e regel)
    lcd.print(Spd);
  }
  lcd.setCursor(7, 0);                  // set the cursor to column 4, line 0 (5e kolom. 1e regel)
  lcd.print (" km/u");

    lcd.setCursor(7, 2);               // tijdelijk wordt hier aantal P op regel 3 geplaatst geplaatst
    lcd.print (P);
    Serial.println(P);
    Serial.println(Spd);
}

  //=== einde Loop ===




void PulseHandler () {                   // Routine "PulseHandler" staat BUITEN DE ROUTINE "VOID LOOP"  !!!
  ms = millis();                         // miliseconden worden door de arduino continu doorgeteld vanaf aanzetten.

 if (ms - last_ms >5)                    /*  Deze functie bekijkt of een signaalteje door de magneet misschien een echo meeneemt.
                                         Dat heet bouncing, deze functie heet dan ook "debounce".
                                         Door te kijken of er in de laatste 5 millisec ook al een signaal is geweest.
                                         is dat het geval dan wordt de teller niet gestart.*/
                                         
  {                                       // als er meer dan 5 milis tussen 2 pulsen zit dan wordt de snelheid berekend door.....
    dTme = (ms - last_ms);                // het tijdsverschil (dTijd) tussen de laatste 2 pulsen op te slaan....
                                          // dan
    Spd = Circ / (dTme) *3.6;             // de snelheid vast te leggen door met de formule: tijdsverschil x wielomtrek ......
                                          // mm naar km = 1/1.000.000  msec naar hr = 1/3.600.000 resultaat = * 3,6
                                          // dan
    last_ms = ms;                         // last ms krijgt de laatst geconstateerde pulswaarde
                                          // dan
    P++;                                  // de puls teller wordt met 1 verhoogd

  }
}


Advertisement

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: hoe werkt de functie Attache Interrupt / PulseHandler

Berichtdoor nicoverduin » 28 Mrt 2015, 18:48

Serial en interrupt gaan heel slecht met elkaar om. Als je al Serial gebruikt dan een zo hoog mogelijke baudrate gebruiken en minimaal er naartoe sturen. Daarnaast heb je kans op verstoringen bij millis() en micros() omdat die ook een interrupt gebruiken.
in de loop hoef je alleen maar de variabelen te vullen en nide de constante waarden lijkt mij. dus km/h enz. in de setup doen.
Get verschil dat je in het begin hebt komt omdat je last_ms op 0 hebt gezet. Dus in de eerste berekening vergelijk je met 0. Wil je dat oplossen moet je geen berekening uitvoeren bij de eerste puls. dus in de setup bijvoorbeeld een flag zetten zoals
cpp code
volatile Uint8_t eersteKeer = true;

En dan in die interuupt handler:
cpp code
if (eersteKeer){
//
// alleen waarde bewaren
//
last_ms = millis();
eersteKeer = false;
} else {
//
// hier de normale behandeling
//
}

Tenslote ALLE variabelen die gebruikt zijn in de ISR als volatile benoemen.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 2
Geregistreerd: 11 Jan 2014, 19:13

Re: hoe werkt de functie Attache Interrupt / PulseHandler

Berichtdoor Deesse » 03 Apr 2015, 19:17

Dank je voor de hulp die je biedt!

Je geeft 4 opmerkingen mee:
1 en 4 is gemakkelijk dus dat heb ik zondermeer gedaan (serial.begin en serial.prinln weggehaald en alle volatile gemaakt)
3 klinkt logisch. Maar ik begrijp de betekenis van “Uint8_t” in jouw code niet. Misschien een verschrijving? In ieder geval : als ik dat stukje weglaat werkt het inderdaad precies zoals je zegt. Weer een stapje verder!
2 Die begrijp ik niet. In de void.loop() heb ik alleen een If-functie die vertelt welke variabelen er afgedrukt moeten worden.
Dan kan het zijn dat je verwijst naar de ISR Pulse Handler:
Ik heb de berekening Spd naar de setup verschoven, dan krijg ik geen waarde meer voor Spd, dat bedoel je dus waarschijnlijk niet
Ook nog met de Ms geprobeerd maar dat werkt ook niet
Kortom kun je nog eens uitleggen wat je bedoelt?
Dan heb ik nog een delay ingebouwd aan het einde van de printloop, daardoor wordt het beeld van de snelheid rustiger. Nu krijg ik geen foute of springerige waardes meer.
Ik heb mijn aangepaste code toegevoegd (hoe krijg ik die zo mooi als jij dat doet, in deze discussie geplakt?)
Deze code laat als resultaat zien dat de pulsteller (P) perfect loopt, reageert snel op veranderingen in snelheid. Maar de snelheid (Spd) telt nog steeds met meerdere km/u tegelijk.
Ik heb ook nog even geprobeerd om de print van de Spd in de ISR op te nemen, zodat ik meteen het resultaat zie: dat maakt dus niets uit (behalve dat ik sneller de waardes te zien krijg).
De vraag blijft: waarom is de berekende snelheid niet accuraat?

Code: Alles selecteren
#include <LiquidCrystal.h>                   // include the library code:
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);     // deze verwijst de library naar de pins van de lcd (RS, E, DB4, DB5, DB6, DB7)
volatile long P=0;                                   // P = aantal pulsen van de reedcontact
volatile long ms = 0, last_ms = 0;        // de lopende tijd wordt eerst op 0 gezet
volatile int Spd = 0;                                // de snelheid wordt op 0 gezet
volatile int Circ = 2077;                          // wielomtrek in mm
volatile int eersteKeer = true;
volatile int Stilstaan = true;

void setup(){
  lcd.begin(16, 4);                       
  pinMode(2, INPUT_PULLUP);                            // maakt pin 2 input and enable the internal pull-up resistor
  attachInterrupt(0, PulseHandler, FALLING);   // interrupt 0 (zit op Pin2), de routine PulsHandler wordt gestart,
                                                                                 // Faling geeft aan dat hij triggert als het signaal weg valt.
  intro();                                                                  // er wordt een introductie gestart als de SuperTwin opgestart wordt
}
//=== einde setup ===
void intro(){                             
  lcd.setCursor(0, 0);
  lcd.print("Speed_v995");           
  delay(4000);
  lcd.clear();
  }

// === einde Intro ===

void loop(){

  //display regel 1
  if (Spd < 10) {                        // trucje om het getal rechts uit te lijnen
    lcd.setCursor(4, 0);
    lcd.print("   ");
    lcd.setCursor(6, 0);
    lcd.print("- ");
  }
  if (Spd >9 && Spd < 100) {
    lcd.setCursor(4, 0);
    lcd.print(" ");
    lcd.setCursor(5, 0);
    lcd.print(Spd);
  }
  if (Spd > 99) {
    lcd.setCursor(4, 0);                // set the cursor to column 1, line 0 (2e kolom. 1e regel)
    lcd.print(Spd);
  }
  lcd.setCursor(7, 0);                  // set the cursor to column 4, line 0 (5e kolom. 1e regel)
  lcd.print (" km/u");

    lcd.setCursor(7, 2);               // tijdelijk wordt hier aantal P op regel 3 geplaatst
    delay (500);
}

  //=== einde Loop ===



void PulseHandler () {                   // Routine "PulseHandler" staat BUITEN DE ROUTINE "VOID LOOP"  !!!
  ms = millis();                                // miliseconden worden door de arduino continu doorgeteld vanaf aanzetten.

if (eersteKeer){
                                                       //
                                                      // alleen waarde bewaren
                                                      //
   last_ms = millis();
   eersteKeer = false;
   }
else {
    if (ms - last_ms >5){                               /*  Deze functie bekijkt of een signaalteje door de magneet misschien een echo meeneemt.
                                                                             Dat heet bouncing, deze functie heet dan ook "debounce".
                                                                             Door te kijken of er in de laatste 5 millisec ook al een signaal is geweest.
                                                                              is dat het geval dan wordt de teller niet gestart.
                                                                              als er meer dan 5 milis tussen 2 pulsen zit dan wordt de snelheid berekend door..... */
                                                                         // dan
    Spd = Circ / (ms - last_ms) *3.6;             // de snelheid vast te leggen door met de formule: tijdsverschil x wielomtrek ......
                                                                         // mm naar km = 1/1.000.000  msec naar hr = 1/3.600.000 resultaat = * 3,6
                                                                         // dan
    last_ms = ms;                                               // last ms krijgt de laatst geconstateerde pulswaarde
                                                                           // dan
    P++;                                                              // de puls teller wordt met 1 verhoogd
    lcd.setCursor(7, 2);                                    // tijdelijk wordt hier aantal P op regel 3 geplaatst geplaatst
    lcd.print (P);
}
}
}

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: hoe werkt de functie Attache Interrupt / PulseHandler

Berichtdoor nicoverduin » 04 Apr 2015, 08:34

uint8_t is een definitie van een 8 bits waarde unsigned. Zo heb je ook int8_t, int16_t en int32_t als ook met de u ervoor om unsigned te definiëren. De reden om variabelen zo te definiëren is om de grootte van een variabele ongeacht het platform dezelfde grootte te hanteren.
bijv.:
een int op een 8 bits platform is 16 bits. Op een 32bits platform is het echter 32bits groot. Dus stel je hebt een programma dat gebruik maakt van een counter die na 65536 (16 bits) door 0 zou lopen en had een unsigned int gebruikt op de Arduino, dan zou het fout kunnen gaan als je hetzelfde programma op een 32bits bordje zou draaien. komt dat voor? Yep... Op dit moment worden er Arduino settings gemaakt voor 32 bitters. de ESP8266 (wifi on a chip) heeft nu ook Arduino IDE ondersteuning. Hierdoor kan je straks een Arduino programma maken die direct op de Wifi Chip wordt gezet ontwikkelen. Maar dat is wel een 32 bitter.
Om nu te voorkomen dat ik tegen allerlei problemen aanloop probeer ik er een standaard gewoonte van te maken om consequent uint8_t etc te gebruiken. Zit ik altijd goed.

Tenslotte moet je de interrupt ISR altijd zo kort mogelijk maken. Het is een onderbreking van je bestaande programma. in het kort is jouw programma niet anders dan het berekenen van het tijdsverschil en daaruit afgeleid de snelheid op basis van 2 tijdsmomenten. Dat is wat jouw loop moet doen.

De interruptISR is de onderbreker die de twee tijdsmomenten aanpast. Zaken als lcd updates, printf etc allemaal weglaten uit de ISR. Die moet echt zo kort mogelijk zijn.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 8
Geregistreerd: 14 Feb 2014, 18:35

Re: hoe werkt de functie Attache Interrupt / PulseHandler

Berichtdoor ToBr » 10 Apr 2015, 19:27

een reed contact is traag.
een Reed contact 'kraakt', d.w.z. dat het kontakt niet onmiddellijk 'aan' is.
Gebruik hiervoor het debounce programma van Arduino. Een gevolg hiervan is een extra vertraging.
een en ander is afhankelijk van de waar te nemen snelheid.
groet ToBr

Terug naar Overige projecten

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 39 gasten