ATtiny45 als Slave und Arduino MEGA 2560 als Master über I2C-Bus

Hallo,

ich habe ein kleines Problem mit meiner Schaltung.

Ich will ein Arduino Board als Master und mehrere Slaves in form von ATtiny 45 betreiben. Habe es auch so weit zum laufen bekommen, aber nur so weit das der Slave dem Master etwas übermittelt.

Meine Wunschvorstellung wäre es aber, dass der Master dem Slave einen Befehl übermittelt und der zwei Ausgangsports hat, die er AN und AUS schalten kann.

für meinen Master habe ich erstmal folgenden Code:


#include <TinyWireM.h>
#include <USI_TWI_Master.h>

void setup() 
{
  // put your setup code here, to run once:
  TinyWireM.begin();
  TinyWireM.requestFrom(requestEvent);
}

void loop() 
{

}

void requestEvent(uint8_t slaveAddr)
{
  TinyWireM.beginTransmission(2); //startet die Übertragung
  TinyWireM.send('F');                   //überträgt ein char zum Slave
  TinyWireM.endTransmission();     //beendet die Übertragung 
  delay(500);
  
  TinyWireM.beginTransmission(2);  //startet die Übertragung
  TinyWireM.send('d');                    //überträgt ein char zum Slave
  TinyWireM.endTransmission();      //beendet die Übertragung 
  delay(500);
}

für meinen Slave (ATtiny45) habe ich folgenden Code verwendet:


//i2c Slave
#include <TinyWireS.h>
#include <Wire.h>

void setup()
{
  TinyWireS.begin(2);                // join i2c bus with address #2
  TinyWireS.onReceive(receiveEvent); // register event
  
  pinMode(1 ,OUTPUT);
}

void loop()
{
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()

void receiveEvent(int howMany)
{
  while(TinyWireS.available())     
  {
    char c = TinyWireS.receive();     // receive byte as a character

    switch (c)
    {
      case 'd':
        digitalWrite(1 ,LOW);
        break;
      case 'F':
        digitalWrite(1 ,HIGH);
        break;
    }
   }
  }

Das hier sind die Keywords zu den Bibliotheken.


#######################################

Syntax Coloring Map For TinyWireM

#######################################

#######################################

Datatypes (KEYWORD1)

#######################################

#######################################

Methods and Functions (KEYWORD2)

#######################################

begin KEYWORD2
beginTransmission KEYWORD2
endTransmission KEYWORD2
requestFrom KEYWORD2
send KEYWORD2
receive KEYWORD2

#######################################

Instances (KEYWORD2)

#######################################

TinyWireM KEYWORD2

#######################################

Constants (LITERAL1)

#######################################


#######################################

Syntax Coloring Map For TinyWireS

#######################################

#######################################

Datatypes (KEYWORD1)

#######################################

#######################################

Methods and Functions (KEYWORD2)

#######################################

begin KEYWORD2
send KEYWORD2
available KEYWORD2
receive KEYWORD2

#######################################

Instances (KEYWORD2)

#######################################

TinyWireS KEYWORD2

#######################################

Constants (LITERAL1)

#######################################

Vielen Dank schon mal im Voraus.

für meinen Master habe ich erstmal folgenden Code:

Hier:

TinyWireM.requestFrom(requestEvent);

Verankerst du einen Callback. Dieser Callback wird nie aufgerufen, da es ja der Master ist. Der Master empfängt keine Requests.

Hier findest du einen lauffähigen Master: https://www.arduino.cc/en/Tutorial/MasterWriter

Hi combie,

ja das habe ich auch gesehen und noch schnell geändert. Aber benötige ich überhaupt die Bib. TinyWireM.h ? Geht das nicht genau so gut über die Wire.h bib.? So kann doch der Arduino ganz normal auf den I2C-Bus sprechen und jeder Attiny mithören.

#include <Wire.h>

//#define slaveAddr 2
void setup() {
  // put your setup code here, to run once:
  Wire.begin();
}

void loop() 
{
  // put your main code here, to run repeatedly:
  Wire.beginTransmission(2);
  Wire.write('F');
  Wire.endTransmission();
  delay(500);
  
  Wire.beginTransmission(2);
  Wire.write('d');
  Wire.endTransmission();
  delay(500);
}

also in diesem Fall würde ich mein Attiny mit der Adresse 2 ansprechen. So funktioniert es auch bei der Kommunikation zwischen 2 Arduino Boards.

Vielen Dank schon mal…

Gruß

Christoph

ja das habe ich auch gesehen und noch schnell geändert. Aber benötige ich überhaupt die Bib. TinyWireM.h ? Geht das nicht genau so gut über die Wire.h bib.? So kann doch der Arduino ganz normal auf den I2C-Bus sprechen und jeder Attiny mithören.

Naja.... Der Master ist der Mega2560, richtig? Dann benötigst du da die Wire Lib

Und die AtTinys sind die Slaves, richtig? Also wird da TinyWire gebraucht.

Die Library muss schon zum verwendetem Prozessor passen.

jo das habe ich ja auch jetzt gemacht und der Master funktioniert auch mit der Wire.h bib. Aber bei dem Slave habe ich es nicht geschafft mit der TinyWireS.h bib.

Aber ja der Master soll der Mega 2560 sein. Mit nem Display und einigen Steuerungsbuttons nachher..

Die ATtiny's sollen nur in den Slave-Boxen die Relais steuern. Diese Salve-Boxen sollen direkt neben dem Master stehen und über einen I2C-Bus verbunden werden. Vielen Dank noch mal.

Christophhericks: Die ATtiny's sollen nur in den Slave-Boxen die Relais steuern. Diese Salve-Boxen sollen direkt neben dem Master stehen und über einen I2C-Bus verbunden werden. Vielen Dank noch mal.

Wenn du nur Relais schalten willst, kannst du es doch einfacher lösen. Setze als Slave einen (oder mehr) Expander (PCF8574) ein. Der hat 8 Ports die sogar bidirektional verwendbar sind.

In irgendeinem Beitrag habe ich gelesen, dass es auch I2C-Relaiskarten gibt. Das wäre noch einfacher

Mit den Relaiskarten ist natürlich auch ne super Idee, aber leider recht teuer und meist mit mehr Relais als nötig sind. Auch sind die Relais meist nicht direkt für 230 Volt geeignet, wenn man es dann braucht. Ein PCF8574 hat 8 Ports, da kann man problemlos div. Relais und Leds dran betreiben.

Somit baust du dann eine eigene "I2C-Relaiskarte" :) :)

