This is an old revision of the document!
Acest laborator acoperă noțiunea de I2C. Pentru aprofundarea acestui topic, consultați Datasheet ATmega328P și Inter-Integrated Circuit.
Protocolul I2C (sau IIC - Inter-Integrated Circuit / TWI - Two-Wire Interface) este un protocol de comunicație serială sincron, multi-master - multi-slave, dezvoltat de către Phillips în anul 1982. O magistrală I2C utilizează următoarele semnale:
Semnalul de ceas este generat de către master, însă linia de date este controlată ori de către master, ori de către slave, în funcție de faza protocolului, cu restricția ca, la un moment dat, un singur dispozitiv să transmită. Din acestă cauză protocolul I2C este half-duplex.
Față de SPI unde master-ul activa, prin intermediul semnalului de Slave Select, dispozitivul cu care dorea să comunice, I2C nu necesită un asemenea semnal adițional. Protocolul I2C introduce noțiunea de Slave Address. Adresa unui dispozitiv de tip slave este un număr pe 7 biți (cel mai comun), pe 8 biți sau 10 biți. Comunicația dintre un master și un slave se face prin mesaje și este tot timpul inițiată de către master. Aceste mesaje pot fi sparte în două tipuri de cadre:
Aceste cadre sunt interschimbate numai după ce master-ul a trimis condiția de start. Sfârșitul unui mesaj este identificat prin condiția de stop.
Înainte ca master-ul să trimită pe linia de date adresa slave-ului cu care dorește să comunice, acesta trebuie sa genereze o condiție de start. Condiția de start determină toate dispozitivele slave să ”asculte” linia de date pentru că va urma o adresă. Pentru a genera această condiție, master-ul lasă linia SCL in HIGH și pune linia SDA pe LOW.
După ce masterul a generat condiția de start, acesta trimite pe linia de date (SDA) adresa dispozitivului slave cu care dorește să comunice. Adresa este (de cele mai multe ori) un număr pe 7 biți (biții A6-A0). Bitul 0 menționează dacă master-ul inițiază o operație de Citire (bitul 0 este 1) sau o operație de Scriere (bitul 0 este 0).
Slave-ul care își recunoaște adresa trimite un ACK master-ului prin punerea liniei SDA pe LOW în al nouălea ciclu de ceas. Starea default a liniilor SDA/SCL este HIGH datorită rezistențelor de pull-up. Master-ul/Slave-ul doar ”trag” liniile pe LOW.
Master-ul identifică dacă a primit ACK (SDA pus pe LOW) sau NACK (SDA a rămas HIGH pe durata celui de-al nouălea ciclu de ceas).
Dacă master-ul a primit ACK (dacă există un slave pe magistrală cu adresa respectivă), el poate continua cu transmiterea datelor (operație de scriere), sau cu recepția datelor (operație de citire). Numărul de cadre de date este arbitrar, pot fi interschimbate oricâte. Fiecare cadru trimis/recepționat este ACK'd sau NACK'd. În funcție de operație (citire sau scriere), ACK-ul/NACK-ul este trimis fie de master fie de slave.
După ce toate cadrele de date au fost interschimbate, master-ul generează condiția de stop. Aceasta este realizată prin eliberarea liniei SDA (trecere din LOW în HIGH) după eliberarea liniei SCL (trecere din LOW în HIGH).
Arduino poate funcționa atât în modul I2C Master cât și I2C Slave.
Procesul de configurare al modulului I2C pe microcontrollerele AVR este relativ simplu (trebuie setată doar frecvența ceasului):
I2C Setup:
void setup() { // Initialize I2C to a 100KHz clock // TWI Status Register: initialize prescaler to 1 TWSR = (0b00 << TWPS0); // TWI Bitrate Register: set bitrate // SCL_Freq = CPU_Freq / (16 + 2*TWBR * TWSR_Prescaler) // so: TWBR = (SCL_Freq / CPU_Freq - 16) / (TWSR_Prescaler * 2) TWBR = 72; // (16000000/100000 - 16) / (1 * 2) }
Însă pașii pentru a efectua o tranzacție completă pe I2C sunt complecși:
TWCR
pentru a transmite condiția de start;TWSR
);TWDR
+ așteptarea;TWSR
); TWDR
(de asemenea, trebuie incluși pașii intermediari de așteptare a finalizării operațiilor);TWCR
.Desigur, Arduino dispune de funcții de nivel înalt pentru operațiunile pe magistrala I2C a microcontrollerului, exemplu:
void setup() { Wire.setClock(100000); // Hz Wire.begin(); } void loop() { Wire.beginTransmission(0x52); // slave address Wire.write(0x88); Wire.endTransmission(); delay(5OOO); }
Pentru laboratorul acesta, vom utiliza un Arduino Uno cu rolul de master, la care a fost conectat un senzor de temperatură + presiune BMP280 (click pentru datasheet) de la care vom citi datele.
Pentru acesta, va trebui să descărcați scheletul de cod aflat aici: lab06-i2c.zip.
Task 1: Definitivați și testați codul pentru a realiza scanarea liniară a dispozitivelor I2C conectate. Ar trebui să găsiți dispozitivul la adresa 0x76
.
Task 2: Definitivați funcțiile de scriere / citire regiștrii ai dispozitivului și folosiți-le pentru a citi + converti temperatura în grade Celsius.