Forum: Mikrocontroller und Digitale Elektronik ina219.getCurrent_mA(); Funktion in der ISR nicht aufrufbar


von Sandro N. (nick2245)


Lesenswert?

Ich habe einen Arduino Nano und ein INA219 Strommessmodul.
Ich möchte über die TimerOne.h Bibliothek einmal die Sekunde den 
Stromwert auslesen.
Hierzu wird 1 mal die Sekunde die ISR per Timer mit dem Namen Strom 
aufgerufen.
Normalerweise sollte der Befehl zum abfragen " I = 
ina219.getCurrent_mA(); " in der ISR mit dem Namen Strom stehen.  Da 
funktioniert er aber nicht und der Arduino Nano stützt ab.
Zum Testen habe ich mal versucht eine andere Methode in der ISR 
aufzurufen. Das geht. Es scheint also ein Problem mit dieser einen 
Funktion zu sein.
Weiß jemand warum ich gerade diese Funktion nicht aufrufen kann aber 
andere Sachen schon?
1
#include <TimerOne.h>
2
#include <Wire.h>
3
#include <Adafruit_INA219.h>
4
Adafruit_INA219 ina219;
5
6
int I = 0;                          //Stromwert
7
8
void setup(void){
9
ina219.begin();
10
Timer1.initialize(1000000);         //Timer auf 1 Sekunden stellen
11
Timer1.attachInterrupt(Strom);      //ISR Strom wird jede Sekunde aufgerufen
12
Serial.begin(115200);
13
}
14
void loop(void){   
15
I = ina219.getCurrent_mA();         //hier wird die Funktion aufgerufen
16
delay(1000);
17
Serial.println("Läuft noch");
18
}
19
void Strom(void){
20
//I = ina219.getCurrent_mA();       //hier wird die Funktion nicht aufgerufen.Warum?
21
Serial.println(I);
22
}

: Bearbeitet durch Moderator
von Stefan F. (Gast)


Lesenswert?

Frage doch mal den Autor der INA Klasse, wenn du die Antwort nicht im 
Quelltext der Klasse findest. Du könntest deine Frage dort abladen: 
https://github.com/adafruit/Adafruit_INA219/issues

von Peter D. (peda)


Lesenswert?

Sandro N. schrieb:
> Weiß jemand warum ich gerade diese Funktion nicht aufrufen kann

Vermutlich wird diese Funktion selber einen Interrupt benutzen, aber die 
sind ja innerhalb eines Interrupts gesperrt (der AVR kann kein Nesting). 
Also wartet sie ewig.
Das sollte aber auch in der Doku zu dieser Funktion stehen.

von Stefan F. (Gast)


Lesenswert?

Generell ist es eine riskante Sache, aus Interrupts heraus Funktionen 
aufzurufen, die extern kommunizieren oder viel Speicher belegen. Dein 
Serial.println() halte ich dort ebenfalls für eine ganz schlechte Idee.

Denn Interrupts können andere Funktionen unterbrechen, die bereits viel 
Speicher belegt haben. RAM ist bei den kleinen AVR Mikrocontrollern 
knapp bemessen.

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

auch wenn das hier warscheinlich nicht das Problem ist, solltest du 
Objekt so initialisieren das sie zum Aufrufzeitpunkt auch verfügbar 
sind.
Serial.begin() sollte also noch vor der Timer1.attachInterrupt() stehen, 
sonst könnte die ISR mit Serial.print() noch vor Serial.begin() 
ausgeführt werden.

Bekommst du vom Compiler irgendwelche Warnungen?

Sascha

von Sandro N. (nick2245)


Lesenswert?

Stefanus F. schrieb:
> Dein
> Serial.println() halte ich dort ebenfalls für eine ganz schlechte Idee.

Da hast du recht, das steht da auch nur zum Testen ob I = 
ina219.getCurrent_mA(); ausgeführt worden ist.

von Sandro N. (nick2245)


Lesenswert?

Sascha W. schrieb:
> solltest du
> Objekt so initialisieren das sie zum Aufrufzeitpunkt auch verfügbar
> sind.

