Problem mit TinyWireS

Hallo zusammen,

ich hab ein kleines Problem mit der Kommunikation zwischen ATtiny und Arduino…

Ich würde den ATtiny gerne nutzen um mehrere Schalter bzw ein Keypad auszuwerten/abzufragen und dann bei betätigung eines Tasters ein Wert an den Arduino schicken…

ich hoffe ihr könnte mir da ein Tipp geben ?
denke mal das hat was mit dem internen Timer oder dem Takt zu tun ?

so klappts:

"#include <TinyWireS.h>
#define I2C_SLAVE_ADDRESS 0x26

const int LED = 15;

void setup()
{

TinyWireS.begin(I2C_SLAVE_ADDRESS);

}

void loop()
{

byte X;
X = 11;
TinyWireS.send(X);

}
"

so dann nicht mehr:
"
#include <TinyWireS.h>
#define I2C_SLAVE_ADDRESS 0x26

const int LED = 15;

void setup()
{

TinyWireS.begin(I2C_SLAVE_ADDRESS);

pinMode(LED, OUTPUT);
}

void loop()
{

byte X;
X = 11;

digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
TinyWireS.send(X);
delay(500);
}

"

und so auch nicht:
"
#include <TinyWireS.h>
#define I2C_SLAVE_ADDRESS 0x26

const int LED = 15;

const int R1 = 0;
const int R2 = 1;
const int R3 = 2;
const int R4 = 3;
const int C1 = 4;

void setup()
{
TinyWireS.begin(I2C_SLAVE_ADDRESS);

pinMode(LED, OUTPUT);

pinMode(R1, OUTPUT);
pinMode(R2, OUTPUT);
pinMode(R3, OUTPUT);
pinMode(R4, OUTPUT);

pinMode(C1, INPUT);
digitalWrite(C1, HIGH);
}

void loop()
{

byte X;
X = 11;

digitalWrite(R1, LOW);
digitalWrite(R2, HIGH);
digitalWrite(R3, HIGH);
digitalWrite(R4, HIGH);

if (digitalRead(C1) == LOW)
{
TinyWireS.send(X);
}

}
"

Der ATtiny 4313 läuft auf 8MHZ, ohne Quarz. Arduino is Mega und an dem scheints nicht zu liegen.... Pull-Up-Widerstände sind auch vorhanden....

Code Tags verwenden!

Ein Slave darf eigentlich nicht ungefragt Daten senden. Das muss auf eine Anfrage per requestFrom() geschehen. TinyWireS hat zwar keinen onRequest() Event Handler, aber im Beispiel dazu ist das trotzdem so gedacht. Der Master muss also Pollen ob Daten zum Abholen vorhanden sind.

ich habs jetzt so ähnlich, wie hier probiert:

dafür bekomme ich:
sketch_oct28a.ino: In function ‘void setup()’:
sketch_oct28a:46: error: ‘class USI_TWI_S’ has no member named ‘onRequest’
sketch_oct28a.ino: In function ‘void loop()’:
sketch_oct28a:56: error: ‘TinyWireS_stop_check’ was not declared in this scope
‘class USI_TWI_S’ has no member named ‘onRequest’

in dem beispiel steht das auch im setup ?
aber ich will ja im loop taster abfragen und was senden ?

magictrips: Ich würde den ATtiny gerne nutzen um mehrere Schalter bzw ein Keypad auszuwerten/abzufragen und dann bei betätigung eines Tasters ein Wert an den Arduino schicken.....

Du hast den ATtiny als Slave definiert, da kann er sich nicht von sich aus beim Master melden. Drei Ansätze:

  1. Der ATtiny ist Master, der Mega als Slave
  2. Der ATtiny ist Slave und wird regelmäßig vom Master befragt
  3. Der ATtiny ist Slave und hat eine Datenleitung zusätzlich zu I2C, um neue Daten zu melden

Welchen Ansatz möchtest Du verfolgen?

PS.: Sorry, habe gestern "4313" vergessen gehabt, da rief schon der Sandmann :-*

Ich habe doch gesagt, dass es in TinyWireS keinen onRequest() Event Handler gibt! Jedenfalls nicht in der Version die du hast. Natürlich kennst der Compiler das nicht.

Schau dir das Beispiel dabei an: http://playground.arduino.cc/uploads/Code/TinyWireS.zip

Ansonsten wie agmue sagt anders herum machen. ATtiny als Master. Dann kannst du senden wann du willst

vielen dank erstmal !

