I2C Communications Partea 1-Arduino la Arduino

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.

I2C Partea 1-Folosind 2 Arduinos

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ă.

I2C bus Communications

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ă:

I2C Arduino la Arduino

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.

I2C Master Demo

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.

I2C Slave Demo

încă o dată începem prin includerea bibliotecii wire. Ca și în schița anterioară, definim și adresa I2C pentru sclav, precum și numărul de octeți pe care intenționăm să-i trimitem înapoi comandantului.

în continuare definim șirul pe care îl vom trimite înapoi comandantului, în acest caz doar cuvântul „salut”. Dacă decideți să modificați acest lucru, asigurați-vă că ajustați constant ANSWERSIZE în ambele schițe pentru a fi corecte.

în Configurare inițializăm conexiunea la magistrala I2C cu o funcție begin. Luați notă de modul diferit în care facem acest lucru, deoarece acesta este un sclav pe care îl specificăm adresa I2C pe care o vom folosi. Făcând acest lucru, Biblioteca Wire știe că vrem să operăm în modul slave.

acum trebuie să definim numele funcțiilor pe care le vom apela atunci când apar două evenimente – o solicitare de date primită de la master și datele primite de la master. De asemenea, configurăm și imprimăm pe monitorul serial.

funcția receiveEvent este apelată atunci când primim date de la master. În această funcție citim datele în timp ce datele sunt disponibile și le atribuim unui octet (amintiți-vă, datele vor fi primite câte un octet la un moment dat).

funcția requestEvent este apelată ori de câte ori primim o cerere de date de la master. Trebuie să trimitem șirul nostru” Bună ziua ” înapoi la maestru. Deoarece trebuie să trimitem datele un octet la un moment dat, împărțim caracterele din „Hello” în elemente individuale dintr-o matrice și apoi le trimitem unul câte unul.

raportăm toate progresele noastre în ambele funcții către monitorul serial.

bucla din această schiță adaugă doar o întârziere de timp, care se potrivește cu cea utilizată în schița principală.

rularea schițelor Demo

pentru a rula aceste schițe va trebui să puteți vizualiza monitorul Serial pe fiecare Arduino. Dacă aveți două computere cu Arduino IDE instalat, atunci care va face mult mai ușor.

I2C Experiment 1

pe Microsoft Windows este posibil să se deschidă două instanțe ale IDE Arduino. Dacă se face acest lucru, puteți afișa ambele monitoare seriale side-by-side pe același ecran.

alternativ, puteți utiliza un computer și porniți al doilea Arduino cu propria sursă de alimentare. Ar trebui să comutați computerul și puterea între cele două Arduino. făcând acest lucru, puteți monitoriza ambele ecrane unul câte unul.

Arduino Remote folosind I2C

în următoarea demonstrație vom conecta un potențiometru la Maestrul Arduino și un LED la sclav. Vom folosi potențiometrul pentru a controla rata de clipire a LED-ului.

aceasta este o altă demonstrație simplă, puteți construi pe ea pentru a crea ceva mai practic.

Remote Demo Hookup

Iată cum acest experiment este pus împreună.

I2C Arduino Control

este în esență același montaj ca experimentul anterior, cu adăugarea potențiometrului pe master și LED-ul pe slave.

rețineți că LED-ul de pe slave a fost atașat la pinul 13. Deoarece Arduino Uno are un LED încorporat pe pinul 13, puteți elimina LED-ul și rezistența sa de cădere, dacă doriți.

remarcile despre rezistențe pull-up se aplică, de asemenea, la acest montaj.

Remote Demo Master Sketch

schița pentru partea principală a acestui experiment este foarte simplă, în unele privințe partea I2C este chiar mai simplă decât cea utilizată în prima demonstrație. Acest lucru se datorează faptului că trimitem doar date sclavului și nu ne așteptăm să primim înapoi.

I2C Master cu potențiometru

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.

I2C Slave cu LED

începem cu includerea obișnuită a Bibliotecii wire, precum și definirea adresei slave. De asemenea, definim un pin pentru LED.

sunt definite câteva variabile suplimentare, una ținând datele primite, în timp ce cealaltă poartă valoarea de întârziere a timpului pentru rata de clipire.

în Configurare setăm pinul I/O pentru LED ca ieșire și inițializăm magistrala I2C. Pe măsură ce folosim adresa slave în funcția begin, Biblioteca Wire știe că acționăm ca un sclav.

trebuie doar să definim o funcție onReceive, spre deosebire de ultima demonstrație, nu așteptăm nicio solicitare din partea comandantului. De asemenea, configurăm și imprimăm pe monitorul Serial, vom folosi monitorul pentru a vizualiza datele primite.

funcția receiveEvent citește datele primite și le atribuie variabilei I. De asemenea, imprimă valoarea pe monitorul serial.

în cele din urmă, în buclă folosim datele primite pentru a clipi LED-ul. Încă o dată folosim funcția Map pentru a realiza acest lucru, schimbând valorile primite de 1-255 într-o gamă mai largă. Puteți experimenta schimbarea acestui interval pentru a face LED-ul să clipească mai repede sau mai lent, dacă doriți.

ultimele declarații sunt în esență schița Arduino Blink deghizată! Pornim și oprim LED-ul pentru o perioadă de timp pe care am determinat-o în ultimul pas.

și apoi repetăm bucla.

rularea Demo la distanță

încărcați codul și puterea atât Arduino lui. puteți utiliza monitorul serial pe Arduino slave pentru a vizualiza datele primite.

I2C Experiment 2

rotirea potențiometrului ar trebui să varieze acum rata de clipire a LED-ului pe sclav.

concluzie

aceasta încheie prima noastră privire detaliată asupra I2C. în următoarea tranșă, vom afla mai multe despre structura datelor care sunt schimbate. De asemenea, vom lua un senzor obișnuit și îl vom transforma într-un senzor I2C.

comunicare fericită!

resurse

schițe – toate schițele I2C utilizate în acest articol.

informații I2C – informații privind protocolul I2C

comunicații I2C Partea 1 – Arduino la Arduino
rezumat
I2C communications part 1 - Arduino la Arduino
numele articolului
I2C communications part 1 – Arduino la Arduino
descriere
în această primă parte a unei serii de articole despre I2C veți afla ce este I2C. Veți vedea, de asemenea, cum Arduino Wire library face comunicațiile prin I2C foarte simple.
autor
Dronebot Workshop
numele editorului
Dronebot Workshop
logo-ul editorului
Dronebot Workshop

tagged pe: Arduino Tutorial
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);
}