I2C Daten im Intervall Abrufen

Gast #6122472
Hallo,

ich habe ein Problem mit mein Kleinen Projekt.

Dabei soll jede Sekunde der Aktuelle Strom von einem INA219 abgerufen 
werden, und per Serielle Schnittstelle ausgegeben werden.

Jedoch sobald ich die Lese Routine über die ISR ausführen möchte hängt 
sich der Controller auf.

Lasse ich die Routine im Loop laufen funktioniert sie Fehlerfrei. Auch 
wenn ich zusätzlich in der ISR was anderes mache läuft der LOOP und die 
ISR problemlos.

Kann mir jemand dabei helfen.
1
#include <Wire.h>
2

3
#define Add_Current0 0x40
4
#define Add_Current1 0x41
5

6
#define R_Shunt0 0.1
7
#define R_Shunt1 0.1
8

9
#define Acc0 0.0001   // maximum = max Current/2^15
10
#define Acc1 0.0001
11

12
float data = 0;
13
void setup() 
14
{
15
  Wire.begin();
16
  Serial.begin(250000);
17
 
18
  current_write_Config(Add_Current0,0x399F);
19
  current_write_Config(Add_Current1,0x399F);
20

21
  current_write_Calibration(Add_Current0,R_Shunt0,Acc0);
22
  current_write_Calibration(Add_Current1,R_Shunt1,Acc1);
23

24
  Timer_Setup();
25
 
26
}
27
void loop() 
28
{
29
    
30
    
31

32
}
33

34
ISR(TIMER1_COMPA_vect)
35
{
36

37
  data = current_get_Current (Add_Current1,Acc1);
38
    Serial.println(data,4);
39
  
40
}
41

42
void current_write_Config (byte Addr, short data)
43
{
44
  
45
  Wire.beginTransmission(Addr);
46
  Wire.write(byte(0x00));
47
  byte transmit = data >> 8;
48
  Wire.write(transmit);
49
  
50
  transmit = data;
51
  Wire.write(transmit);
52
  
53
  Wire.endTransmission();
54
  
55
}
56

57
void Timer_Setup()
58
{
59
  TCCR1A = 0;
60
  TCCR1B = 0;
61
  OCR1A = 62500; //1Hz
62
  TCCR1B |= (1<<WGM12)| (1<<CS12);
63
  
64
  TIMSK1 |= (1<<OCIE1A);
65
    
66
}
67
void current_write_Calibration (byte Addr, float shunt, float acc)
68
{
69
  
70
  Wire.beginTransmission(Addr);
71
  Wire.write(byte(0x05));
72
  short data = trunc(0.04096/(acc*shunt));
73
  
74
  byte transmit = data >> 8;
75
  Wire.write(transmit);
76
  
77
  transmit = data;
78
  Wire.write(transmit);
79
  
80
  Wire.endTransmission();
81
  
82
}
83

84
float current_get_Current (byte Addr,float acc)
85
{
86
  
87
  Wire.beginTransmission(Addr); 
88
  Wire.write(byte(0x04));      
89
  Wire.endTransmission(); 
90
  short reading = 0;
91

92
   Wire.requestFrom(Addr, 2);
93
  
94
  if (2 <= Wire.available()) { // if two bytes were received
95
   reading = Wire.read();  // receive high byte (overwrites previous reading)
96
   reading = reading << 8;  // shift high byte to be high 8 bits
97
   reading |= Wire.read(); // receive low byte as lower 8 bits
98
  }
99
   
100
   float current = reading *acc ;
101
   
102
   return(current);
103
}
#6122486
wenn du die einfach in der Loop laufen lässt, wie schnell kommen denn 
dann die Werte?
Viel schneller als 1s oder langsamer?
Und wie ist es mit dem Timer?
Läuft der immer weiter? Oder muss der in der ISR einfach neu gestartet 
werden?
Sprich, ließt er einmal die Werte aus und stoppt dann? (Weil der Timer 
stehen geblieben ist).

Grüße, Jens
Gast #6122502
Also er blibt im Timer hängen.

Wenn ich dort nur mir die millis anzeigen lasse kommen die im Sekunden 
Takt.

das eine Print Funktion nix in der ISR zu suchen hat ist mir klar, war 
jetzt nur zum debuggen.

Die print Funktion soll später im Loop und nur ausgeführt werden, wenn 
ich neue Daten über die i2C empfangen habe.
Gast #6122506
hab den Datentyp geändert mit "volatile" geändert.

jedoch bleibt das Programm weiter vor der Print Funktion hängen, so das 
diese nicht ausgeführt wird.
Gast #6122517
Hab es auch mal so versucht, auch hier wird die Print funktion nicht 
ausgeführt.

Die unterprogramme welche unverändert sind habe ich mal jetzt nicht 
mitgesendet.
1
#include <Wire.h>
2

3
#define Add_Current0 0x40
4
#define Add_Current1 0x41
5

6
#define R_Shunt0 0.1
7
#define R_Shunt1 0.1
8

9
#define Acc0 0.0001   // maximum = max Current/2^15
10
#define Acc1 0.0001
11

12
volatile float data = 0;
13
volatile byte x = 0;
14
void setup() 
15
{
16
  Wire.begin();
17
  Serial.begin(250000);
18
 
19
  current_write_Config(Add_Current0,0x399F);
20
  current_write_Config(Add_Current1,0x399F);
21

22
  current_write_Calibration(Add_Current0,R_Shunt0,Acc0);
23
  current_write_Calibration(Add_Current1,R_Shunt1,Acc1);
24

25
  Timer_Setup();
26
 
27
}
28
void loop() 
29
{
30
    
31
    if (x==1)
32
    {
33
      Serial.println(data,4);
34
      x=0;
35
    }
36

37
}
38

39
ISR(TIMER1_COMPA_vect)
40
{
41

42
  data = current_get_Current (Add_Current1,Acc1);
43
  x=1;  
44
  
45
}
Gast #6122535
hab des rätsels Lösung.

Die Wire.h benötigt ebenfalls Interrupt befehle welche in der ISR 
deaktiviert sind.
habe jetzt zu beginn der ISR die Interrupts per sei(); aktiviert und es 
läuft.

keine schöne lösung, funktioniert aber schonmal.

falls jemand ein eleganteren vorschlag hat gerne her damit.
Gast #6122548
Weshalb muss die Abfrage der Daten in der ISR stattfinden? Setze in der 
ISR einfach ein Flag und werte es in der Loop aus.

Und überhaupt, weshalb für diesen Zweck einen Timer Interrupt? Bei einer 
Periode von 1 Sekunde kann das auch ein millis() Vergleich in der Loop 
erledigen.
Gast #6122587
wichtig ist, das der Daten abruf im sekunden intervall passiert. Da noch 
einiges mehr im Code später passiert, dann es sein das ein kompletter 
durchlauf länger dauert als eine sekunde.
#6122645
Hallo,

Nimm doch die Struktur aus dem Arduino Beispiel "blink without delay".

unsigned long millis_1s =0;

void loop(){

 if( millis() - millis_1s >= 1000){
 millis_1s+=1000;

 // Hier was du jede Sekunde ausgeführt haben willst

 }

 // Restlicher Code
}

Gruß
Gast #6122655
Michael V. schrieb:
> Nimm doch die Struktur aus dem Arduino Beispiel "blink without delay".

Er hat in seiner loop() noch andere Programmteile, die länger als 1 
Sekunde laufen können (vermutlich wegen großzügigem Delay-Einsatz)

---> loop umstrukturieren, dass ein durchlauf wieder nur eine sache von 
wenigen msec ist.

Eine Statemachine kann dabei helfen.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.