Probleme mit Wire.requestFrom

Hallo Leute,
so jetzt werd ich mal vom Leser zum Nutzer :wink:
Bin grad dabei ein einfaches USB-Oszi zu bauen, funktioniert auch alles soweit, nur ein Problem stellt sich mir grad wofür mir absolut kein Lösungsansatz einfällt.
Bisher hab ich den internen A/D Wandler genützt um meine PC-Software mit Daten zu versorgen. Um negative Spannungen zu messen wollte ich jetzt den PCF8591P einsetzen, was wie man sich denken kann nicht ganz funktioniert.
Das heist der PCF8591P funktionert schon, die I2C-Kommunikation funktioniert in einem kleinen Testprogramm auch wunderbar und wenn ich die Daten an den PC weiterleite versteht dieser die auch.
Allerdings wenn ich den Code in meinem eigentlichen Programm ausführen möchte, dann hängt sich der Arduino bei Wire.Request(72, 2); auf! Wichtig wäre noch zu erwähnen das der Aufruf in der Interruptroutine von FlexiTimer2 stattfindet, vielleicht liegt da das Problem.

So jetzt mal zum Code, mein kleines Testprogramm, welches funktioniert:

#include <Wire.h>
char c;
void setup()
{
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop()
{
  Wire.requestFrom(72, 1);    // request 6 bytes from slave device #2

  while(Wire.available())    // slave may send less than requested
  { 
   c = Wire.receive(); // receive a byte as character
    Serial.print(c);         // print the character
  }

  delay(50);
}

Meine Interruptroutine welche nicht will (lcd.print ist nur dafür da um zu sehen wo´s hängt):

void Get_Analog (){
    if (Analog_Neu == false){
  //Analog_Wert = analogRead(0);
  lcd.print("0");
  Wire.requestFrom(72, 1);
  lcd.print("1");
  while(Wire.available()){
        lcd.print("2");
 Analog_Wert = Wire.receive();
    lcd.print("3");
  Analog_Neu = true;
  }
    //Analog_Neu = true;
  }
  else
  {
    FlexiTimer2::stop();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Fehler 1");
  }
}

Und zum Schluss noch der gesamte Programmtext:

#include <FlexiTimer2.h>
#include <LiquidCrystal.h>
#include <Wire.h>

LiquidCrystal lcd(12,11,5,4,3,2); //Interface definieren

int Analog_Wert = 0;
boolean Analog_Neu = false;

void setup(){
  FlexiTimer2::set(50,Get_Analog);//(interruptinterval in ms, ISR)
  Serial.begin(115200);
  lcd.begin(16,2); //Spalten/Zeilen
  lcd.clear();
  Wire.begin();
  
  Wire.beginTransmission(72);
  Wire.send(48);//Anzwählen der richtigen PCF8591P Funktion
  Wire.endTransmission();
}
void loop (){
  int Rec = 0;
  int x = 0; //Schleifendurchlaufzähler, wird ggf an mehreren Stellen
         //verwendet. Der Zählerstand hat nach der Schleife keine
         //Relevanz mehr und wird vor beginn der Schleife neu 
         //initialisiert wird.

  if (Analog_Neu == true){
    //Serial.print (Analog_Wert);
    Serial.write (Analog_Wert);
    //Serial.print(" ");
    Analog_Neu =false;
    /*lcd.clear();
    lcd.setCursor(0,1);
    lcd.print (int((Analog_Wert/1023.0)*5000));
    lcd.print("mV");*/
  }
  if (Serial.available()){
    FlexiTimer2::stop();//Interrupt anhalten damit USB ohne unterbrechung gelesen werden kann
    Rec = Serial.read();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(Rec,DEC);
  }
  switch (Rec)
  {
  case 49: //ASCII 1 Interrupt starten
    FlexiTimer2::start();
    break;        
  
  case 50: //ASCII 2 Interrupt stop
    FlexiTimer2::stop();
    break;        
  
  case 51: //ASCII 3 Abtastrate setzen
      FlexiTimer2::stop();
     x=0;
    do{
    if (Serial.available()){
      Abtastrate_setzen(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;
    
  case 52: //ASCII 4 Spannungsbereich setzen
    FlexiTimer2::stop();
    x=0;
    do{
    if (Serial.available()){
      Spannungsbereich_setzen(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;    
    
  /*case 53: //ASCII 5 Triggerpunkt setzen
    x=0;
    do{
    if (Serial.available()){
      Set_Trigger(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;*/
  }
}
void Analog(){

}
void Get_Analog (){
    if (Analog_Neu == false){
  //Analog_Wert = analogRead(0);
  lcd.print("0");
  Wire.requestFrom(72, 1);
  lcd.print("1");
  while(Wire.available()){
        lcd.print("2");
 Analog_Wert = Wire.receive();
    lcd.print("3");
  Analog_Neu = true;
  }
    //Analog_Neu = true;
  }
  else
  {
    FlexiTimer2::stop();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Fehler 1");
  }
}

void Abtastrate_setzen (int Abtastrate){
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print(Abtastrate);
  
  switch (Abtastrate){
  case 49:
    FlexiTimer2::set(50,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 50:
    FlexiTimer2::set(100,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 51:
    FlexiTimer2::set(250,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 52:
    FlexiTimer2::set(500,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 53:
    FlexiTimer2::set(1000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 54:
    FlexiTimer2::set(2500,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 55:
    FlexiTimer2::set(5000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 56:
    FlexiTimer2::set(10000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 57:
    FlexiTimer2::set(25000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 48:
    FlexiTimer2::set(100000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  }
}

void Spannungsbereich_setzen (int Spannungsbereich){
  switch (Spannungsbereich){
  case 49:  Wire.beginTransmission(32);
            Wire.send(254); //K1 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 50:  Wire.beginTransmission(32);
            Wire.send(253); //K2 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 51:  Wire.beginTransmission(32);
            Wire.send(251); //K3 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 52:  Wire.beginTransmission(32);
            Wire.send(247); //K4 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 53:  Wire.beginTransmission(32);
            Wire.send(239); //K5 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 54:  Wire.beginTransmission(32);
            Wire.send(255); //alle Relais werden abgeschalten
            Wire.endTransmission();
  break;
  }
}

Ich hoffe irgendwer kann mir einen Brocken hinwerfen der mir weiterhilft! Ist wirklich wichtig, da es sich um meine Abschlussarbeit handelt (Abgabe ende November ANGST).
Vielen dank im Vorraus
MfG Jago

PS.: Wenn ich fertig bin stell ich das ganze hier mal vor, ist sicher nicht ganz uninteressant.

Wollt grad noch mein PC-Programm nachreichen, allerdings sprengt das die erlaubten 9500 Zeichen :roll_eyes: Wenn jemand interesse daran hat, einfach melden. Programmiersprache ist VB.Net

Hallo Ich glaube, es müsste so ablaufen:

Wire.beginTransmission(Deviceadresse); // I2C-Adresse Wire.send(Datenadresse); // Start-Byte Nr. Wire.endTransmission(); Wire.requestFrom(Deviceadresse, x) // x=Anzahl der zu lesenden Bytes a=Wire.receive(); b=Wire.receive(); c=Wire.receive();

Gruß Reinhard

Mh, das wäre ein ansatz den ich probieren sollte.
Eigentlich bin ich davon ausgegangen das sich der PCF8591 merkt was ich von ihm will, dh ich sende das Startbyte einmal im Setup und das sollte eigentlich reichen.
Nach meinen bissherigen Test´s braucht er noch nicht mal ein Startbyte, er liefert gleich irgendwelche Daten. Hab das einmal mit dem geposteten Testprogramm probiert und zum anderen mit einem einfachen USB zu I2C umsetzer. Beide male brauchte er ein Startbyte nicht, bzw keine zeitliche nähe zum Lesezugriff.
Probieren werd ich das aber morgen gleich mal, jetzt ist erstmal Bett angesagt. 04:30 klingelt der Wecker =(

MfG
Martin

In der Setup definierst Du ja das Start-Byte für den ersten/nächsten Zugriff. Das nächste mal greifst Du dann automatisch auf das nächste Byte zu. Um sicher zu gehen, das Startbyte also direkt vor dem Lese/Schreibzugriff zuweisen.

Gruß Reinhard

Den Gedanken hat ich schon aus deinem Beispielcode heraus verstanden.

Hab es auch grad probiert, mit dem Ergebnis das er sich beim senden des Startbytes aufhängt. Das Problem scheint also nicht speziell mit Wire.RequestFrom zu tun zu haben, sondern generell mit I2C Funktionen in Interruptroutinen. Unschön, jetzt weis ich erst recht nicht was ich machen soll. Werd mal probieren das auslesen im Hauptprogramm zu erledigen, das kann allerdings keine Lösung sein, da mir dann der definiert Messzeitpunkt fehlt. Weitergeholfen hat mir dein Tipp zumindest ein stückchen, Danke! MfG Martin

Na schau mal einer an, ich den wenn ich das Auslesen im Hauptprogramm erledige, dann geht´s.
Fazit wäre also das da ein problem bei I2C Funktionen in der FlexiTimer2 Interruptserviceroutine (ISR) ist.
Gefällt mir ja mal garnicht, das heist ich muss den Code von Wire.cpp und FlexiTimer2.cpp analysieren. Fehlt mir offengestanden ein wenig die Zeit für, Mist!
Mh, ich überleg grad ob ich das so verkaufen kann das der abstand zwischen zwei Messungen trotzdem gleich bleibt, da es sich um einen ungefähr konstanten Offset handelt.

Mein aktueller Code in der ISR:

void Get_Analog (){
    if (Analog_Neu == false){
    Analog_Neu = true;
  }
  else
  {
    FlexiTimer2::stop();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Fehler 1");
  }
}

Code im Hauptprogramm:

  if (Analog_Neu == true){
    Wire.requestFrom(72, 2);
    while(Wire.available()){
      Analog_Wert = Wire.receive();
     }
    Serial.print(Analog_Wert);
       Analog_Neu =false;
  }

Und der vollständige Code:

#include <FlexiTimer2.h>
#include <LiquidCrystal.h>
#include <Wire.h>

LiquidCrystal lcd(12,11,5,4,3,2); //Interface definieren

int Analog_Wert = 0;
boolean Analog_Neu = false;

void setup(){
  FlexiTimer2::set(50,Get_Analog);//(interruptinterval in ms, ISR)
  Serial.begin(115200);
  lcd.begin(16,2); //Spalten/Zeilen
  lcd.clear();
  Wire.begin();
  
  Wire.beginTransmission(72);
  Wire.send(48);//Anzwählen der richtigen PCF8591P Funktion
  Wire.endTransmission();
}
void loop (){
  int Rec = 0;
  int x = 0; //Schleifendurchlaufzähler, wird ggf an mehreren Stellen
         //verwendet. Der Zählerstand hat nach der Schleife keine
         //Relevanz mehr und wird vor beginn der Schleife neu 
         //initialisiert wird.

  if (Analog_Neu == true){
    Wire.requestFrom(72, 2);
    while(Wire.available()){
      Analog_Wert = Wire.receive();
     }
    Serial.print(Analog_Wert);
       Analog_Neu =false;
  }
  if (Serial.available()){
    FlexiTimer2::stop();//Interrupt anhalten damit USB ohne unterbrechung gelesen werden kann
    Rec = Serial.read();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(Rec,DEC);
  }
  switch (Rec)
  {
  case 49: //ASCII 1 Interrupt starten
    FlexiTimer2::start();
    break;        
  
  case 50: //ASCII 2 Interrupt stop
    FlexiTimer2::stop();
    break;        
  
  case 51: //ASCII 3 Abtastrate setzen
      FlexiTimer2::stop();
     x=0;
    do{
    if (Serial.available()){
      Abtastrate_setzen(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;
    
  case 52: //ASCII 4 Spannungsbereich setzen
    FlexiTimer2::stop();
    x=0;
    do{
    if (Serial.available()){
      Spannungsbereich_setzen(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;    
    
  /*case 53: //ASCII 5 Triggerpunkt setzen
    x=0;
    do{
    if (Serial.available()){
      Set_Trigger(Serial.read());
    }
    delay(1);
    x++;
    }
    while (x!=1500);
    break;*/
  }
}

void Get_Analog (){
    if (Analog_Neu == false){
    Analog_Neu = true;
  }
  else
  {
    FlexiTimer2::stop();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Fehler 1");
  }
}

void Abtastrate_setzen (int Abtastrate){
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print(Abtastrate);
  
  switch (Abtastrate){
  case 49:
    FlexiTimer2::set(50,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 50:
    FlexiTimer2::set(100,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 51:
    FlexiTimer2::set(250,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 52:
    FlexiTimer2::set(500,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 53:
    FlexiTimer2::set(1000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 54:
    FlexiTimer2::set(2500,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 55:
    FlexiTimer2::set(5000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 56:
    FlexiTimer2::set(10000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 57:
    FlexiTimer2::set(25000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  case 48:
    FlexiTimer2::set(100000,Get_Analog);//(interruptinterval in ms, ISR)
    break;
  }
}

void Spannungsbereich_setzen (int Spannungsbereich){
  switch (Spannungsbereich){
  case 49:  Wire.beginTransmission(32);
            Wire.send(254); //K1 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 50:  Wire.beginTransmission(32);
            Wire.send(253); //K2 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 51:  Wire.beginTransmission(32);
            Wire.send(251); //K3 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 52:  Wire.beginTransmission(32);
            Wire.send(247); //K4 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 53:  Wire.beginTransmission(32);
            Wire.send(239); //K5 wird angeschalten
            Wire.endTransmission();
  break;
  
  case 54:  Wire.beginTransmission(32);
            Wire.send(255); //alle Relais werden abgeschalten
            Wire.endTransmission();
  break;
  }
}