Hilfe bei I2C Arduino ATtiny

Hallo Leute,

ich versuche zwischen einem Arduino Nano und einem ATtiny84 Daten per I2C auszutauschen.
Leider bleibt mein Master in den send oder request schleifen hängen, ob der Slave alles richtig macht kann ich dadurch leider auch nicht sagen, aber dieser läuft wenigstens den loop fleißig durch.
Hoffentlich könnt ihr mir dabei weiterhelfen, habe noch nie zuvor I2C verwendet und komme einfach nicht mehr weiter.

Mal ein kleiner Überblick damit ihr wisst um was es geht.

Der Arduino(Master) soll per I2C Daten an den Slave senden

  • einen Status welchen ich mit den Zahlen 1-9 definiere wodurch verschiedene LED-Blinkmuster am Slave erzeugt werden sollen
  • PWM Helligkeit für die LED´s am Slave 0-255

und einen Wert von diesem empfangen.

  • eingelesener ADC wert von 0 bis 1023, welcher dann im Master den Status ändern kann.

Am liebsten würde ich einfach ein Array senden, ist das denn möglich ohne irgendwelche umwandlungen?

Der Arduino Nano wird zum Programmieren des ATtiny verwendet, funktioniert problemlos.
Anschließend lade ich den Master-Sketch auf den Arduino.

Falls gewünscht kann ich auch versuchen einen Schaltplan meines derzeitigen Aufbaus zu zeichnen, aber vorerst hier erstmal mein Code.
Er Kompiliert ohne Fehler und lässt sich aufspielen.

//Master Arduino Nano
#include <Wire.h>

#define I2C_ADDR 0x4
 
int brightness;
int state;
int button;
int dimADC = 19;                       // A0 ADC PIN
int dimVal;
 
void setup()
{
 Wire.begin(); // join i2c bus (address optional for master)
 Serial.begin(9600);
 pinMode(dimADC, INPUT);
 pinMode(9, OUTPUT);

 state = 8;
 
 
}
  
void loop() {
  
    digitalWrite(9, HIGH);             //loop test
    delay(50);
    digitalWrite(9, LOW);
    delay(50);
    
  Wire.requestFrom(I2C_ADDR, 1);      //stucks right after this

    while(Wire.available() > 0) {
    button = Wire.read();
    }
      

  if (button == 0) {
    state = 9;
  }
  if ((button == 1) || (button == 3)) {
    state = 1;
  }
  if (button == 2) {
    state = 6;
  }
  if (button == 4) {                     // The other states are not necessary at the moment 
    state = 7;
  }


     dimVal = analogRead(dimADC)/ 4;
 
  
    Wire.beginTransmission(I2C_ADDR);       // send the address 
    Wire.write(state);
    Wire.write(dimVal);
    Wire.endTransmission(); 

 
}
//Slave ATtiny 84
#include <TinyWireS.h>              // I2C Bib
#define I2C_ADDR 0x4                // Slaveadress 7 Bit
#define INTERNAL2V56_NO_CAP (6)     // VREF pin 0, no capacitor
int button;
                                    // 0 = nothing pressed
                                    // 1 = left button pressed 
                                    // 2 = right button pressed
                                    // 3 = both pressed
                                    // 4 = Error
                               
int a;                              //ADC-value 0 to 1023
int pwm;                            //PWM 0 to 255
int adcPin = 1;                     //ADC in for Button
int green = 8;                      //Status LED green
int red = 7;                        //Status LED red
int backlight = 5;                  //LED Backlight
int d;                              //1-9 Blinkmodi

void setup() {
  TinyWireS.begin(I2C_ADDR);        //Adress slave
  TinyWireS.onRequest(requestEvent);
  TinyWireS.onReceive(receiveEvent);
  
  pinMode(green,OUTPUT);            // LED green
  pinMode(red, OUTPUT);             // LED red    
  pinMode(backlight, OUTPUT);       // Backlight
  pinMode(adcPin, INPUT);           // Button ADC
  pinMode(0, OUTPUT);               // VREF 2.56V for ADC ???

  analogReference( INTERNAL2V56_NO_CAP );

}

