Arraw einlesen Probleme in ISR

Hallo zusammen,

ich habe ein kleines Programm geschrieben welches jede Sekunde einen Wert von A0 ausliesst und in einem Array mit 60 Werten speichert. Nach einer Minute wird der Durchschnitt gebildet und neu angefangen. So weit so gut. Nun wollte ich nicht die ganze Zeit immer nur auf das Einlesen warten und habe mir eine ISR im Sekundentakt geschrieben. Nun habe ich das Auslesen von A0 in diese ausgegliedert, leider scheint das nicht mehr zu funktionieren. Kann mir einer helfen ?

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define LED 13  // Das Wort „LED“ steht jetzt für den Pin 13
#define Auswahl1 22  // Das Wort „Auswahl1“ steht jetzt für den Pin 22
#define eingang A0 // Das Wort „Eingang“ steht jetzt für den Pin A0
#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 display(OLED_RESET);


//volatile
int sensorwert [60];
int sensorwertzaehler=0;
long mittelwertberechnen1min=0;
int tankinhalt=0;
int sekundenzaehler=0;
int minutenzaehler=0;
int reserve=0;
int reserve_alarm=0;
int reserve_alarm_zaehler=0;


void setup() //Hier beginnt das Setup.
{
pinMode (LED, OUTPUT); //Der Pin mit der LED (Pin 13) ist jetzt ein Ausgang.
pinMode (Auswahl1,INPUT_PULLUP); 

// Timer 1
 noInterrupts();           // Alle Interrupts temporär abschalten
 TCCR1A = 0;
 TCCR1B = 0;

 TCNT1 = 3036;            // Timer nach obiger Rechnung vorbelegen
 TCCR1B |= (1 << CS12);    // 256 als Prescale-Wert spezifizieren
 TIMSK1 |= (1 << TOIE1);   // Timer Overflow Interrupt aktivieren
 interrupts();             // alle Interrupts scharf schalten

Serial.begin(9600); //Im Setup beginnt die serielle Kommunikation, damit die Temperatur an den serial monitor übertragen wird.
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

// Sekundentakt Interrupft Routine
ISR(TIMER1_OVF_vect)        
{
 TCNT1 = 3036;             // Zähler erneut vorbelegen
 //digitalWrite(LED, digitalRead(LED) ^ 1); // LED ein und aus
 sekundenzaehler++;
 sensorwert [sensorwertzaehler]=analogRead(eingang);
 sensorwertzaehler++;

   Serial.print(sensorwertzaehler);
   Serial.print("   ");
   Serial.print(sensorwert [sensorwertzaehler]);
   Serial.print("   ");
   mittelwertberechnen1min=mittelwertberechnen1min+sensorwert[sensorwertzaehler];
   Serial.print("   ");
   Serial.print(mittelwertberechnen1min);
   Serial.print(" Aktueller Wert ");
   Serial.print("   ");
   Serial.print("Sekundenzaehler");
   Serial.print(sekundenzaehler);
   Serial.print("   ");
   Serial.print("Minutenzaehler");
   Serial.println(minutenzaehler);
   

 if (sekundenzaehler==60) 
 {   
   minutenzaehler++;
   reserve_alarm_zaehler++;
   sekundenzaehler=0;
 }

 if (reserve==1)
 {
   digitalWrite(LED,HIGH);
 }

 if(reserve_alarm==1)
 {
   digitalWrite(LED, digitalRead(LED) ^ 1); // LED ein und aus
 }
}


void loop()

Kleiner Nachtrag. Was nicht mehr funktioniert ist das Auslesen des Wertes an A0. Die ersten 60mal läuft die Abfrage durch und zeigt immer "0" an, warum auch immer. In der nächsten Minute wird der richtige Wert (hier 170) genommen, kann aber auch die ganze Minute nicht mehr geändert werden. Sprich wenn ich jetzt einen anderen Wert an A0 anlege wird dieser erst in der nächsten Minute angezeigt, und kann dann auch wieder in der laufenden Minute nicht mehr geändert werden. Ich finde da einfach meinen Denkfehler nicht...

Hi,

  1. solltest du deinen Sketch im Code-Tag setzen, dazu die </> Schaltfläche klicken und den Code zwischen [code] und [/code] (ohne *) einfügen.

  2. Lässt du alles in setup() ausführen, statt es in loop() auszuführen.

Hi,

danke erst mal für deine Antwort. Was Du mit 1) meinst habe ich leider nicht verstanden, so lange bin ich noch nicht dabei. Im Loop laufen andere Teile (Anzeigenroutinen auf Display etc). Aber die ISR muss ich doch in der setup haben, oder ?

Schönen Gruß
Andreas

schmidtkoe:
Hi,