Da hast du grundsätzlich recht aber wie du schon geschrieben hast spielt 
das hier keine rolle :-)

Achso, und ich bekomme keine Probleme beim Compiler .

von Stefan F. (Gast)


Lesenswert?

Sandro N. schrieb:
> das steht da auch nur zum Testen

Dachte ich mir schon.

von Einer K. (Gast)


Lesenswert?

Sandro N. schrieb:
> Sascha W. schrieb:
>> solltest du
>> Objekt so initialisieren das sie zum Aufrufzeitpunkt auch verfügbar
>> sind.
>
> Da hast du grundsätzlich recht aber wie du schon geschrieben hast spielt
> das hier keine rolle :-)
>
> Achso, und ich bekomme keine Probleme beim Compiler .

Aber, das Problem, hast du jetzt verstanden, oder?

von Brain 2.0 (Gast)


Lesenswert?

Und warum überhaupt per IRQ ?
1 sek ist doch nicht zeitkritisch, das geht auch wunderbar in der loop.

von Sascha W. (sascha-w)


Lesenswert?

Brain 2.0 schrieb:
> Und warum überhaupt per IRQ ?
> 1 sek ist doch nicht zeitkritisch, das geht auch wunderbar in der loop.
Oder besser noch, im IRQ ein Flag setzen und in der Loop darauf 
reagieren. In Loop darf dann natürlich kein delay vorkommen.

Sascha

von Stefan F. (Gast)


Lesenswert?

Sascha W. schrieb:
> Oder besser noch, im IRQ ein Flag setzen und in der Loop darauf
> reagieren.

Dann kannst du auch gleich den millis() Timer benutzen.

von Brain 2.0 (Gast)


Lesenswert?

Sascha W. schrieb:
> Oder besser noch, im IRQ ein Flag setzen und in der Loop darauf
> reagieren. In Loop darf dann natürlich kein delay vorkommen.

Ok....aber besser sehe ich nicht.
Hier braucht man keinen IRQ.

von Sandro N. (nick2245)


Lesenswert?

Sascha W. schrieb:
> Oder besser noch, im IRQ ein Flag setzen und in der Loop darauf
> reagieren. In Loop darf dann natürlich kein delay vorkommen.

ja, so habe ich das jetzt auch gelöst. Ich musste nur sicherstellen, 
dass der Code in einer Stunde genau 3600 mal ausgeführt wird.
Solange der Loop nicht länger als 1 Sekunde braucht sollte das auch 
funktionieren.
Ich hatte mich schon gefragt wozu so ein "Job Flag" gut sein soll. Mann 
kann ja alles in die ISR schreiben dachte ich. Aber in meinem Fall ging 
es eben doch nur über eine "Flag".

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Sascha W. schrieb:
> Brain 2.0 schrieb:
>> Und warum überhaupt per IRQ ?
>> 1 sek ist doch nicht zeitkritisch, das geht auch wunderbar in der loop.
> Oder besser noch, im IRQ ein Flag setzen und in der Loop darauf
> reagieren. In Loop darf dann natürlich kein delay vorkommen.
>
> Sascha

Oder in der IRQ erst den ADC-Wert sichern und dann den ADC neu starten.
So bracht man nicht Warten bis der ADC fertig ist, dar hat dann fast 
eine Sekunde zeit um fertig zu werden. Die Werte sind dann zwar eine 
Sekunde alt, dafür aber nirgends Wartezeiten wegen dem ADC. Und in 
etlichen Anwendungsfällen ist das durchaus langt das durchaus.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Sandro N. schrieb:
> Solange der Loop nicht länger als 1 Sekunde braucht sollte das auch
> funktionieren.
Für mich enthält eine main()-Loop, die mehr als 50ms(*) braucht, schon 
einen Fehler. Denn dort drin wird zyklisch alles abgearbeitet, was 
während des letzten Durchlaufs in den Interrupts so angefallen ist.

(*) je nach Anwendung 10..100ms

: Bearbeitet durch Moderator
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.