TWI ATtiny85 & Atmega328 (Uno)

Guten Abend allerseits!
Kann mich mal einer aufklären, warum bei einer TWI-Übertragung zwischen ATTiny 85 (Slave Sender) und Atmega328 teilweise negative Werte als Ergebnis ankommen?

ATtiny85
int sensorValue;
#include <Wire.h>

void setup() {
  pinMode(2, INPUT); // A3 !!!
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);
  delay(1000);
  digitalWrite(4, LOW);
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event
}

void loop() {
  delay(100);
  sensorValue = analogRead(A3);
  sensorValue = sensorValue / 4;
  if (sensorValue > 127) {
    digitalWrite(4, HIGH);
  }
  else {
    digitalWrite(4, LOW);
  }
}
void requestEvent() {
  Wire.write("Hello "); // respond with message of 6 bytes
  Wire.write(sensorValue);
  // as expected by master
}

Atmega

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

void loop() {
  byte a=0;
  Wire.requestFrom(8, 7);    // request 6 bytes from slave device #8

  while (Wire.available()) { // slave may send less than requested
    char c = Wire.read(); // receive a byte as character
    a++;
    if(a<7){    Serial.print(c);}
    else{b=c;
      Serial.print(b);}// print the character
  }
Serial.println();
  delay(500);
}

Das Hello aus dem ersten Wire.Write kommt richtig an.
Als zweite Ausgabe habe ich erst 0 - 127, die dann in -128 bis -1 übergeht.
PIN2 am ATTiny liest übrigens ein Poti aus.

Kann ich nicht, ich versuch es aber:

Dann schaun wa mal, was kommt:

Das ist bis dahin noch ok.
Das Problem ist schon vorher:

Während Du mit der LED darauf reagierst, das der INT

int sensorValue;

grösser ist, als das was in ein BYTE (

byte a=0;

) passt, machst Du daraus nichts.
Wenn Du auf ein Byte begrenzen willst, dann entweder das Maximum, oder aber umsteigen auf einen (unsigned) int. :wink:

while (Wire.available()) { // slave may send less than requested
    char c = Wire.read(); // receive a byte as character
    a++;
    if(a<7){    Serial.print(c);}
    else{byte b=c;
      Serial.print(b);}// print the character
  }

So kommt raus was soll. Verstehe ich nicht wirklich, aber nun. Das 'a' im zweiten Script ist übrigens eine Zählvariable um das 7. Byte zu erkennen.

Stimmt.
Aber trotzdem kannst Du einen int nicht in ein byte kippen:

Du schreibst im Atmega:

char c = Wire.read(); 

Aber sendest aus dem tiny:

sensorValue wird vorher schon auf:

getakkert, was bei 1023/4 zu 255 führt....

mit Deinem cast

byte b=c;

vermeidest Du das zwar - behebst aber nicht die Ursache.

Wire funktioniert bei Dir mit ATtiny85? Bei mir mit SpenceCode kommt da ein Fehler. Was verwendest Du für eine Hardwaredefinition?

Das habe ich auch länger gesucht.
In der Boarddefinition "ATtiny 25/45/85 (no Bootloader)"
Müsste der " SpenceKonde" sein.
Die Pinzuordnungen sind, nun ja, seltsam:
pinMode(2, INPUT); // ADC3 !!!
pinMode(1, OUTPUT); // PWM Pin6

Mein Tipp zu deinem Projekt:
Baue eine I2C-Verbindung zwischen den Systemen auf, bei der du nur einfache und bekannte Daten überträgst. Sobald das sicher funktioniert, erweitere das zu deinem Projekt.
Beim ATtiny habe ich bisher die Erfahrung gemacht, dass analoge Pins besser mit "Ax" definiert werden. Hängt sicher auch mit dem verwendeten core zusammen.

In Version 1.5.2 benötigt man wohl nicht mehr TinyWire, sondern kann Wire.h einbinden. Da habe ich was gelernt :slightly_smiling_face:

Eigentlich nicht, nur gibt es unterschiedliche, das kann irritieren, da bist Du nicht alleine. Daher steht am Anfang meiner Programme:

// ATMEL ATtiny45/85
//
//                +-\/-+
//        Reset  1|    |8  Vcc
// A3 (D 3) PB3  2|    |7  PB2 (D 2) A1 SCL
// A2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//          GND  4|    |5  PB0 (D 0) pwm0 SDA
//                +----+
  • Die Nummern 1 bis 8 sind die Pinnummern des ICs und haben keine Bedeutung für die Programmierung.
  • PBn: Port B Pin n; wird so im Datenblatt verwendet und auch digitalWrite(PB4, LOW); ebenso wie analogRead(PB3); ist möglich.
  • An: Bezeichnung für analogRead(An)
  • (D n): Pinnummer für digitalRead(n) und digitalWrite(n)

Zur flexiblen Übertragung via I2C eignet sich ein struct eingebettet in ein union. Im struct stehen die zu übertragenen Variablen, während der zweite Zeiger auf den selben Speicherbereich vom Typ byte einzig der byteweisen Übertragung dient. Wichtig ist, ANZAHL muß stimmen, sonst gibt es Murks!

// ATMEL ATtiny45/85 als I2C-Slave
//
//                +-\/-+
//        Reset  1|    |8  Vcc
// A3 (D 3) PB3  2|    |7  PB2 (D 2) A1 SCL
// A2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//          GND  4|    |5  PB0 (D 0) pwm0 SDA
//                +----+
#include <Wire.h>

const int ANZAHL = 9; // Wire möchte int!
const int SLAVEADR = 8; // Wire möchte int!

union {
  byte bytes[ANZAHL];
  struct {
    const char text[7] = {"Hallo "};
    int wert = 0;
  };
} A;


void setup() {
  pinMode(PB4, OUTPUT);
  digitalWrite(PB4, HIGH);
  delay(1000);
  digitalWrite(PB4, LOW);
  delay(1000);
  Wire.begin(SLAVEADR);         // join i2c bus with slave address
  Wire.onRequest(requestEvent); // register event
}

void loop() {
  delay(100);
  A.wert = analogRead(PB3);
  if (A.wert > 511) {
    digitalWrite(PB4, HIGH);
  }
  else {
    digitalWrite(PB4, LOW);
  }
}

void requestEvent() { // respond with message of 9 bytes as expected by master
  for (byte j; j < ANZAHL; j++) {
    Wire.write(A.bytes[j]);
  }
}
// UNO als I2C-Master
#include <Wire.h>

const int ANZAHL = 9; // Wire möchte int!
const int SLAVEADR = 8; // Wire möchte int!

union {
  byte bytes[ANZAHL];
  struct {
    char text[7];
    int wert = 0;
  };
} A;

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
  Serial.println(F("Start"));
}

void loop() {
  byte a = 0;
  Wire.requestFrom(SLAVEADR, ANZAHL);    // request bytes from slave device #8

  while (Wire.available()) { // slave may send less than requested
    A.bytes[a++] = Wire.read(); // receive a byte as character
  }
  Serial.print(A.text); Serial.println(A.wert);
  delay(500);
}

Viel Erfolg beim Testen!