danke erst mal für deine Antwort. Was Du mit 1) meinst habe ich leider nicht verstanden, so lange bin ich noch nicht dabei.

zu 1.
Du solltest deinen Code speziell formatieren, damit der besser lesbar ist und die Einrückungen dargestellt werden. Wenn du einen neuen Beitrag erstellst, findest du oberhalb des Textfeld die ganzen Schaltflächen und da ist dann oben links der </>-Button. Kannst du übrigens auch noch nachträglich, in dem du in deinem Eingangspost unten auf edit klickst. :wink:

zu 2.
Bin mit ISR noch nicht vertraut, aber lass dir mal im Setup nach Serial.begin() und in ISR(TIMER1_OVF_vect) den Wert von analogRead(eingang) ausgeben:

Serial.print("A0 = ");
Serial.println(analogRead(eingang));

Ist der Wert dann auch 0?

prüfe ich

BTW: Der Sensor steckt aber auch auf dem Pin A0?

Das mit den Code-Tags habe ich mal übernommen:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define LED 13  // Das Wort „LED" steht jetzt für den Pin 13
#define Auswahl1 22  // Das Wort „Auswahl1" steht jetzt für den Pin 22
#define eingang A0 // Das Wort „Eingang" steht jetzt für den Pin A0
#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 display(OLED_RESET);


//volatile
int sensorwert [60];
int sensorwertzaehler=0;
long mittelwertberechnen1min=0;
int tankinhalt=0;
int sekundenzaehler=0;
int minutenzaehler=0;
int reserve=0;
int reserve_alarm=0;
int reserve_alarm_zaehler=0;