void loop() {

TinyWireS_stop_check();

analogWrite(backlight, pwm);              // backlight
if (d == 1) {
          analogWrite(green, pwm);         // blink patterns
          delay(500);
          analogWrite(green, 0);
          delay(500); }
if (d ==2) { analogWrite(green, pwm);         
          delay(1000);
          analogWrite(green, 0);
          delay(1000);
          analogWrite(green, pwm);         
          delay(500);
          analogWrite(green, 0);
          delay(500); 
          analogWrite(green, pwm);
          delay(500);
          analogWrite(green, 0);
          delay(500); }
if (d == 3) { analogWrite(green, pwm);        
          delay(1000);
          analogWrite(green, 0);
          delay(1000); }
if (d == 4) { analogWrite(red, pwm);         
          delay(1000);
          analogWrite(red, 0);
          delay(1000);     
          analogWrite(red, pwm);         
          delay(1000);
          analogWrite(red, 0);
          delay(5000);   }  
if (d == 5) { analogWrite(red, pwm);         
          delay(1000);
          analogWrite(red, 0);
          delay(1000);   }
if (d == 6) { analogWrite(red, pwm);         
          delay(500);
          analogWrite(red, 0);
          delay(500);     }     
if (d == 7) { analogWrite(red, pwm);   }      
if (d == 8) { analogWrite(green, 0);          
          analogWrite(red, 0);         }        
if (d == 9) { analogWrite(green, pwm);  }      

  
    a = analogRead (adcPin);
    if ((a == 0) || (a > 1022)){               // Error
        button = 4;
    }
    if ((a > 0) && (a <= 255)){                // nothing pressed
        button = 0;
    }
    if ((a > 255) && (a <= 510)) {             // 1 pressed
        button = 1;
    }
    if ((a > 510) && (a <= 765)) {             // 2 pressed
        button = 2;
    }
    if ((a > 765) && (a <= 1022)){             // 1 and 2 Pressed 
        button = 3;
    }
    
 
}

void requestEvent() {
    TinyWireS.send(button);                   // send button state
    }

void receiveEvent() {
    if(TinyWireS.available()) {
    d = TinyWireS.receive();
    pwm = TinyWireS.receive();
    }
}

Die Verwendete Bibliothek für den ATtiny ist von hier: GitHub - svoisen/TinyWire: My modifications to TinyWire Arduino libs
Vielen Dank schonmal für eure Hilfe
Liebe Grüße, d3dx9

Deine Sketche sind schlecht bis überhaut nicht zu lesen.

In einem Mobilgerät überhaupt nicht.
Setze den bitte in Code-Tags.

Verwende dazu die Schaltfläche </> oben links im Editorfenster.
Das kannst du auch nachträglich machen.
Dazu den Sketch markieren und die Schaltfläche klicken.

Damit wird dieser für alle besser lesbar.

Ich sehe aber auch nicht, dass du in der Loop die I2C-Schnittstelle abfragst.

Überflüssiger Weise im Setup schon.

Zusätzlich zu dem von hotsystems gesagten töten Dir die ganzen Delays mit hoher Wahrscheinlichkeit jegliche Kommunikation. Schaue Dir besser millis(), BilinkWithoutDelay und die Nachtwächtererklärung an.

Gruß Tommy

Danke für die schnellen Antworten habe es mal geändert :slight_smile: Soll ich noch ein paar mehr Kommentare hinzufügen oder ist das in Ordung soweit?

