|

Komunikacja I2C w Arduino

Magistrala I2C (inter-integrated circuit), zwana również TWI (two wire interface), I2C, IIC to urządzenie do przesyłania danych na jednej linii (half duplex)

Komunikacja I2C w Arduino
Komunikacja I2C w Arduino

Interfejs I2C (Two-Wire) jest przydatny do łączenia wielu urządzeń, ponieważ wszystkie mogą dzielić te same dwa piny (oraz wspólny pin uziemienia).

Urządzenia w sieci I2C są „adresowalne”.
Adresy są przekazywane za pomocą 7 bitów, stąd zakres od 0 do 127.
Każde urządzenie musi mieć unikalny adres z zakresu od 8 do 119.
Adres 0 jest zarezerwowany jako adres „rozgłoszeniowy”, adresy od 1 do 7 są zarezerwowane do innych celów, a adresy od 120 do 127 są zarezerwowane na przyszłość.

Domyślny rozmiar bufora transmisji w bibliotece Wire wynosi 32 bajty. Oznacza to, że całkowity rozmiar danych, które można przesłać w jednej transmisji I2C (między Wire.beginTransmission() a Wire.endTransmission()), nie może przekroczyć 32 bajtów.

Adresowanie I2C w Arduino
Adresowanie I2C w Arduino

Połączenie I2C

I2C jest połączeniem open drain, to znaczy, że linie są normalnie w stanie wysokim, a komunikacja rozpoczyna się po zmianie stanu na niski.

Analog port 4 (A4) = SDA (serial data)
Analog port 5 (A5) = SCL (serial clock)

Piny SDA i SCL wymagają pull-up rezystora, aby utrzymywać je w stanie wysokim, zazwyczaj jest to 4.7K.
Atmega328 jest skonfigurowany z wewnętrznym pull-up rezystorem więc dla niewielkich sieci, na krótkich odległościach dodatkowe rezystory nie są niezbędne.
Interfejs I2C pozwala na komunikację synchroniczną, ponieważ jeden z przewodów SCL dyktuje taktowanie zegara.

Skaner urządzeń I2C

Funkcja Wire.endTransmission() zwraca kod statusu, który może być jednym z poniższych:

0: Sukces (success)

1: Przepełnienie bufora transmitera (data too long to fit in transmit buffer)

2: Adres NACK (received NACK on transmit of address)

3: Dane NACK (received NACK on transmit of data)

4: Inny błąd (other error)

#include <Wire.h>
#define WIRE Wire

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

void loop() {
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; address++) {
    WIRE.beginTransmission(address);
    error = WIRE.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");
      nDevices++;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);  // wait 5 seconds for next scan
}

Wizualizacja stanów logicznych linii CLK i DATA

Wizualizacja stanów logicznych linii CLK i DATA podczas wysyłania wartości 0x06 na adres 0x20 z częstotliwością 100kHz

Przesył danych I2C z analizatorem stanów logicznych
Przesył danych I2C z analizatorem stanów logicznych

Przesyłanie danych za pomocą interfejsu I2C

#include <Wire.h>
void setup() {
  Wire.begin();  //Aktywacja magistrali
  Wire.beginTransmission(0x30); //Inicjalizacja komunikacji z podanym adresem
  Wire.write(data); // Zapisanie 1 bajta danych do bufora
  Wire.endTransmission(); // Wysłanie danych i zakończenie komunikacji
}
void loop() {}

Dane odbiera się za pomocą eventu, który powinien być prosty i szybki w realizacji.  W funkcji receiveEvent można pobierać ilość przesłanych bajtów.

Wire.onReceive(receiveEvent);
void receiveEvent(int howMany){
  myData = Wire.read();
  bool a = bitRead(myData, 0);
  digitalWrite(13, a);
}

Przykład przesłania tablicy danych

#include <Wire.h>
void setup() {
  Wire.begin();
}

void loop() {
  Wire.beginTransmission(0x50);
  byte data[] = {1, 2, 3, 4, 5};
  Wire.write(data, sizeof(data));
  Wire.endTransmission();
  delay(1000);
}

Przesyłanie danych I2C pomiędzy 2 płytkami Arduino

Połączenie dwóch Arduino do komunikacji I2C
Połączenie dwóch Arduino do komunikacji I2C
//Master Arduino

#include <Wire.h>
const int SLAVE_ADDR = 0x20;
// 0x20 - 0b00100000
int counter = 0;
void setup() {
  delay(500);
}
void SendData(byte data){
  Wire.begin();
  Wire.beginTransmission(SLAVE_ADDR);
  Wire.write(data);
  Wire.endTransmission();
  delay(500);
}
void loop() {
  SendData(counter);
  counter++;
}
//Slave Arduino

#include <Wire.h>
const byte MY_ADDRESS = 0x20;
const int LED = 2;
void setup() {
  Wire.begin(MY_ADDRESS);
  pinMode(LED, OUTPUT);
  Wire.onReceive(receiveEvent);
  Serial.begin(9600);
}
void loop() {}

void receiveEvent() {
  while(Wire.available()){
    byte incData = Wire.read();
    Serial.println(incData);  
    digitalWrite(LED, incData%=2);
  }
}

Zobacz: Komunikacja I2C w Arduino

Zobacz: Komunikacja SPI w Arduino

Zobacz: Komunikacja radiowa SPI NRF24L01 z Arduino

Podobne wpisy

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *