introduktion
I2C kommunikation er blevet de facto metode til kommunikation mellem mikrocontrollere, mikrocomputere og en række integrerede kredsløb og sensorer. Det har eksisteret siden 1982 og blev oprindeligt udviklet til brug i tv-modtagere.
selvom vi har brugt mange I2C sensorer og skærme i tidligere artikler, har vi faktisk ikke undersøgt, hvordan I2C fungerer, og hvordan det kan bruges til at kommunikere mellem mikrocontrollere.
i dag vil vi rette det og lære mere om I2C. vi vil også se, hvordan det kan bruges til at udveksle information mellem to Arduinos, og hvordan det kan bruges til at tillade en Arduino at kontrollere en anden.
Dette vil være den første af fire artikler om I2C. i fremtidige artikler vil vi se, hvordan vi kan bygge vores egne I2C-enheder, hvordan man interface en Raspberry Pi og en Arduino ved hjælp af I2C, og hvordan man gør nogle avancerede I2C-konfigurationer, herunder brug af flere mestre på en I2C-bus.
lad os komme i gang!
I2C Communications
I2C er en seriel protokol, der anvendes på en lav hastighed 2-leder interface. Det blev oprindeligt udviklet af Phillips i 1982 for at tillade integrerede kredsløb inden for tv-modtagere at kommunikere med hinanden.
tiderne er ændret, Phillips er nu NHP og I2C er blevet en kommunikationsstandard, der understøttes af stort set alle større halvlederproducenter.
I2C er en forkortelse for “Inter-Integrated Circuit”. Det kaldes også” IIC”eller” jeg kvadreret C”.
anvendelser og begrænsninger
I2C bruges med mikrocontrollere som Arduino og med mikrocomputere som Raspberry Pi. Mange skærme og sensorer interface til deres vært controller ved hjælp af I2C.
I2C har dog flere begrænsninger. Det er ikke særlig hurtigt, selvom det for de fleste af de tilsigtede anvendelser er rigeligt hurtigt nok.
I2C kan kun bruges over korte afstande, når alt kommer til alt var det oprindeligt beregnet til at kommunikere mellem integrerede kredsløb på det samme printkort. Den maksimale afstand for pålidelig transmission falder, når hastigheden øges, ved den langsomste hastighed (100 Kbaud eller en klokhastighed på 100 KHS) er den maksimale afstand ca.en meter.
I2C-hastigheder
den originale I2C-bus havde en maksimal hastighed på 100 KHS. De fleste almindelige applikationer bruger stadig denne hastighed, da det er helt tilstrækkeligt til at overføre data fra sensorer og til enkle skærme.
I2C og har nogle højere hastighedstilstande. Ikke alle I2C – enheder understøtter disse tilstande:
- hurtig tilstand-Dette har en maksimal klokhastighed på 400 KHS.
- Hi-Speed Mode – en maksimal klokfrekvens fo 3.4 MH
- Ultra hurtig tilstand – maksimal klokfrekvens på 5 MH
på en I2C-bus er det masteren, der bestemmer klokhastigheden.
Sådan fungerer I2C
en I2C-bus har to signaler sammen med en strøm-og jordforbindelse.
de to signallinjer er som følger:
- SDA – dette er den tovejs datalinje.
- SCL – dette er ursignalet.
der er to pull-up modstande fastgjort til hver signallinje, de trækker bussen op til forsyningsspændingen, når den er inaktiv.
Bemærk, at forsyningsspændingen ikke er standard, den kan enten være 3,3 eller 5 volt. Det kan også være en lavere spænding for nogle high-speed I2C implementeringer.
denne forskel i forsyningsspændinger kan forårsage problemer, når du forbinder I2C-enheder, der bruger forskellige logiske niveauer. Vi vil diskutere dette mere i en fremtidig artikel, når jeg viser dig, hvordan du interface en Raspberry Pi (3.3-volt logik) med en Arduino Uno (5-volt logik).
der er to typer enheder, der kan forbindes til I2C – bussen-mestere og slaver.
hovedenheden styrer bussen og leverer ursignalet. Det anmoder om data fra slaverne individuelt. Der kan være mere end en masterenhed på bussen, men kun en kan være den aktive master til enhver tid.
masterenhederne har ikke en adresse tildelt dem.
Slave-enheder har en adresse, og denne adresse skal være unik på bussen. De bruger en 7-bit adresseringsplan, så op til 128 slaver kan være på en I2C-bus. I det virkelige liv er denne store samling af enheder aldrig brugt, det er sjældent at se over et dusin I2C-enheder på en bus.
en nyere 10-bit adresseringsplan er implementeret, den er bagudkompatibel med den eksisterende 7-bit adresseringsmetode.
Kommercielle I2C-Enheder tildeles I2C-adresse af NHP, der opretholder busspecifikationerne. Selvom I2C har været open source siden 2006, opkræves der et gebyr for at få en Slaveadresse fra
nogle I2C-Enheder tildeles flere adresser, normalt afvigelser i de nederste adressebits. Disse enheder kan konfigureres manuelt til forskellige adresser, så flere enheder af samme type kan bruges på en enkelt I2C-bus.
andre I2C-derivater
Der er andre busser, der er afledt af I2C-bussen, og som på mange måder er kompatible med I2C.
- to – den dobbelte trådgrænseflade er næsten identisk med I2C-bussen. Dette er faktisk den bus, som Arduino bruger, der blev udviklet, da I2C-bussen ikke var open source, og Atmel ikke ønskede at risikere en overtrædelse af handelsnavnet. Den eneste store forskel mellem to og I2C er, at to ikke understøtter en avanceret teknik kaldet “urstrækning”.
- SMBus er en anden I2C-ækvivalent bus, udviklet af Intel. Ligesom to understøtter det de fleste I2C-funktioner.
i en fremtidig artikel vil jeg forklare, hvordan dataene på I2C-bussen er struktureret. Men nu har vi nogle grundlæggende I2C-oplysninger, nok til at begynde at eksperimentere.
Arduino Trådbibliotek
Arduino har et indbygget bibliotek til arbejde med I2C kaldet Trådbiblioteket. Det gør det meget nemt at kommunikere på I2C-bussen, og det kan konfigurere Arduino til at blive enten en mester eller en slave.
Trådbiblioteket har flere nyttige funktioner til at arbejde med I2C.
- begin() – dette initierer biblioteket og opretter Arduino til at være enten mester eller slave.
- anmodning fra() – denne funktion bruges af masteren til at anmode om data fra en slave.
- beginTransmission() – denne funktion bruges af masteren til at sende data til en bestemt slave.
- endTransmission() – denne funktion bruges af masteren til at afslutte en transmission startet med beginTransmission-funktionen.
- skriv() – bruges af både master og slave til at sende data på I2C-bussen.
- tilgængelig() – bruges af både master og slave til at bestemme antallet af bytes i de data, de modtager.
- Læs() – læser en byte af data fra I2C-bussen.
- SetClock() – bruges af masteren til at indstille en bestemt klokfrekvens.
- onReceive() – bruges af slaven til at angive en funktion, der kaldes, når data modtages fra masteren.
- onanmod() – bruges af slaven til at specificere en funktion, der kaldes, når masteren har anmodet om data.
Vi vil bruge nogle af disse funktioner i vores skitser.
Arduino I2C-forbindelser
SDA-og SCL-forbindelserne til I2C er forskellige mellem Arduino-modeller. De eksperimenter, jeg er ved at vise dig, blev udført ved hjælp af to Arduino Unos, men du kan bruge andre modeller af Arduino, forudsat at du ændrer stifterne i overensstemmelse hermed.
jeg har sammensat et diagram for at hjælpe dig med at få det regnet ud. Det omfatter nogle fælles Arduino boards, samt et par af de diskrete chips. Pinouts til chips i-listen (ATTiny og ATmega328P) er med DIP-pakken, ikke de overflademonterede.
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 |
nogle Arduino Uno-kloner har separate SDA-og SCL-stifter, og du kan bruge dem i stedet for de to analoge stifter, hvis du ønsker det. De er internt forbundet til samme sted.
Bemærk, at Arduino Due faktisk har to I2C-porte.
vær også opmærksom på, at der er nogle forkerte tilslutningsdiagrammer på internettet til Pro Mini. Brug de to analoge stifter, A4 og A5, som vist i tabellen ovenfor.
I2C mellem 2 Arduinos
til vores første eksperiment vil vi hoo to Arduinos sammen og udveksle data mellem dem. En Arduino vil være mesteren, den anden vil være slaven.
Jeg bruger to Arduino Unos, men du kan erstatte andre Arduino ‘ er, hvis du ikke har to Unos. Brug det forrige diagram til forbindelserne.
Tilslutning 2 Arduino s
Sådan forbinder jeg mine to Arduino Unos sammen:
det er en ganske enkel tilslutning, i det væsentlige binder du bare jorden og de to I2C-stifter sammen.
en ting at være opmærksom på er, at mit diagram ikke viser brugen af pull-up modstande, jeg fandt ud af, at alt syntes at fungere korrekt uden dem. Det kan dog være en god ide at medtage dem, især hvis du oplever fejl eller intermitterende drift.
for at tilslutte nogle pull-up modstande vedhæfter et par 10K modstande til SDA-og SCL-linjerne. Fastgør den anden ende til 5-volt-udgangen på en af Arduino ‘ erne.
Master Demo Sketch
Her er den skitse, der vil blive brugt på Arduino, som du har udpeget som værende master.
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
32
33
34
35
36
37
38
39
40
41
42
43
45
46
47
48
49
50
51
52
|
/*
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();
/ /opsætning seriel skærm
seriel.begynde (9600);
seriel.println (“I2C Master Demonstration”);
}
void loop () {
forsinkelse(50);
seriel.println (“skriv data til slave”);
// Skriv en charatre til slaven
Ledning.beginTransmission (SLAVE_ADDR);
tråd.skriv (0);
tråd.endTransmission ();
seriel.println (“Modtag data”);
// Læs svar fra Slave
// Læs tilbage 5 tegn
tråd.anmodning fra (SLAVE_ADDR, SVARSTØRRELSE);
/ / Tilføj tegn til string
String response=””;
mens (tråd.tilgængelig ()) {
char b = Ledning.Læs ();
svar += b;
}
// Udskriv til seriel skærm
seriel.println (svar);
}
|
som med alle I2C-skitser starter vi med at inkludere Trådbiblioteket.
dernæst definerer vi et par konstanter til at repræsentere slavens I2C-adresse og antallet af bytes data, som vi forventer at hente fra den.
i opsætningen initialiserer vi I2C-kommunikationen som en master. Vi ved, at det er en master, da der ikke er nogen adresseparameter i startfunktionen. Vi opsætter også en seriel skærm og udskriver en tekstlinje til den.
nu til Løkken.
Vi starter med en lille tidsforsinkelse, for det meste for at bremse tingene nok, så vi kan læse displayet på den serielle skærm.
næste bruger vi beginTransmission-funktionen til at sende data til slaven. I dette tilfælde er de data, vi sender, kun et tal nul. Vi slutter at sende med et opkald til slutningentransmissionsfunktion.
dernæst anmoder vi om nogle data tilbage fra slaven ved hjælp af funktionen anmodfra.
derefter formulerer vi en svarstreng ved at læse dataene, en byte ad gangen, fra slaven.
vi udskriver detaljerne om, hvad vi laver, og de data, vi modtager til den serielle skærm. Og så afslutter vi løkken og gør det hele igen.
Slave Demo Sketch
nu på skitsen brugt af slaven.
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
32
33
34
35
36
37
38
39
40
41
42
43
45
46
47
48
49
50
51
52
53
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>
// Definer Slave I2C-adresse
#Definer SLAVE_ADDR 9
// Definer Slave svarstørrelse
#Definer SVARSTØRRELSE 5
// Definer streng med svar på Master
String svar = “Hej”;
void setup () {
// Initialiser I2C-kommunikation som slave
ledning.begynde (SLAVE_ADDR);
// funktion til at køre, når data anmodet fra master
tråd.Onanmod (anmodning begivenhed);
// funktion til at køre, når data modtaget fra master
Ledning.onReceive (receiveEvent);
/ /opsætning seriel skærm
seriel.begynde (9600);
seriel.println (“I2C Slave Demonstration”);
}
void receiveEvent () {
// Læs mens data modtaget
mens (0 < tråd.tilgængelig ()) {
byte = tråd.Læs ();
}
/ / Udskriv til seriel skærm
seriel.println (“Modtag begivenhed”);
}
ugyldig anmodningevent () {
/ / opsætning byte variabel i den korrekte størrelse
byte svar;
/ /Format svaret som array
for (byte i=0;i<SVARSTØRRELSE;i++) {
svar = (byte)svar.charAt (i);
}
// Send svar tilbage til Master
Ledning.skriv (svar, størrelse (svar));
// Udskriv til seriel skærm
seriel.println(“anmodning begivenhed”);
}
void loop() {
// tidsforsinkelse i loop
forsinkelse(50);
}
|
endnu en gang starter vi med at inkludere trådbiblioteket. Som med den foregående skitse definerer vi også I2C-adressen til slaven samt antallet af bytes, vi planlægger at sende tilbage til mesteren.
næste definerer vi den streng, vi skal sende tilbage til mesteren, i dette tilfælde bare ordet “Hej”. Hvis du beslutter dig for at ændre dette, skal du sørge for at justere SVARSTØRRELSESKONSTANTEN i begge skitser for at være korrekt.
i opsætningen initialiserer vi forbindelsen til I2C-bussen med en startfunktion. Vær opmærksom på den forskellige måde, vi gør dette på, da dette er en slave, angiver vi den I2C-adresse, vi skal bruge. Ved at gøre dette ved Trådbiblioteket, at vi vil operere i slavetilstand.
nu skal vi definere navnene på de funktioner, vi vil ringe til, når to begivenheder opstår – en dataanmodning modtaget fra masteren og data modtaget fra masteren. Vi opsætter og udskriver også til den serielle skærm.
funktionen modtagerbegivenhed kaldes, når vi modtager data fra masteren. I denne funktion læser vi data, mens dataene er tilgængelige og tildeler dem til en byte (husk, dataene modtages en byte ad gangen).
funktionen anmodevent kaldes, når vi får en anmodning om data fra masteren. Vi skal sende vores streng” hej ” tilbage til mesteren. Da vi har brug for at sende dataene en byte ad gangen, deler vi tegnene i “Hej” i individuelle emner i et array og sender dem derefter en efter en.
Vi rapporterer alle vores fremskridt i begge funktioner til den serielle skærm.
sløjfen i denne skitse tilføjer bare en tidsforsinkelse, der matcher den, der bruges i hovedskitsen.
kører Demo skitser
for at køre disse skitser skal du kunne se den serielle skærm på hver Arduino. Hvis du har to computere med Arduino IDE installeret, vil det gøre det meget lettere.
på Microsoft-vinduer er det muligt at åbne to forekomster af Arduino IDE. Hvis det er gjort, kan du vise begge serielle skærme side om side på samme skærm.
Alternativt kan du bruge en computer og tænde den anden Arduino med sin egen strømforsyning. Du bliver nødt til at skifte computer og strøm mellem de to Arduino ‘ er. ved at gøre dette kan du overvåge begge skærme en efter en.
Arduino Remote ved hjælp af I2C
i den næste demonstration vil vi koble et potentiometer til master Arduino og en LED til slaven. Vi bruger potentiometeret til at kontrollere LED ‘ ens blinkhastighed.
dette er en anden simpel demonstration, du kan bygge videre på det for at skabe noget mere praktisk.
Remote Demo tilslutning
Her er, hvordan dette eksperiment er sat sammen.
det er i det væsentlige den samme tilslutning som det foregående eksperiment med tilføjelsen af potentiometeret på masteren og LED ‘ en på slaven.
Bemærk, at LED ‘ en på slaven er fastgjort til pin 13. Da Arduino Uno har en indbygget LED på pin 13, kan du fjerne LED ‘ en og dens faldende modstand, hvis du ønsker det.
bemærkningerne om pull-up modstande gælder også for denne tilslutning.
Remote Demo Master Sketch
skitsen til mastersiden af dette eksperiment er meget enkel, på nogle måder er I2C-siden endnu enklere end den, der blev brugt i den første demonstration. Dette skyldes, at vi bare sender data til slaven og ikke forventer at få nogen tilbage.
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
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 () {
/ /Initialiser I2C-kommunikation som Master
Ledning.begynd();
}
void loop () {
forsinkelse (50);
/ / Læs potværdi
/ / kort til rækkevidde på 1-255 for flashhastighed
val = kort (analogRead(analogPin), 0, 1023, 255, 1);
/ / Skriv en charatre til slaven
Ledning.beginTransmission (SLAVE_ADDR);
tråd.skriv (val);
tråd.endTransmission();
}
|
som altid skal vi medtage Trådbiblioteket i begyndelsen af skitsen. Vi vil også definere en konstant til at holde slaveadressen.
da vi bruger et potentiometer, bliver vi nødt til at definere både den pin, den er forbundet til, og en variabel for at holde dens værdi.
alt, hvad vi gør i opsætningen, er at initialisere I2C-forbindelsen som en master.
i sløjfen læser vi potentiometerværdien og kortlægger den til et interval på 01-255. Vi skal gøre det, da vi sender en byte af information og kun kan holde så mange værdier i en enkelt byte.
Bemærk, at vi vender nummereringssekvensen i Arduino – kortfunktionen, dette gøres, så systemet opfører sig som vi forventer det-at dreje potentiometeret til højre øger flashhastigheden. Da “flash rate” er angivet af en tidsforsinkelse, vil et større antal, der sendes, svare til en længere flashhastighed.
Bemærk også, at vi ikke sender værdien 0, som bare holder LED ‘ en i en tilstand. Vi sætter vores sortiment til at ende på 1 i stedet.
nu er det bare et spørgsmål om at sende byte til slaven og gentage sløjfen igen.
Fjern Demo Modtag skitse
slavesiden skal modtage data fra masteren og bruge den til at blinke LED ‘ en.
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
32
33
34
35
36
37
38
39
40
41
42
43
45
46
47
48
49
50
51
52
53
55
56
57
58
59
60
|
/*
I2C slave kontrol demo
I2C-slave-demo-kontrol.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, udgang);
/ / Initialiser I2C-kommunikation som Slave
Ledning.begynde (SLAVE_ADDR);
// funktion til at køre, når data modtaget fra master
tråd.onReceive (receiveEvent);
// Setup Serial Monitor
Serial.begynde (9600);
seriel.println (“I2C Slave Demonstration”);
}
void receiveEvent () {
// læs et tegn fra I2C
rd = Ledning.Læs ();
// Udskrivningsværdi af indgående data
seriel.println (rd);
}
void loop () {
forsinkelse(50);
/ / Beregn blink værdi
br = kort (rd, 1, 255, 100, 2000);
digitalskriv(LED, høj);
forsinkelse(br);
digitalskriv(LED, lav);
forsinkelse(br);
}
|
Vi starter med den sædvanlige optagelse af TRÅDBIBLIOTEKET samt definition af slaveadressen. Vi definerer også en pin til LED ‘ en.
et par yderligere variabler er defineret, hvor den ene holder de modtagne data, mens den anden bærer tidsforsinkelsesværdien for blinkhastigheden.
i opsætningen indstiller vi i/O-stiften til LED ‘ en som en udgang og initialiserer I2C-bussen. Når vi bruger slaveadressen i startfunktionen, ved Trådbiblioteket, at vi fungerer som slave.
Vi behøver kun at definere en onReceive-funktion, i modsætning til den sidste demo forventer vi ikke nogen anmodninger fra masteren. Vi konfigurerer og udskriver også til den serielle Skærm, Vi bruger skærmen til at se de indgående data.
funktionen receiveEvent læser de indgående data og tildeler dem til i-variablen. Det udskriver også værdien til den serielle skærm.
endelig i sløjfen bruger vi de indgående data til at blinke LED ‘ en. Endnu en gang bruger vi kortfunktionen til at opnå dette og ændrer de indgående værdier på 1-255 til et bredere interval. Du kan eksperimentere med at ændre dette interval for at få LED ‘ en til at blinke hurtigere eller langsommere, hvis du ønsker det.
de sidste par udsagn er i det væsentlige Arduino Blink skitse i forklædning! Vi tænder og slukker LED ‘ en i en periode, vi bestemte i det sidste trin.
og så gentager vi sløjfen.
kørsel af Fjerndemoen
Indlæs koden og tænd for begge Arduino ‘ er. du kan bruge din serielle skærm på slaven Arduino til at se de indgående data.
drejning af potentiometeret skal nu variere LED-blinkhastigheden på slaven.
konklusion
Dette afslutter vores første detaljerede kig på I2C. i den næste rate lærer vi mere om strukturen af de data, der udveksles. Vi tager også en almindelig sensor og gør den til en I2C-sensor.
glad kommunikation!
ressourcer
skitser – alle I2C-skitser, der bruges i denne artikel.
I2C information – Information om I2C – protokollen