void setup() //Hier beginnt das Setup.
{
pinMode (LED, OUTPUT); //Der Pin mit der LED (Pin 13) ist jetzt ein Ausgang.
pinMode (Auswahl1,INPUT_PULLUP);

// Timer 1
  noInterrupts();           // Alle Interrupts temporär abschalten
  TCCR1A = 0;
  TCCR1B = 0;

  TCNT1 = 3036;            // Timer nach obiger Rechnung vorbelegen
  TCCR1B |= (1 << CS12);    // 256 als Prescale-Wert spezifizieren
  TIMSK1 |= (1 << TOIE1);   // Timer Overflow Interrupt aktivieren
  interrupts();             // alle Interrupts scharf schalten

Serial.begin(9600); //Im Setup beginnt die serielle Kommunikation, damit die Temperatur an den serial monitor übertragen wird.
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

// Sekundentakt Interrupft Routine
ISR(TIMER1_OVF_vect)       
{
  TCNT1 = 3036;             // Zähler erneut vorbelegen
  //digitalWrite(LED, digitalRead(LED) ^ 1); // LED ein und aus
  sekundenzaehler++;
  sensorwert [sensorwertzaehler]=analogRead(eingang);
  sensorwertzaehler++;

    Serial.print(sensorwertzaehler);
    Serial.print("   ");
    Serial.print(sensorwert [sensorwertzaehler]);
    Serial.print("   ");
    mittelwertberechnen1min=mittelwertberechnen1min+sensorwert[sensorwertzaehler];
    Serial.print("   ");
    Serial.print(mittelwertberechnen1min);
    Serial.print(" Aktueller Wert ");
    Serial.print("   ");
    Serial.print("Sekundenzaehler");
    Serial.print(sekundenzaehler);
    Serial.print("   ");
    Serial.print("Minutenzaehler");
    Serial.println(minutenzaehler);
   

  if (sekundenzaehler==60)
  {   
    minutenzaehler++;
    reserve_alarm_zaehler++;
    sekundenzaehler=0;
  }

  if (reserve==1)
  {
    digitalWrite(LED,HIGH);
  }

  if(reserve_alarm==1)
  {
    digitalWrite(LED, digitalRead(LED) ^ 1); // LED ein und aus
  }
}


void loop()

Zu 2 fällt mir nur ein, dass serielle Ausgaben in einer ISR ganz schlecht sind. In einer ISR sollten nur Dinge getan werden, die wirklich fix sind. Nimm die Ausgaben auf der seriellen Schnittstelle in loop() vor. Da ich mit ISRs bislang jedoch so gut wie nicht zu tun hatte, bin ich mir diesbezüglich nicht so sicher.

Gruß

Gregor

Danke zusammen. Die serielle Ausagbe soll da auch nicht bleiben. Die habe ich nur zur Fehlersuche eingebaut da nach umstellen auf ISR nichts mehr im Hauptprogramm funktionierte. Und dadurch kam ich darauf das die input anscheindend nicht vernünftig eingelesen wird. Und da suche nun warum das so ist. Kann man keine Arrays richtig in einer ISR beschreiben oder kiene inputs auslesen ?

Ich habe die serielle Ausgabe jetzt mal in die loop gesetzt, es ändert sich nichts. Das array scheint nicht zu arbeiten

schmidtkoe:
... Kann man keine Arrays richtig in einer ISR beschreiben oder kiene inputs auslesen ?

Das mit den Arrays ist kein Problem. Die Ausgabe ist eins - wenn möglicherweise auch nicht der Grund des eigentlichen Fehlverhaltens.

Gruß

Gregor

Also eigentlich muss der Fehler irgendwo hier liegen. Der Sensorwert startet bei 1, ebenso der sensorwertzaehler. Wie gesagt im ersten Durchlauf wird angeblich immer "0" ausgelesen, obwohl der Wert 70 ist. Nach 60 sekunden (also wenn das Array zum ersten Mal gefüllt ist) wird der Wert "70" übernommen, kann aber auch wieder nicht geändert werden

// Sekundentakt Interrupft Routine
ISR(TIMER1_OVF_vect)        
{
  TCNT1 = 3036;             // Zähler erneut vorbelegen
  //digitalWrite(LED, digitalRead(LED) ^ 1); // LED ein und aus
  sekundenzaehler++;
  sensorwert [sensorwertzaehler]=analogRead(eingang);
  sensorwertzaehler++;

    [code]

schmidtkoe:
Also eigentlich muss der Fehler irgendwo hier liegen. ...

In Deinem Codeschnipselchen sehe ich auf die Schnelle keinen Fehler. Da Dein Sketch schön kurz ist, knöpfe ich ihn mir mal intensiver vor, was aber mindestens ein paar Minuten dauert.

Gruß

Gregor

PS: Mir scheint, dass Du falsch geklammert hast. Formatiere Deinen Sketch am besten mal so, dass die Einrückungen die „Klammer-Ebenen“ sichtbar machen. Kurze if-Konstrukte lesen sich IMO besser, wenn sie in einer statt drei Zeilen stehen. Insgesamt kann man Deinen Sketch wahrscheinlich so formatieren, dass er vollständig auf eine Bildschirmseite passt.

Super danke Dir

Ich habe jetzt folgendes ausprobiert

// Sekundentakt Interrupft Routine
ISR(TIMER1_OVF_vect)
{
TCNT1 = 3036; // Zähler erneut vorbelegen
//digitalWrite(LED, digitalRead(LED) ^ 1); // LED ein und aus
sekundenzaehler++;
//sensorwert [sensorwertzaehler]=analogRead(eingang);
sensorwertzaehler++;
sensorwertohnearray=analogRead(eingang);
sensorwert[sensorwertzaehler]=sensorwertohnearray;

Sprich ich lese den Eingang jetzt nicht in ein Array, sondern in eine Variable. Danach speiche ich die Variable im Array, und auf einmal geht alles.

schmidtkoe:
... und auf einmal geht alles.

Schön :slight_smile: Dann habe ich mir jetzt aber einen Karma-Punkt verdient, gell.

Bitte poste mal den vollständigen, funktionierenden Sketch. Wenn ich mich vorhin nicht verguckt habe, dürfte der nach Deiner Änderung (trotzdem) nicht funktionieren.

Ich möchte ihn mir mal genauer ansehen (wenn auch erst morgen).

Gruß

Gregor

Macht das Leerzeichen in sensorwert [sensorwertzaehler]=analogRead(eingang); vielleicht Probleme? Bitte mal so testen:

sensorwert[sensorwertzaehler]=analogRead(eingang);

Ich verstehe das mit meinen bescheidenen Kenntnissen so:
Mit dem Leerzeichen zwischen sensorwert und [sensorwertzaehler] machst du aus dem Array eine Variable und setzt den Wert der (neuen) Variable sensorwert auf "[sensorwertzaehler]", bzw. damit auf 0, weil es nicht interpretiert werden kann.

Allerdings kann ich mich auch genauso gut täuschen...

Hallo Wapjoe,

ich könnte kotzen, das wars.... Dieses blöde Leerzeichen macht einen so üblen Fehler. Jetzt klappt alles.

Euch beiden vielen Dank

An die Leerzeichen Geschichte glaube ich nicht, das sollte keinen Unterschied machen.

Und siehe da, die Leerzeichen spielen keine Rolle.

byte testArray[20];

void setup() {
  Serial.begin(250000);
  testArray           [10]                 =   5;
  Serial.println(testArray[10]);
}
void loop() {}
5

Whandall:
Und siehe da, die Leerzeichen spielen keine Rolle.

...

testArray          [10]                =  5;
...

Sind bei Dir ja auch 11. Kein Wunder, dass das klappt :slight_smile:

Gruß

Gregor

Schon komisch was für Tips hier rumgeistern und dann auch noch als Lösung akzeptiert werden.