ElEspanol: Somit baust du dann eine eigene "I2C-Relaiskarte" :) :)

Ja, das ist richtig. Damit wird es deutlich billiger und ich kann den Baustein (PCF8574) auch als Eingang für Schalter o.ä. verwenden.

Die Relais kann ich bei 230 Volt Anwendung dann im Sicherungskasten (Hutschienenrelais) einbauen und habe dahin nur eine Niederspannungsleitung. Also mein Aufbau ist gefahrlos was die Netzspannung betrifft.

Natürlich hat das mit der fertigen Relaiskarte auch seinen Reiz, wenn man keine entsprechenden elektronischen Vorkenntnisse hat, ist das die bessere Lösung.

Der integrierte Schaltkreis MCP23017 von Microchip ist auch zu empfehlen wenn es ein paar I/O-Ports mehr sein dürfen(müssen). Liegt preisliche genauso wie der PCF8574 bietet aber doppelt so viel I/O-Ports.

Gruß Django

Den MCP23017 benutze ich auch für sowas. den anderen nur bei lcd Displays

Django83: Der integrierte Schaltkreis MCP23017 von Microchip ist auch zu empfehlen wenn es ein paar I/O-Ports mehr sein dürfen(müssen). Liegt preisliche genauso wie der PCF8574 bietet aber doppelt so viel I/O-Ports.

Gruß Django

Ja, das ist richtig. Allerdings habe ich bisher diese Anzahl von Ports nicht benötigt. Daher stellte sich bei mir noch nicht die Frage. Und von den PCF8574 habe ich vor langer Zeit eine größere Anzahl bestellt, das reicht erst mal. :)

Hallo Christoph,
hier ein paar Zeilen zum Probieren.

Master Mega2560:

#include "Wire.h"
#define ATTINY45_ADDR 0x03
char command;

void send_i2c(unsigned char address)
{
  Wire.beginTransmission(address);  // transmit to device address
  Wire.write(command);              // sends one byte
  Wire.endTransmission();           // stop transmitting
}

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

void loop() {
  if (Serial.available() > 0) {
    command = Serial.read();
    send_i2c(ATTINY45_ADDR);
  }
}

Slave ATtiny45:

// ATMEL ATtiny45/85
//
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) (SCL)
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1)
//            GND  4|    |5  PB0 (D 0) (SDA)
//                  +----+

#define I2C_SLAVE_ADDRESS 0x03 // the 7-bit address (remember to change this when adapting this example)
// Get this from https://github.com/rambo/TinyWire
#include <TinyWireS.h>
// in TinyWireS\usiTwiSlave.h auf 64 Byte geaendert
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 64 )
#endif

void receiveEvent(uint8_t howMany) {
  if (TinyWireS.available() > 0) {                         // returns the number of bytes in the received buffer
    byte a = TinyWireS.receive();      // returns the next byte in the received buffer
    switch (a) {
      case 'a':
        digitalWrite(3, HIGH);
        break;
      case 'b':
        digitalWrite(3, LOW);
        break;
      case 'c':
        digitalWrite(4, HIGH);
        break;
      case 'd':
        digitalWrite(4, LOW);
        break;
    }
  }
}

void setup()
{
  pinMode (3, OUTPUT);
  pinMode (4, OUTPUT);
  TinyWireS.begin(I2C_SLAVE_ADDRESS);
  TinyWireS.onReceive(receiveEvent);
}

void loop()
{
  /**
   * This is the only way we can detect stop condition (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=984716&sid=82e9dc7299a8243b86cf7969dd41b5b5#984716)
   * it needs to be called in a very tight loop in order not to miss any (REMINDER: Do *not* use delay() anywhere, use tws_delay() instead).
   * It will call the function registered via TinyWireS.onReceive(); if there is data in the buffer on stop.
   */
  TinyWireS_stop_check();
}

Mit den Buchstaben “a” bis “d” können die Ausgänge D3 und D4 ein und ausgeschaltet werden.

Ich hoffe, es hilft Dir.