volgorde van interrupts wijzigen

Hey allemaal,

ik heb eens een rare vraag,

ik werk met een sketch, met daarin 2 ISR’s.
ik gebruik dit om tijdsmetingen te doen, via fotocellen, van voorbij bewegende objecten (honden)

nu had ik al gelezen dat de interrupts een bepaalde voorrang krijgen op arduino

/* init variabelen*/
long _prevTime1,_prevTime2,_nextTime2 = 0;
volatile unsigned long time1 = 0, time2 = 0;
int dogIn = LOW;
...

/* init Interrupts */
void setup()
{
  pinMode(FotocelA, INPUT_PULLUP); // PIN 30 instellen voor FotocelA als digitale input
  attachInterrupt(0, Time1, FALLING); // time1 (in sensor A )(PIN 2)
  pinMode(FotocelB, INPUT_PULLUP); // PIN 31 instellen voor FotocelB als digitale input
  attachInterrupt(1, Time2, FALLING); // time2 (in sensor B )(PIN 3)
  ...
}

void loop()
{
/* afhankelijk van waar in de loop, kan de waarde van "nextString" ofwel "A" ofwel "Z" zijn
....
}

/*---- ISR zone ----*/
void Time1() // Fotocel A - eerste fotocel horizontaal
{
  Serial.println("Time1()");
  Serial.println(nextString);
  Serial.println(micros() - _prevTime1);
  Serial.println(dogIn);
  if ((micros() - _prevTime1) > 200000)
 {
  time1 = micros(); // neem tijd bvb : 8.765.433
  _prevTime1 = time1; // dus wordt dit 8.765.433 !
  if (nextString == "A" || nextString == "Z")
  {
    nextString = "B";
  }
  if (nextString == "a")
  {
    nextString = "A";
  }
 }
 Serial.println(nextString);
}

void Time2() // Fotocel B - tweede fotocel horizontaal
{
  Serial.println("Time2()");
  Serial.println(nextString);
  Serial.println(micros() - _prevTime2);
  Serial.println(dogIn);
  if ((micros() -_prevTime2) > 200000)
  {
    time2 = micros();
    _prevTime2 = time2;
    passLijnSensor = HIGH;
    if (dogIn == LOW && nextString == "B")
      {
        dogIn = HIGH;
        nextString = "b";
        _nextTime2 = time2;
    Serial.println("1."+ nextString);
      } 
     if(dogIn == HIGH && nextString == "b" && (micros() - _nextTime2) > 2000000)
      {
        dogIn = LOW;
        nextString = "a";
    Serial.println("2." + nextString + ":" + String((micros() - _nextTime2)) );
     }
  }
}

nu krijg ik redelijk de gegevens die ik wil, MAAR op een bepaald moment (bij het terugkeren dus) krijg ik eerst de waarde terug vanuit Time1() en pas daarna die vanuit Time2()
waarbij dus inderdaad blijkt dat de tijd die gemeten was in Time2() kleiner is dan in Time1()

het voorwerp (hond) wordt gemeten doorgaand en een stuk later terugkerend

(zie bijlage als voorbeeld)

is het nu op een eenvoudige manier mogelijk om vanuit de code deze volgorde te wijzigen? zodat bvb de ISR Time2() voorrang krijgt op Time1(), om dit nadien héél snel weer om te schakelen bij een volgende hond…

Grtz,
Yves

test1.txt (238 Bytes)

Ach je kunt terug in de tijd, geintje
de oplossing is om de functie ABS te gebruiken dus tijd= ABS(tijd1-tijd2).
dit moet je niet in de ISR doen maar ergens anders, in de ISR alleen de tijd opslaan.
dan kun je in de gewone loop dus kijken welke tijd groter is dan weet je ook de richting.

Hi Shooter,

Thanks...

het zou waarschijnlijk ook al een stuk helpen om geen serial.println() ofzo te gebruiken, wordt ook afgeraden door Nick Gammon, maar ik wil natuurlijk netjes de uitvoer kunnen volgen op scherm.

ik ga deze week eens kijken waar ik geraak met de ABS() functie, als ik er niet uit geraak dan kom ik nog eens terug op dit topic

Grtz,
Yves

het is leuk om met interupts te werken, maar je kunt ze tijdens het communiceren ook uit zetten.

Shooter,

ook elk apart?

als ik bvb de INT0 wil uitschakelen voor een cyclus, kan dat dan?
ik heb dat nog nergens teruggevonden...

en werkt dat ook voor de vijf andere op een Mega?

Grtz,
Yves

Je kan de interrupts als geheel uitzetten en weer aanzetten (zie: http://www.arduino.cc/en/Reference/noInterrupts)

of via detachintterrup() een int uitzetten en weer via attachinterrupt weer aanzetten voor individuele interrupts. Misschien een tip om eens het verhaal over interrupts te lezen hoe het werkt.......

Nico was weer net even sneller :grin:

YvesD:
als ik bvb de INT0 wil uitschakelen voor een cyclus, kan dat dan?
ik heb dat nog nergens teruggevonden...

en werkt dat ook voor de vijf andere op een Mega?

In de setup() gebruik je : attachInterrupt(0, Time1, FALLING);

op deze manier kun je toch in je programma de opdracht detachInterrupt(0) opnemen waardoor de interrupt uitgeschakeld wordt en verderop dan weer attachInterrupt(0, Time1, FALLING) zetten om de interrupt(0) weer aktief te maken.
Op dezelfde manier kun je in een Mega2560 elk van de 6 interrupts activeren/deactiveren.

Zie ook Gammon Forum : Electronics : Microprocessors : Interrupts voor uitgebreide info .

@ cartoonist :

Nico was weer net even sneller :grin:

Hihi cartoonist :wink:
dat hebben we al vaker met Nico meegemaakt, klopt helemaal :slight_smile:

@Nico:

bedankt voor jullie beider tips, mijn gedacht was dat dit enkel in de setup() mocht/moest gebeuren :-*

ik heb het artikel van Nick al een paar keer doorgenomen, en beetje bij beetje begint het in sijpelen (keigoed artikel trouwens)

ik ga alvast aan de slag met de nieuwe kennis, ik hou jullie op de hoogte

Grtz,
Yves

Nico & Cartoonist,

dan kan ik mogelijks ook m'n debouncing oplossen daarmee?

ik dacht aan iets in deze aard :

ik lees even geen fotocellen uit met digitalRead() in de lus, ik laat de interrupt het werk doen...
als er een doorgang is in m'n eerste ISR, dan schakel ik die uit in diezelfde ISR (als dit al mag of kan natuurlijk), in de loop() lees ik dan de tijd uit, en schakel de ISR pas terug in na 2 seconden, waardoor ik geen uitlezing krijg van meervoudige doorgangen door de fotocellen (die ik niet nodig heb, enkel de eerste waarneming telt voor mij)

het volgende probleem stelt zich pas nadien denk ik, omdat de honden terugkomen (na zo'n 3,90s tot 5,00s gemiddeld), als de eerdere hond uit de baan komt, en ik hou dit systeem aan, dan kan ik natuurlijk de daaropvolgende hond niet zien voorbij komen als ik die 2s "out" gebruik...

wordt nog een moeilijke opdracht, want ik hoorde gisteren op de flyballwedstrijd dat er al velen geprobeerd hebben om het sensorsysteem met een arduino te maken, maar ze haken allemaal af...

"onmogelijk om te maken" , "niet haalbaar" , "veel te tijdsrovend" - zeggen ze, en ze werken dan allemaal met een PLC (meestal LOGO van Siemens)

nu heb ik zoiets van, dit moet zeker haalbaar zijn om te maken met arduino

dus eventjes in "Pitbull -modus" gaan en blijven proberen :wink:

Grtz,
Yves

YvesD:
dan kan ik mogelijks ook m'n debouncing oplossen daarmee?

ik dacht aan iets in deze aard :

ik lees even geen fotocellen uit met digitalRead() in de lus, ik laat de interrupt het werk doen...
als er een doorgang is in m'n eerste ISR, dan schakel ik die uit in diezelfde ISR (als dit al mag of kan natuurlijk), in de loop() lees ik dan de tijd uit, en schakel de ISR pas terug in na 2 seconden, waardoor ik geen uitlezing krijg van meervoudige doorgangen door de fotocellen (die ik niet nodig heb, enkel de eerste waarneming telt voor mij)

het volgende probleem stelt zich pas nadien denk ik, omdat de honden terugkomen (na zo'n 3,90s tot 5,00s gemiddeld), als de eerdere hond uit de baan komt, en ik hou dit systeem aan, dan kan ik natuurlijk de daaropvolgende hond niet zien voorbij komen als ik die 2s "out" gebruik...

Is het niet veel eenvoudiger om vlaggen te zetten (of een state machine) en op basis daarvan te handelen?

YvesD:
"onmogelijk om te maken" , "niet haalbaar" , "veel te tijdsrovend" - zeggen ze, en ze werken dan allemaal met een PLC (meestal LOGO van Siemens)

nu heb ik zoiets van, dit moet zeker haalbaar zijn om te maken met arduino

Ik ben geen ervarings deskundige maar als het met een PLC kan zou het ook met een Arduino moeten kunnen.

Pitbull ... das de juiste mentaliteit :slight_smile:

Jante

Hey Jantje !!

da's een tijdje geleden (maar dat ligt vast aan mij hoor :wink: )

ik werk al een tijdje met vlaggen en zelfs met een String() die ik opvul met een bepaalde waarde
maar ik loop steeds tegen m'n eigen beperkingen aan, omdat ik nooit eerder in C/C++ bezig was
soms krijg ik er een punthoofdje van, maar ik weiger op te geven... ik heb een thread lopen op een Engelstalig onderdeel van dit forum, de mensen doen echt super hun best om mij vooruit te helpen (zelfs Nick is even op de kar gesprongen...!)

Maar als ik dan ga experimenteren loop ik steeds weer tegen m'n onkunde aan :cry:

Ik zit met m'n neus tegen de deur van een redelijke doorbraak, maar vindt het sleuteltje niet...

De mensen doen super hun best om mij vooruit te helpen, maar ik kan onmogelijk verlangen dat ze het volledige verhaal van een flyballrace in no-time doorhebben... het is ook vrij complex om zonder beelden (en zelfs met beeldmateriaal) uit te leggen

Ik denk dat ik intussen al zo'n dertig varianten op m'n code geschreven heb (bovendien ben ik nog niet in staat om superstrakke code te schrijven - ik ga via het spreekwoordelijke Parijs naar Brussel, ipv van rechtstreeks)

De tip van Nick om met ISR's te werken was een grote stap voorwaarts, maar dan heb ik terug een dipje in het doorgronden van een volgende stap

Ik woon ook te ver van een Timelab of zo om daar met ervaren rotten over een probleem te kunnen buigen...

Ik ga deze avond de tips van Nico en Cartoonist eens uit testen, en kijken wat ik er mee kan aanvangen, en dan van daar af weer proberen voort te bouwen...

Als het weer niet lukt, dan ga ik op zoek naar een aangepaste muts, om m'n punthoofd toch een beetje te verdoezelen :wink:

Grtz,
Yves

PS : toch nog eens een dikke merci aan iedereen die me telkens weer op de goede weg helpt, maar opgeven zie ik niet zitten (ben nu al een dik anderhalf jaartje aan het sukkelen, het komt nu niet meer op een paar extra maanden aan)

Ik zou trouwens zsm van Strings afstappen..... Meest inefficiente RAM gebruik. Zeker als deze veel muteert.

Nico,

ah OK! te tijdsrovend ook of zo? Ik las ergens eens dat Strings() ook niet superefficient zijn of zo...
op de mega heb ik wel wat RAM zitten, maar betere technieken zijn altijd welkom...

Grtz,
Yves

YvesD:
Nico,

ah OK! te tijdsrovend ook of zo? Ik las ergens eens dat Strings() ook niet superefficient zijn of zo...
op de mega heb ik wel wat RAM zitten, maar betere technieken zijn altijd welkom...

Grtz,
Yves

Het heeft te maken met alloceren en de-alloceren zonder zgn. "garbage collection". Als een String groter wordt, dan zal hij opnieuw het geheugen alloceren dat jij vraagt + de additionelel bytes. Daarna wordt de inhoud van oud gekopieerd naar het nieuwe geheugen. Echter stel het oude stuk is 5 bytes groot, dan is er een grote kans dat hoewel die 5 bytes vrij zijn, deze nooit meer benaderd kunnen worden door het programma. Doe dit genoeg keren en je RAM is op terwijl je bij wijze van spreken nog 1K vrij hebt van allemaal van die kleine stukjes.
Grotere platformen als Windows/Linux/OSx/Android/IOS ed heb een zogenaamde "garbage collection" routine die al die vrijgekomen kleinen stukjes weer bij elkaar schraapt en vrijgeeft voor nieuw gebruik.
Bij microprocessoren moet je dus zelf het geheugen managen wat er op neerkomt dat alloceren prima gaat maar dat je dan moet dealloceren in omgekeerde volgorde (voor velen een lastige materie). Het alternatief is variabelen te creeren die een string array (char) krijgen die de maximale waarde kan bevatten. Immers die zou bekend moeten zijn anders wordt het wel heel erg de goden verzoeken.
Verder dan gebruik maken van functies als strlen, strcpu, strncpy, strchar, strcmp etc.
Die zijn trouwens een stuk sneller als de Sting class.

Hey,

OK, deze avond ga ik eens het volgende uitproberen !

ergens in de initialisatie:

...
boolean _int1 = LOW; // vlag ter controle van de interrupt
boolean _int2 = LOW; // vlag ter controle van de interrupt
Sensor1 = 2; // PIN 2 => INT0
Sensor2 = 3; // PIN 3 => INT1
volatile long time1 = 0;
volatile long time2 = 0;
debounce = 200000;
boolean Z,A,B,a,b = LOW;
Fout = LOW;
...

ergens in de setup() :

...
pinMode(Sensor1, INPUT_PULLUP);
attachInterrupt(0, Time1, FALLING);
_int1 = HIGH;
pinMode(Sensor2, INPUT_PULLUP);
attachInterrupt(1, Time2, FALLING);
_int2 = HIGH;
...

ergens in de loop() :

...
if ( (micros() - time1) > debounce && !_int1)
{
  attachInterrupt(0, Time1, FALLING);
  _int1 = HIGH;
}
if ( (micros() - time2) > debounce && !_int2)
{
  attachInterrupt(1, Time2, FALLING);
  _int2 = HIGH;
}
...

en dan de ISR’s zelf :
ISR 1 :

void Time1()
{
  time1 = micros(); // nodig voor het bijhouden van de racetijden, alsook het resetten van de interrupt1
  if ( Z || B ) // ofwel een foute start, ofwel een te vroege doorgang v/d volgende hond
  {
     Fout = HIGH; // aangeven dat er een fout is
     B = HIGH; // volgende vlag zetten voor Time2()
     Z,A,b,a = LOW; // rest zeker LOW zetten
  }
  if (a)
  {
     A = HIGH; // volgende vlag zetten voor Time2()
     Z,B,b,a = LOW; // rest zeker LOW zetten
  }
  if (A)
  {
     B = HIGH; // volgende vlag zetten voor Time2()
     Z,A,b,a = LOW // terug op zeker spelen en de rest LOW zetten
  }
  detachInterrupt(0);
  _int1 = LOW;
} // einde ISR 1

ISR 2 :

void Time2()
{
  time2 = micros(); // nodig voor het bijhouden van de racetijden, alsook het resetten van de interrupt2

  /*
  Er is dus een hond correct of foutief door de eerste rij sensors gelopen, de volgende stap is deze tweede rij sensors...
  Deze doorgang zal maximaal 0,200 s na de doorgang door de eerste rij sensors gebeuren...
  */
  if ( B )
  {
     b = HIGH; // volgende vlag zetten voor Time2()
     Z,A,B,a = LOW; // rest zeker LOW zetten
  }

  /* 
  raceTime is de "start" van het programma + 3 seconden;
  bijgevolg is deze doorgang als dusdanig te herkennen, als een hond terugkeert van de bal te halen, dan is dit zeker
  ongeveer zo'n 3,8s à 4,5s later, dus een waarde kleiner dan "debounce" is een doorgang richting box
  */
  if (b && (micros() - raceTime) < debounce) // kleiner dan 0,2s => richting box
  {
     b = HIGH; // volgende vlag zetten voor Time2()
     Z,B,b,a = LOW; // rest zeker LOW zetten
  }

  /*
  als deze tijd groter is dan 0,2 seconden, dan was de hond aan het terugkeren naar de geleider
  */

  if (b && (micros() - raceTime) > debounce)
  {
     a = HIGH; // volgende vlag zetten voor Time2()
     Z,B,b,a = LOW; // rest zeker LOW zetten
  }
  detachInterrupt(1);
  _int2 = LOW;
} // einde ISR 2

een “normale” heat van één hondje zie er idealiter als volgt uit

“Z” : de baan in nog niet vrijgegeven om te racen, dus als Z op HIGH staat, dan is er een “startfout”, dit wordt aan de loop() doorgegeven via “Fout = HIGH;”
“A” : de baan is vrijgegeven om te racen, bij een doorgang door de eerste rij sensors, wordt “B” HIGH gezet terwijl de hond richting flyballtoestel loopt, een paar hondersten van een seconde later breekt deze hond de tweede sensorlijn, hier wordt dan “b” op HIGH gezet, als de hond terugkeert met de bal en dus eerst terug door de tweede sensorrij loopt, wordt “a” op HIGH gezet, een paar hondersten later gaat hij door de eerste sensorrij, dan komt “A” terug HIGH te staan, en de volgende hond kan de baan in…

eens zien of het wat opbrengt voor m’n systeempje :wink:

Grtz,
Yves

nicoverduin:
Het heeft te maken met alloceren en de-alloceren zonder zgn. “garbage collection”.
~ ~ ~
Bij microprocessoren moet je dus zelf het geheugen managen
~ ~ ~
Verder dan gebruik maken van functies als strlen, strcpu, strncpy, strchar, strcmp etc.
Die zijn trouwens een stuk sneller als de Sting class.

Je hebt helemaal gelijk maar ik vind het gebruik van de String class toch wel erg makkelijk wat, voor mij dus, een groot voordeel is.
Bij de ontwikkeling van mijn programma’s hou ik daarom rekening met dit probleem en hou het vrije RAM in de gaten.

Daar bestaat de library ‘freeMemory.h’ voor die slechts een paar honderd bytes flashgeheugen nodig heeft en ongeveer 10 bytes van het schaarse RAM opeist.

#include <MemoryFree.h> // declare library

// ergens in het programma na het gebruik van de String functie plaats ik de regel :

Serial.println( freeMemory() ); // print free RAM

Als tijdens de loop van het programma dit vrije RAM niet kleiner wordt betekent dit dat het probleem, zoals jij dat hierboven beschreef, niet optreedt en dat het programma geen geheugenlek heeft waardoor het zou crashen.

Ik ben daarom van mening dat er geen reden is om de String Class te mijden.

Hey allemaal,

NIET gelukt !

Althans niet zoals ik het voor ogen had ! Ik slaag er op een of andere manier maar niet in om enkel de eerste doorgang te registreren en alle volgende doorgangen binnen de 200ms te laten voorbij gaan zonder actie te ondernemen...

edit : als ik de interrupts uitschakel via detachInterrupt(x), kan ik diezelfde PIN dan nog gewoon uitlezen met digitalRead(PIN)?
edit 2: ja dus ! :slight_smile:

Grtz,
Yves

Dat laatste is logisch. Het is uiteindelijk gewoon een input pin. Een interrupt echter wordt niet gegenereerd omdat je de hardware via detachInterrupt() hebt losgekoppeld.

pffff, even m'n dipje delen met de community,

ik slaag er dus niet in om een correct werkende "debouncing" te otnwikkelen die met een aantal factoren rekening houd.

ik kan nu dus wel al perfect een foute of een correcte start loggen, ik werk hiervoor met flags die ik hoog of laag zet

bij de druk op "start" zet ik een flag "Z" op high, dit is voor het systeem het teken dat er eigenlijk nog geen vrijgave is van de wedstrijdbaan, na drie seconden (de startlichten dus) wordt "Z" low, en de volgende vlag ("A") high, dit is een teken dat de baan vrijgegeven wordt.

Als de eerste hond door de sensor1 loopt bij "Z" == HIGH dan genereer ik een foutmelding en neem de tijd op, bij "A" neem ik enkel de tijd op en verwerk die, op dat moment zet ik "A" op LOW en "B" op high

na die eerste sensor1 loopt een hond altijd door de sensor2 lijn richting balletje. doordat "B" op high staat, is dit voor het systeem correct, "B" komt op LOW en "b" wordt high gezet, nu duurt het zeker meer dan 2sec eer er nog iets te gebeuren valt aan de sensors (ondertussen schrijf ik de tijden op de LCD's)

na zeker meer dan 2sec komt de eerste hond terug, maar dan eerst door sensorlijn2, ik moet hier nog geen tijd nemen, enkel flags omschakelen : "b" wordt low en "a" wordt high gezet, quasi ogenblikkelijk daarna gaat de hond richting baasje door sensorlijn1, "a" wordt low gezet en "A" high
het volledige spel kan heraanvangen voor een volgende hond

dus de sequentie is idealiter als volgt

"Z"-"A"-"B"-"b"->2sec-"a"-"A" bij een correcte start, en correcte terugkomst van een eerste hond.
een volgende hond zal ergens tussen de 0,01s en de 0,80s na de vorige door de sensors komen, ik mag deze dus niet missen, maar ook geen dubbele meting hebben...

iemand een idee of tip om mij terug op de goede baan te zetten?
of een library om op verschillende manieren te debouncen (nu eens 0,2s en dan eens >2,0s)

Grtz,
Yves

yaeiijh !! :slight_smile:

na een paar nachtjes slapen, toch gelukt !!

deze avond plaats ik de code, zo heeft er mogelijks nog iemand anders ook wat aan :slight_smile:

Grtz,
Yves