I2C cz9

i2c

Magistrala I2C to dwukierunkowy interfejs, który wykorzystuje urządzenie nadrzędne (master) do komunikacji z urządzeniami podrzędnymi (slave). Urządzenie podrzędne musi posiadać swój własny adres urządzenia. Fizycznie interfejs I2C składa się z linii zegara szeregowego (SCL) i danych szeregowych (SDA).

Transmisja danych może być inicjowana tylko wtedy, gdy magistrala jest w stanie spoczynku - obie linie SDA i SCL mają stan wysoki po stanie STOP.

Opis działania magistrali na rysunku:

i2c

 

Aby wygenerować warunek START, master zmienia linię SDA z jedynki na zero, pozostawiając linię SCL w stanie wysokim. Następnie Master wyprowadza stan niski na linii SCL, aby przygotować magistralę do transmisji pierwszego bitu. Pierwsze 7 bitów to adres slave’a. 8 bit to bit decydujący czy dane będą nadawane do czy odbierane od slave’a. 9 bit to bit potwierdzający komunikację, ustawiany przez odbiorcę. Następnych 8 bitów to dane. 18 bit to znów bit potwierdzający.

Po zakończeniu transmisji Master generuje warunek STOP i zwalnia magistralę. Warunek STOP jest generowany przez zmianę linii SDA z niskiego na wysoki. Gdy SCL jest w stanie wysokim. Aby przygotować się na stan STOP, Master musi ustawić pierwsze linię SDA na zero podczas niskiej fazy zegara.

Zadanie:

Zbuduj układ, który będzie pobierał informacje z czujnika BMP180 i wyświetlał na ekranie.

Do zbudowania użyję:
  • Ekran LCD z konwerter I2C LCM1602
  • Czujnik BMP180
  • Arduino (użyłem MKR1010 wifi)
  • Użyłem również zewnętrznego zasilania dla Ekranu.
Interaktywny schemat:

I2C

Jak już wiemy po wstępie teoretycznym – każde urządzenie ma własny adres. Aby odczytać adres użyjemy gotowego programu, który odczyta adresy urządzeń i wyświetli je nam w monitorze portu szeregowego.

Kod skanera I2C:
#include <Wire.h>
 
void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("I2C Scanner");
}
 
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.println(address,HEX);
      nDevices++;
    }
    else if (error==4) {
      Serial.print("Unknow 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(10000);          
}

Przed wgraniem programu odłączamy urządzenia. Po wgraniu podłączamy po kolei tak aby wiedzieć, które urządzenie to który adres:

skaner

Poznaliśmy już adresy wiec możemy przejść do rozwiązania naszego zadania.

  • Czujnik BMP180 ma adres 0x77
  • Ekran 0x3F
Kod programu:
#include <Wire.h>

// Biblioteki które musimy zainstalować:
#include <Adafruit_BMP085.h>
#include "LiquidCrystal_I2C.h"

Adafruit_BMP085 bmp; // Definicja zmiennej bmp
LiquidCrystal_I2C lcd(0x3F,16,2); // Zdefiniowanie typu LCD, oraz adresu expandera
  
void setup() {
  lcd.init(); // Inicjalizacja wyświetlacza
  lcd.backlight(); // Ustawienie tła jasnego
   
  if (!bmp.begin()) {
    Serial.println("Nie znaleziono sensora BMP180!");
    while (1) {}
  }
}
  
void loop() {
  lcd.setCursor(0,0); // Ustawienie kursora
  lcd.print("Temp = "); // Wyświetlenie tekstu
  lcd.print(bmp.readTemperature()); // Odczytanie i wyświetlenie temperatury
  lcd.print(" C");
  
  lcd.setCursor(0,1); // Ustawienie cursora
  lcd.print("Pres = "); // Wyświetlenie tekstu
  lcd.print(bmp.readPressure()); // Odczytanie i wyświetlenie ciśnienia
  lcd.print(" Pa");  
    
  delay(1000); // Wstrzymanie programu na 1s
}