ich würde dann ansatz 2 nehmen (;

ich habe auch noch eien rtc und ein luftdrucksensor am bus…

ich habe jetzt den sketch aus dem beispiel genommen:

#include "TinyWireS.h"                  // wrapper class for I2C slave routines

#define I2C_SLAVE_ADDR  0x26            // i2c slave address (38)
#define LED1_PIN         15              // ATtiny Pin 3
#define LED2_PIN         15              // ATtiny Pin 6

void setup(){
  pinMode(LED1_PIN,OUTPUT);             // for general DEBUG use
  pinMode(LED2_PIN,OUTPUT);             // for verification
  Blink(LED1_PIN,2);                    // show it's alive
  TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode
}


void loop(){
  byte byteRcvd = 0;
  if (TinyWireS.available()){           // got I2C input!
    byteRcvd = TinyWireS.receive();     // get the byte from master
    Blink(LED1_PIN,byteRcvd);           // master must wait for this to finish before calling Wire.requestFrom
    byteRcvd += 10;                     // add 10 to what's received
    TinyWireS.send(byteRcvd);           // send it back to master

    Blink(LED2_PIN,1);                  // show we transmitted
  }
}


void Blink(byte led, byte times){ // poor man's display
  for (byte i=0; i< times; i++){
    digitalWrite(led,HIGH);
    delay (250);
    digitalWrite(led,LOW);
    delay (175);
  }
}

da wartet der ja darauf das der master ihm was sendet ?

mein sketch für den master sieht so aus:

#include <Wire.h>
 #define I2C_SLAVE_ADDR  0x26           

 void setup() 
 {
     Wire.begin();
     Serial.begin(9600);
 }

 void loop() 
 {
     byte num;

     Wire.beginTransmission(0x26); // transmit to device #9
     Wire.write(0); // sends x
     Wire.endTransmission(); // stop transmitting
 
     // read 1 byte, from address 0x26
     Wire.requestFrom(I2C_SLAVE_ADDR, 1);

     while(Wire.available()) 
     {
          num = Wire.read();
     }
     

     Serial.print("num = ");
     Serial.println(num,DEC);
 }

ich vermute mal, da is irgendwo ein fehler drin ?

sorry, ich hab keien große ahnung davon und ich vermute mal, das es was kleines ist, wo ich aber stundenlang nach suchen würde (;
bzw hab ich shcon mal geschaut aber bisher nichts gefunden

Der nette Herr, der sich hier auch am Thema beteiligt, hatte mir mal ein Beispiel gegeben, bei dem der Master den Indexwert sendet und danach eine Anzahl Byte anfordert.

EDIT: Beispiel gelöscht, da irritierend.

ok, vielen dank !

der besagt nette herr, sollte meiner meinung nach ehe einen orden in form eines vergoldeten "C"s bekommen (;

wenn ich das richtig verstehe(das beispiel)....

wartet der darauf, das der master ihm X byte sendet ? dann blinkt die led X mal und der sendet X + 10 zurück und die led blinkt noch einmal ?

agmue: Der nette Herr, der sich hier auch am Thema beteiligt, hatte mir mal ein Beispiel gegeben, bei dem der Master den Indexwert sendet und danach eine Anzahl Byte anfordert.

Das Beispiel war ein Workaround weil man im OnRequest() Event Handler nur ein einziges mal write() machen kann. Das ist nicht dokumentiert und das war mir da nicht klar. Ich wunderte mich dass ich immer nur ein Byte Senden kann. Also ich habe da außen herum programmiert und es so gemacht dass immer nur ein Byte auf einmal angefordert wird.

Wenn ich sowas nochmal machen würde, würde ich einfach eine Union aus den einzelnen Variablen und einem Byte Array nehmen. Dann kann man mit write() mehrere Bytes mit einem Befehl senden. Man kann dann immer noch vom Master aus einen Start-Index setzen, aber es ist nicht mehr komplizierter als eigentlich nötig.

wartet der darauf, das der master ihm X byte sendet ? dann blinkt die led X mal und der sendet X + 10 zurück und die led blinkt noch einmal ?

Ja. Es geht eben darum dass man nur was macht wenn etwas gesendet wurde.

magictrips: der besagt nette herr, sollte meiner meinung nach ehe einen orden in form eines vergoldeten "C"s bekommen (;

Ich wäre gleich für mehrere Orden 8)

Noch eine Sache: Ich hatte da wohl eine Version von TinyWireS verwendet in der onRequest() implementiert ist. Das ist in der die er verwendet nicht vorhanden. Da muss man dann eben etwas anders vorgehen.

Überhaupt ist das Beispiel für die Anwendung nicht sehr sinnvoll. Das sollte man eher so machen, dass auf dem Slave immer der letzte Tastendruck gespeichert wird. Wenn dann der Master Daten anfordert schickt man z.B. 0 zurück wenn keine Taste gedrückt wurde und den Wert der Taste wenn eine gedrückt wurde. Das geht mit dem Beispiel aus der TinyWireS Version die ich oben verlinkt habe (was wahrscheinlich auch die Version ist die er schon hatte).

Also bitte hier nicht verschiedene Dinge durcheinander bringen. Das stiftet nur noch mehr Verwirrung.

ok, vielen dank !

bin ich denn "gezwunngen " die tinywireS version zu nehmen, die ich habe ? oder hat die andere vorteile ?

die taster sollen nach möglichkeit direkt reagieren…
also es geht da nicht um notaus usw aber um bedienung auf einem display usw, wäre natürlich doof, wenn dan dann jedes mal eien spührbare zeitverzögerung zwischen drücken und “sehen” ist…
aber an sich sollte der sketch doch auf einem atmega 1284 schnell genug laufen ?

ich verstehe aber immer noch nicht, wo mein fehler liegt…
habe den sketch jetzt noch mehr abgekürzt…

#include "TinyWireS.h"                  // wrapper class for I2C slave routines

#define I2C_SLAVE_ADDR  0x26            // i2c slave address (38)
#define LED1_PIN         15              // ATtiny Pin 3
#define LED2_PIN         10              // ATtiny Pin 6

void setup(){
  pinMode(LED1_PIN,OUTPUT);             // for general DEBUG use
  pinMode(LED2_PIN,OUTPUT);             // for verification
  TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode
}


void loop(){
  byte byteRcvd = 0;
  if (TinyWireS.available()){           // got I2C input!
    byteRcvd = TinyWireS.receive();     // get the byte from master
    Blink(LED1_PIN,byteRcvd);           // master must wait for this to finish before calling Wire.requestFrom
   
    //byteRcvd += 10;                     // add 10 to what's received
    //TinyWireS.send(byteRcvd);           // send it back to master

    Blink(LED2_PIN,1);                  // show we transmitted
  }
}


void Blink(byte led, byte times){ // poor man's display
  for (byte i=0; i< times; i++){
    digitalWrite(led,HIGH);
    delay (250);
    digitalWrite(led,LOW);
    delay (175);
  }
}

also die led blinkt X byte ???

und mein master:

#include <Wire.h>
 #define I2C_SLAVE_ADDR  0x26           

 void setup() 
 {
     Wire.begin();
     Serial.begin(9600);
 }

 void loop() 
 {
     byte num;
     byte x = 1;
     Wire.beginTransmission(I2C_SLAVE_ADDR);
     Wire.write(x); // sends x
     Wire.endTransmission(); // stop transmitting
 
     /*
     Wire.requestFrom(I2C_SLAVE_ADDR, 1);
     while(Wire.available()) 
     {
          num = Wire.read();
     }
     

     Serial.print("num = ");
     Serial.println(num);

     */
 }

das sind doch echt nur ein paar zeilen…
ich hab sogar mal ein lux-sensor mit software i2c ausgelesen…warum klappt das nicht…

Soll ich das Beispiel wieder löschen? Es funktioniert prima und kompiliert auch ohne Fehler.

Sehe gerade: Ich habe Variante 3 mit zusätzlicher Datenleitung zum "Hallo" sagen benutzt. Du merkst auch alles ...

also wenn ich das richtig verstanden habe, ist das beispiel für mich nicht geeignet ???

Von der Kommunikation her geht es, aber da wird ein Array für die Daten genommen. Das hatte ich so gemacht wie es auf einem IC ist, wo man verschiedene Speicherzellen für verschiedene Daten hat. Erstens würde ich das heute nicht mehr so machen (siehe #9) und zweitens ist das nicht was du eigentlich willst. Du hast nicht zig Bytes an Daten die du senden willst.

Wenn man schnell genug abfragt sollte das eigentlich zeitlich gehen. Oder nimm die andere Variante mit der extra Statusleitung. Dann kannst du melden wenn etwas gedrückt wurde und sofort abfragen. Sollte aber nicht zwingend nötig sein

Von der Funktion: Auf dem ATtiny85 dekodiere ich eine IR-Fernbedienung. Bei einem neuen Tastendruck setze ich die Datenleitung, um dem Master dies mitzuteilen. Der Master setzt den Index dann auf Null und fordert ein Byte mit der Nummer der Taste an.

Das kommt, so dachte ich zumindest, Deiner Funktionalität recht nahe.

Serenifly meint aber, ich hätte eine exotische Variante der Programmbibliothek, was mir nicht mehr so in Erinnerung war und womit ich auch keine Verwirrung stiften wollte. Ich kann Dir die exotische Variante anbieten oder Du machst mit der normalen weiter.

agmue: Serenifly meint aber, ich hätte eine exotische Variante der Programmbibliothek,

Nicht exotisch. Halt eine andere. Die Version hatte ich wohl auch da verwendet. In der Version sind die Event Handler implementiert. In der anderen nicht. Das muss man beachten. Darüber ist er ja schon gestolpert und hat sich gewundert wieso ein anderes Beispiel nicht funktioniert.

also mir is das ehrlich gesagt recht egal, was ich verwende, so lange es funktioniert.....

aber ich brauche ja nur das einfachste, was möglich ist.... nämlich nur ein byte senden, über zwei draht, da ich für drei drähte glaube ich keine pins mehr frei hab aber selbst das läuft ja nicht ):

In #7 habe ich Dir die von mir verwendete TinyWireS mit Eventhandler angehängt. In requestEvent() müßtest Du buf[index]=0 setzen für "nichts los".

Ist nur ein Angebot, ich mache jetzt was anderes ...