
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:

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:

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:

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
}