In den Codebeispielen (hauptsächlich von http://www.mauroalfieri.it/?s=attiny84) welche ich verwendet habe waren diese abfragen auch im setup,
wie gesagt ich habe noch nie mit I2C gearbeitet und stehe da leider etwas auf dem schlauch.

Gut ich versuche mal bis morgen die delays loszuwerden.

LG d3dx9

So einfach wie das Anfänger meistens versuchen ist das nicht. Was fast immer übersehen wird, ist dass man mit read()/receive() nur ein Byte einlesen kann! Bei 0-9 und 0-255 reicht ein Byte. Bei 0-1023 fliegst du aber auf die Schnauze

Hier habe ich gezeigt wie man Multi-Byte Variablen überträgt:
http://forum.arduino.cc/index.php?topic=407599.msg2804476#msg2804476

Das ist da für die normale Wire Klasse, aber das geht mit etwas Anpassung auch mit TinyWire (siehe unten)

Passe deine Datentypen entsprechend an. Und wenn du nur Werte von 0-255 hast, dann verwende byte statt int!

Am liebsten würde ich einfach ein Array senden, ist das denn möglich ohne irgendwelche umwandlungen?

Ja, da geht. Aber besser ist ein struct (bzw. eine union aus einem Array und einem struct). Dann hat man getrennte, klar benannte Variablen, aber kann diese für die Übertragung wie ein Array behandeln

Wo sich TinyWire und Wire unterscheiden ist dass TinyWire nicht von Stream abgeleitet ist und keine Methode hat um mehr als ein Byte auf einmal zu senden! Aber du kannst mit einer for-Schleife über das Array iterieren und jedes Byte einzeln mit send() schicken (so wie es im Receive Event Handler beim Lesen gemacht wird). Das geht wiederum in der Wire-Klasse nicht! Da kann man im Request Event Handler nur einmal write() machen, was auch eine beliebte Fehler-Quelle ist

Möglicherweise findest Du im Thema Problem mit TinyWireS Anregungen für Dich.

So Danke nochmal für eure Anregungen.

Habe alle Daten in byte geändert und die delays durch millis() gelöst.
Blinkmodi 2 ist leider etwas wirr codiert, da mit der Funktion eigenlich immer mit einer Pause begonnen wird und das hier den "Rhythmus" zerstört.
(OO--O-O-)

Danach hatte es immernoch nicht funktioniert und nach etwas rumprobieren ist mir aufgefallen das ich vor dem ersten Wire-befehl im loop() nur einen beliebigen Digitalpin einschalten muss (blinken mit mills() funktioniert hier nicht komischerweise), dann bleibt er nichtmehr stecken und alles funktioniert wie gewollt.
Wohl irgend ein Timingproblem.

Der Pin für den ADC war auch falsch, hier musste ich A1 angeben und nicht 19... also kann man auch keinem Pinlayout blind vertrauen.

Ein Problem bleibt leider, wenn ich die Masse der LED mit auf GND des ATtiny lege, gibt es sichtbare Störungen.
Auf der Arduinomasse flackert nichts und wenn ich die Anzahl der Massekabel vom ATtiny zum Arduino auf 3 erhöhe ist das Flackern auch nichtmehr sichtbar. Könnte ein Kondensator hier Abhilfe schaffen?

Vollständigkeitshalber noch der funktionierende Sketch, vielleicht kann es ja mal jemand brauchen.

//Master Arduino Nano
#include <Wire.h>

#define I2C_ADDR 0x4
 

byte d;
byte button;
int dimADC = A1;                       // A0 ADC PIN
byte dimVal;
unsigned long previousMillis = 0;
unsigned long currentMillis;
const long interval = 500;
boolean ledState = LOW;

 
void setup()
{
 Wire.begin(); // join i2c bus (address optional for master)
 Serial.begin(9600);
 pinMode(dimADC, INPUT);
 pinMode(9, OUTPUT);
 pinMode(8, OUTPUT);
 

 
 
}
  
void loop() {

//    currentMillis = millis();                                   
//    if (currentMillis - previousMillis >= interval) {               //looptest (es blinkt nur ohne Wire.requestFrom)
//            previousMillis = currentMillis;
//            if (ledState == LOW) {
//              ledState = HIGH;
//              analogWrite(9, 200);
//            }
//            else {
//              ledState = LOW;
//              analogWrite(9, 0);
//            }
//          }

    analogWrite(9, 200); 
     
    Wire.requestFrom(I2C_ADDR, 1);      //stucks right after this
     
    analogWrite(8, 200);
     
   while(Wire.available()) {
    button = Wire.read();
   }
      

  if (button == 0) {
    d = 9;
  }
  if ((button == 1) || (button == 3)) {
    d = 1;
  }
  if (button == 2) {
    d = 6;
  }
  if (button == 4) {                     // The other states are not necessary at the moment 
    d = 7;
  }


    dimVal = analogRead(dimADC)/ 4;
    
 
  
    Wire.beginTransmission(I2C_ADDR);       // send to 
    Wire.write(d);
    Wire.write(dimVal);
    Wire.endTransmission(); 
 
 
}

9000 Zeichen überschritten... hier der Sketch vom Slave und ein Bild vom Aufbau^^

//Slave ATtiny 84
#include <TinyWireS.h>              // I2C Bib
#define I2C_ADDR 0x4                // Slaveadress 7 Bit
#define INTERNAL2V56_NO_CAP (6)     // VREF pin 0, no capacitor
byte button = 0;
                                    // 0 = nothing pressed
                                    // 1 = left button pressed 
                                    // 2 = right button pressed
                                    // 3 = both pressed
                                    // 4 = Error
                               
int a;                              //ADC-value 0 to 1023
byte pwm = 0;                           //PWM 0 to 255
int adcPin = 1;                     //ADC in for Button
int green = 8;                      //Status LED green
int red = 7;                        //Status LED red
int backlight = 5;                  //LED Backlight
byte d = 8;                              //1-9 Blinkmodi
unsigned long previousMillis = 0;
unsigned long currentMillis;
const long interval1 = 500;
const long interval2 = 1000;
boolean ledGreenOn = LOW;
boolean ledRedOn = LOW;
int i = 0;                           //loopcounter
int x = 0;

void requestEvent() {
    TinyWireS.send(button);                   // send button state
    }

void receiveEvent() {
    if(TinyWireS.available()) {
    d = TinyWireS.receive();
    pwm = TinyWireS.receive();
    }
    }

void setup() {
  TinyWireS.begin(I2C_ADDR);        //Adress slave
  TinyWireS.onRequest(requestEvent);
  TinyWireS.onReceive(receiveEvent);
  
  pinMode(green,OUTPUT);            // LED green
  pinMode(red, OUTPUT);             // LED red    
  pinMode(backlight, OUTPUT);       // Backlight
  pinMode(adcPin, INPUT);           // Button ADC
  pinMode(0, OUTPUT);               // VREF 2.56V for ADC ???

  analogReference( INTERNAL2V56_NO_CAP );


}

void loop() {

TinyWireS_stop_check();

analogWrite(backlight, pwm);              // backlight

currentMillis = millis();

if (d == 1) {         
          analogWrite(red, 0);
          ledRedOn = LOW;
          if (currentMillis - previousMillis >= interval1) {
            previousMillis = currentMillis;
            if (ledGreenOn == LOW) {
              ledGreenOn = HIGH;
              analogWrite(green, pwm);
            }
            else {
              ledGreenOn = LOW;
              analogWrite(green, 0);
            }
          }
}
if (d ==2) { 
           analogWrite(red, 0);
           ledRedOn = LOW;
           if (x == 0) {
           analogWrite(green, pwm);
           ledGreenOn = HIGH;
           x++;
           }
           if (x == 1) {
                if (currentMillis - previousMillis >= interval1) {
                previousMillis = currentMillis;
                    x++;
                    analogWrite(green, 0);
                    ledGreenOn = LOW;
                    }
                }
                   
           if (x == 2) {
                if (currentMillis - previousMillis >= interval1) {
                previousMillis = currentMillis;
                     x++;
           }
                   
           }
           if ((x > 2) && (x < 6))   {
            if (currentMillis - previousMillis >= interval1) {
            previousMillis = currentMillis;
            if (ledGreenOn == LOW) {
              ledGreenOn = HIGH;
              analogWrite(green, pwm);
            }
            else {
              ledGreenOn = LOW;
              analogWrite(green, 0);
              x++;
            }
          } 
           }
           if (x >= 6){
            x = 0;
           }
}  
if (d == 3) {   
          analogWrite(red, 0);
          ledRedOn = LOW;
          if (currentMillis - previousMillis >= interval2) {
            previousMillis = currentMillis;
            if (ledGreenOn == LOW) {
              ledGreenOn = HIGH;
              analogWrite(green, pwm);
            }
            else {
              ledGreenOn = LOW;
              analogWrite(green, 0);
            }
          }
}
if (d == 4)  {   
          analogWrite(green, 0);
          ledGreenOn = LOW;
          if (i <= 1){
            if (currentMillis - previousMillis >= interval2) {
              previousMillis = currentMillis;
              if (ledRedOn == LOW) {
                ledRedOn = HIGH;
                analogWrite(red, pwm);
                } else {
              ledRedOn = LOW;
              analogWrite(red, 0);
              i++;
                }
          } 
          }
          if ((i >= 2) || (i <=5)) {
            if (currentMillis - previousMillis >= interval2) {
              previousMillis = currentMillis;
              analogWrite(red, 0);
              i++;
          } 
            }
          if (i > 5) {
            i = 0;
          }
}
if (d == 5) {   
          analogWrite(green, 0);
          ledGreenOn = LOW;
          if (currentMillis - previousMillis >= interval2) {
            previousMillis = currentMillis;
            if (ledRedOn == LOW) {
              ledRedOn = HIGH;
              analogWrite(red, pwm);
            }
            else {
              ledRedOn = LOW;
              analogWrite(red, 0);
            }
          }
}
if (d == 6) {  
          analogWrite(green, 0);
          ledGreenOn = LOW;
          if (currentMillis - previousMillis >= interval1) {
            previousMillis = currentMillis;
            if (ledRedOn == LOW) {
              ledRedOn = HIGH;
              analogWrite(red, pwm);
            } else {
              ledRedOn = LOW;
              analogWrite(red, 0);
            }
          }
        }    
if (d == 7) { analogWrite(red, pwm);
              ledRedOn = HIGH;
              analogWrite(green, 0);
              ledGreenOn = LOW;}      
if (d == 8) { analogWrite(green, 0);
              ledGreenOn = LOW;          
              analogWrite(red, 0); 
              ledRedOn = LOW;}        
if (d == 9) { analogWrite(green, pwm);
              ledGreenOn = HIGH;
              analogWrite(red, 0);
              ledRedOn = LOW;}      

  
    a = analogRead (adcPin);
    if ((a == 0) || (a > 1022)){               // Error
        button = 4;
    }
    if ((a > 0) && (a <= 255)){                // nothing pressed
        button = 0;
    }
    if ((a > 255) && (a <= 510)) {             // 1 pressed
        button = 1;
    }
    if ((a > 510) && (a <= 765)) {             // 2 pressed
        button = 2;
    }
    if ((a > 765) && (a <= 1022)){             // 1 and 2 Pressed 
        button = 3;
    }
    
 
}