Introducere
I2C communications au devenit metoda de facto de comunicare între microcontrolere, microcomputere și o varietate de circuite integrate și senzori. Acesta a fost în jur de 1982 și a fost inițial dezvoltat pentru utilizarea în receptoare de televiziune.
deși am folosit mulți senzori și afișaje I2C în articolele anterioare, nu am analizat de fapt modul în care funcționează I2C și cum poate fi folosit pentru a comunica între microcontrolere.
astăzi vom corecta acest lucru și vom afla mai multe despre I2C. vom vedea, de asemenea, cum poate fi folosit pentru a face schimb de informații între doi Arduinos și cum poate fi folosit pentru a permite unui Arduino să controleze altul.
acesta va fi primul dintre cele patru articole despre I2C. în articolele viitoare vom vedea cum putem construi propriile noastre dispozitive I2C, cum să interfațăm un Raspberry Pi și un Arduino folosind I2C și cum să facem câteva configurații avansate I2C, inclusiv utilizarea mai multor maeștri pe o magistrală I2C.
Să începem!
comunicații I2C
I2C este un protocol serial utilizat pe o interfață cu 2 fire de viteză redusă. A fost inițial dezvoltat de Phillips în 1982 pentru a permite circuitelor integrate din receptoarele de televiziune să comunice între ele.
vremurile s-au schimbat, Phillips este acum NXP și I2C a devenit un standard de comunicare care este susținut de aproape fiecare producător important de semiconductori.
I2C este o abreviere pentru”Circuit Inter-integrat”. Se mai numește „IIC”sau” i pătrat C”.
utilizări și limitări
I2C este utilizat cu microcontrolere precum Arduino și cu microcomputere precum Raspberry Pi. Multe Display-uri și senzori de interfață pentru controlerul lor gazdă folosind I2C.
I2C are mai multe limitări cu toate acestea. Nu este deosebit de rapid, deși pentru majoritatea utilizărilor intenționate este suficient de rapid.
I2C poate fi utilizat numai pe distanțe scurte, la urma urmei, a fost inițial menit să comunice între circuitele integrate de pe aceeași placă de circuite imprimate. Distanța maximă a transmisiei fiabile scade odată cu creșterea vitezei, la cea mai mică viteză (100 Kbaud sau o rată de ceas de 100 KHz) distanța maximă este de aproximativ un metru.
viteze I2C
magistrala originală I2C avea o viteză maximă de 100 KHz. Cele mai frecvente aplicații folosesc încă această viteză, deoarece este suficient pentru transferul de date de la senzori și la afișaje simple.
I2C și are unele moduri de viteză mai mare. Nu toate dispozitivele I2C acceptă aceste moduri:
- mod rapid – aceasta are o viteză maximă de ceas de 400 KHz.
- mod Hi-Speed – o frecvență maximă de ceas fo 3.4 MHz
- mod Ultra rapid – frecvența maximă de ceas de 5 MHz
pe o magistrală I2C este maestrul care determină viteza ceasului.
cum funcționează I2C
o magistrală I2C are două semnale, împreună cu o conexiune de alimentare și masă.
cele două linii de semnal sunt după cum urmează:
- SDA – aceasta este linia de date bidirecțională.
- SCL – acesta este semnalul ceasului.
există două rezistențe de tragere atașate la fiecare linie de semnal, trag magistrala până la tensiunea de alimentare atunci când este inactivă.
rețineți că tensiunea de alimentare nu este standard, poate fi de 3,3 sau 5 volți. Poate fi, de asemenea, o tensiune mai mică pentru unele implementări I2C de mare viteză.
această diferență de tensiuni de alimentare poate cauza probleme atunci când interfațați dispozitive I2C care utilizează niveluri logice diferite. Vom discuta acest lucru mai mult într-un articol viitor când vă voi arăta cum să interfațați un Raspberry Pi (3.Logică de 3 volți) cu un Arduino Uno (logică de 5 volți).
există două tipuri de dispozitive care pot fi interfațate cu autobuzul I2C – maeștri și sclavi.
dispozitivul principal controlează magistrala și furnizează semnalul ceasului. Solicită date de la sclavi individual. Nu poate fi mai mult de un dispozitiv de master pe autobuz, dar numai unul poate fi maestru activ la un moment dat.
dispozitivele master nu au o adresă atribuită acestora.
dispozitivele Slave au o adresă, iar această adresă trebuie să fie unică în autobuz. Ei folosesc o schemă de adresare pe 7 biți, astfel încât până la 128 de sclavi pot fi pe un autobuz I2C. În viața reală, această colecție mare de dispozitive nu este niciodată folosită, este rar să vezi peste o duzină de dispozitive I2C pe un singur autobuz.
o nouă schemă de adresare pe 10 biți a fost implementată, este compatibilă cu metoda existentă de adresare pe 7 biți.
dispozitive comerciale I2C sunt alocate adresa I2C de NXP, care menține specificațiile de autobuz. Deși I2C a fost open source din 2006, există o taxă percepută pentru obținerea unei adrese slave de la NXP. Nu este necesară nicio taxă pentru dispozitivele master sau pentru dispozitivele care nu sunt destinate fabricării comerciale.
unor dispozitive I2C li se atribuie mai multe adrese, de obicei variații în biții de adresă inferiori. Aceste dispozitive pot fi configurate manual pentru adrese diferite, permițând utilizarea mai multor dispozitive de același tip pe o singură magistrală I2C.
alte derivate I2C
există și alte autobuze care au fost derivate din magistrala I2C și care sunt în multe privințe compatibile cu I2C.
- TWI – interfața Twin Wire este practic identică cu magistrala I2C. Acesta este de fapt autobuzul pe care îl folosește Arduino, TWI a fost dezvoltat atunci când autobuzul I2C nu era open source și Atmel nu dorea să riște o încălcare a denumirii comerciale. Singura diferență majoră între TWI și I2C este că TWI nu acceptă o tehnică avansată numită „întinderea ceasului”.
- SMBus este un alt autobuz echivalent I2C, dezvoltat de Intel. Ca TWI suportă cele mai multe caracteristici I2C.
într-un articol viitor voi explica modul în care sunt structurate datele de pe magistrala I2C. Dar acum avem câteva informații de bază I2C, suficiente pentru a începe experimentarea.
Arduino Wire Library
Arduino are o bibliotecă încorporată pentru lucrul cu I2C numită Wire Library. Se face foarte ușor de a comunica pe magistrala I2C, și se poate configura Arduino pentru a deveni fie un maestru sau un sclav.
Biblioteca Wire are mai multe funcții utile pentru lucrul cu I2C.
- begin() – aceasta inițiază biblioteca și stabilește Arduino să fie fie maestru sau sclav.
- requestFrom() – această funcție este utilizată de master pentru a solicita date de la un sclav.
- beginTransmission() – această funcție este utilizată de master pentru a trimite date către un sclav specificat.
- endTransmission() – această funcție este utilizată de master pentru a încheia o transmisie începută cu funcția beginTransmission.
- write() – folosit atât de master, cât și de slave pentru a trimite date pe magistrala I2C.
- disponibil() – utilizat atât de master, cât și de slave pentru a determina numărul de octeți din datele pe care le primesc.
- read() – citește un octet de date din magistrala I2C.
- SetClock() – folosit de master pentru a seta o anumită frecvență de ceas.
- onReceive() – folosit de sclav pentru a specifica o funcție care este apelată atunci când datele sunt primite de la master.
- onRequest() – folosit de sclav pentru a specifica o funcție care este apelată atunci când maestrul a solicitat date.
vom folosi unele dintre aceste funcții în schițele noastre.
conexiuni Arduino I2C
conexiunile SDA și SCL pentru I2C sunt diferite între modelele Arduino. Experimentele pe care urmează să vi le arăt au fost făcute folosind două Arduino Unos, dar puteți utiliza alte modele ale Arduino, oferindu-vă să schimbați pinii în consecință.
am pus împreună o diagramă pentru a vă ajuta să-l dat seama. Acesta include unele placi Arduino comune, precum și câteva dintre chips-uri discrete. Pinouts pentru lista de chips-uri i (ATTiny și ATmega328P) sunt cu pachetul DIP, nu cele de montare pe suprafață.
Arduino Board or Chip | SDA | SCL |
Uno | A4 | A5 |
Mega2560 | 20 | 21 |
Nano | A4 | A5 |
Pro Mini | A4 | A5 |
Leonardo | 2 | 3 |
Due (has two I2C) | 20 + SDA1 | 20 + SCL1 |
ATTiny85 & ATTiny45 | 5 | 7 |
ATmega328P | 27 | 28 |
unele Clone Arduino Uno au pini SDA și SCL separați și le puteți folosi în locul celor doi pini analogici, dacă doriți. Ele sunt conectate intern la același loc.
rețineți că Arduino Due are de fapt două porturi I2C.
De asemenea, să fie conștienți de faptul că există unele diagrame de montaj incorecte pe internet pentru Pro Mini. Utilizați cei doi pini analogici, A4 și A5, așa cum se arată în tabelul de mai sus.
I2C între 2 Arduino lui
pentru primul nostru experiment vom hoo două Arduinos împreună și schimbul de date între ele. Un Arduino va fi stăpânul, celălalt va fi sclavul.
folosesc două Arduino Unos, dar puteți înlocui alte Arduino dacă nu aveți două Unos. Utilizați graficul anterior pentru conexiuni.
agățarea 2 Arduino lui
Iată cum am conectat meu două Arduino Unos împreună:
este destul de un montaj simplu, în esență, vă lega doar la sol și cei doi pini I2C împreună.
un lucru de care trebuie să fim conștienți este că diagrama mea nu arată utilizarea rezistențelor pull-up, Am constatat că totul părea să funcționeze corect fără ele. Cu toate acestea, este posibil să doriți să le includeți, mai ales dacă întâmpinați erori sau funcționare intermitentă.
pentru a conecta niște rezistențe pull-up atașați câteva rezistențe 10k la liniile SDA și SCL. Atașați celălalt capăt la ieșirea de 5 Volți pe unul dintre Arduino.
Master Demo Sketch
aici este schița care va fi folosit pe Arduino pe care le-ați desemnat ca fiind maestru.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
/*
I2C master demo
I2C-master-demo.ino
Demonstrate use of I2C bus
Master sends character and gets reply from Slave
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define Slave answer size
#define ANSWERSIZE 5
void setup() {
// Initialize I2C communications as Master
Wire.begin();
/ /configurare monitor serial
Serial.începe (9600);
Serial.println („I2C Master Demonstration”);
}
void loop () {
delay(50);
Serial.println („scrie date la slave”);
// scrie un charatre la Slave
sârmă.beginTransmission (SLAVE_ADDR);
sârmă.scrie (0);
sârmă.endTransmission ();
Serial.println („primiți date”);
// citiți răspunsul de la Slave
// citiți înapoi 5 caractere
sârmă.requestFrom (SLAVE_ADDR,ANSWERSIZE);
/ /adăugați caractere la șir
string response=””;
în timp ce (sârmă.disponibil()) {
char b = sârmă.citește ();
răspuns += b;
}
/ /imprimare la monitor Serial
Serial.println (răspuns);
}
|
ca și în cazul tuturor schițelor I2C, începem prin includerea bibliotecii de sârmă.
în continuare definim câteva constante pentru a reprezenta adresa I2C a sclavului și numărul de octeți de date pe care ne așteptăm să le extragem din acesta.
în Configurare inițializăm comunicațiile I2C ca master. Știm că este un maestru, deoarece nu există un parametru de adresă în funcția begin. De asemenea, configurăm un monitor serial și imprimăm o linie de text.
acum la bucla.
începem cu o mică întârziere de timp, mai ales pentru a încetini lucrurile suficient de jos, astfel încât să putem citi afișajul de pe monitorul serial.
în continuare folosim funcția beginTransmission pentru a trimite date către slave. În acest caz, datele pe care le trimitem sunt doar un număr zero. Terminăm trimiterea cu un apel până la sfârșitfuncția de transmisie.
în continuare solicităm câteva date înapoi de la sclav folosind funcția requestFrom.
după aceea formulăm un șir de răspuns citind Datele, un octet la un moment dat, de la sclav.
imprimăm detaliile a ceea ce facem și a datelor pe care le primim pe monitorul serial. Și apoi terminăm bucla și o facem din nou.
Slave Demo Sketch
acum pe schița folosită de Sclav.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
/*
I2C Slave Demo
i2c-slave-demo.ino
Demonstrate use of I2C bus
Slave receives character from Master and responds
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define Slave answersize
#define ANSWERSIZE 5
// Define string cu răspuns la Master
string answers = „Hello”;
void setup() {
// inițializa comunicații I2C ca sclav
sârmă.începe (SLAVE_ADDR);
/ /funcție pentru a rula atunci când datele solicitate de la master
sârmă.onRequest (requestEvent);
/ /funcție pentru a rula atunci când datele primite de la master
sârmă.onReceive (receiveEvent);
/ /configurare monitor Serial
Serial.începe (9600);
Serial.println („demonstrație Sclav I2C”);
}
void receiveEvent () {
/ /citit în timp ce datele primite
în timp ce (0< sârmă.disponibil()) {
octet x = sârmă.citește ();
}
/ /imprimare la monitor Serial
Serial.println („primi eveniment”);
}
void requestEvent () {
// Setup octet variabilă în dimensiunea corectă
răspuns octet;
/ /formatați răspunsul ca matrice
pentru (octet i=0;I<ANSWERSIZE;i++) {
response = (octet)răspuns.charAt (i);
}
/ /Trimite răspuns înapoi la Master
sârmă.scrie (răspuns, sizeof (răspuns));
// imprimare la monitor Serial
Serial.println(„eveniment cerere”);
}
void loop() {
// întârziere în buclă
delay(50);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/*
I2C master control demo
I2C-master-demo-control.ino
Demonstrate use of I2C bus
Master sends potentimeter position data
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Analog pin for potentiometer
int analogPin = 0;
// Integer to hold potentiometer value
int val = 0;
void setup () {
/ /inițializa comunicații I2C ca maestru
sârmă.begin();
}
void loop() {
delay(50);
/ / Read pot value
/ / Map la gama de 1-255 pentru flash rate
val = map(analogRead(analogPin), 0, 1023, 255, 1);
/ / scrie un charatre sclavului
sârmă.beginTransmission (SLAVE_ADDR);
sârmă.scrie (val);
sârmă.endTransmission();
}
|
ca întotdeauna trebuie să includem Biblioteca de sârmă la începutul schiței. De asemenea, vom defini o constantă pentru a ține adresa sclavului.
deoarece folosim un potențiometru, va trebui să definim atât pinul la care este conectat, cât și o variabilă pentru a-și menține valoarea.
tot ce facem în configurare este să inițializăm conexiunea I2C ca master.
în buclă citim valoarea potențiometrului și o mapăm la un interval de 01-255. Trebuie să facem acest lucru, deoarece trimitem un octet de informații și putem deține atât de multe valori într-un singur octet.
rețineți că inversăm secvența de numerotare în funcția de hartă Arduino, acest lucru se face astfel încât sistemul să se comporte așa cum ne așteptăm – rotirea potențiometrului spre dreapta crește rata blițului. Ca „rata de flash” este specificat de o întârziere de timp un număr mai mare fiind trimis va echivala cu o rată de flash mai mult.
de asemenea, rețineți că nu trimitem valoarea 0, care ar ține doar LED-ul la o singură stare. Am stabilit gama noastră să se încheie la 1 în schimb.
acum este doar o chestiune de a trimite octetul către sclav și de a repeta bucla din nou.
Remote Demo primi Sketch
partea slave trebuie să primească date de la master și să-l utilizați pentru a clipi LED-ul.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
/*
I2C slave control demo
I2C-slave-demo-control.ino
Demonstrate use of I2C bus
Receives potentimeter position data
Controls LED blink rate
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define LED Pin
int LED = 13;
// Variable for received data
int rd;
// Variable for blink rate
int br;
void setup () {
pinMode(LED, ieșire);
/ /inițializa comunicații I2C ca sclav
sârmă.începe (SLAVE_ADDR);
/ /funcție pentru a rula atunci când datele primite de la master
sârmă.onReceive (receiveEvent);
/ /Setup Serial Monitor
Serial.începe (9600);
Serial.println („demonstrație de sclavi I2C”);
}
void receiveEvent () {
/ /citiți un caracter din I2C
rd = sârmă.citește ();
// valoarea de imprimare a datelor primite
Serial.println(rd);
}
void loop () {
delay(50);
/ / calculați valoarea clipirii
br = map (rd, 1, 255, 100, 2000);
digitalWrite(LED, HIGH);
delay(br);
digitalWrite(LED, LOW);
delay(br);
}
|