RP2350-Zero/I2C: Rozdiel medzi revíziami
d →I2C |
|||
| Riadok 1: | Riadok 1: | ||
[[RP2350 - úvod|Späť k RP2350-zero]] | |||
== I2C == | == I2C == | ||
Aktuálna revízia z 18:18, 8. september 2026
I2C
I2C (Inter-Integrated Circuit) je sériová komunikačná zbernica, ktorá umožňuje jednému riadiacemu zariadeniu (master) komunikovať s viacerými periférnymi zariadeniami (slave) pomocou iba dvoch vodičov. Bežne sa s ňou stretneš pri pripájaní senzorov, displejov alebo iných modulov k mikrokontroléru.
Hlavná výhoda I2C oproti riešeniam, kde má každé zariadenie svoje vlastné piny (napr. ultrazvukový senzor cez TRIG/ECHO), je, že na tie isté dva vodiče (SDA, SCL) sa dá pripojiť viacero zariadení naraz – každé má svoju vlastnú adresu (7-bitové číslo), podľa ktorej ho master osloví. Vďaka tomu netreba pre každé nové zariadenie obetovať ďalšie piny.
Vo väčšine breakout dosiek (aj BNO055, aj VL53L0X) sú navyše potrebné pull-up rezistory na SDA/SCL už priamo na doštičke, takže netreba pridávať vlastné.
Princíp
I2C komunikuje master so slave zariadením. Každé slave zariadenie má adresu, podľa ktorej sa identifikuje. Adresa je zvyčajne 7-bitová (128 možných adries), voliteľne aj 10-bitová (1024 adries).
- Master zariadenie si môžeme predstaviť ako naše RP2350-Zero.
- Slave (podriadené zariadenie) si môžeme predstaviť ako VL53L0X (laserový senzor vzdialenosti) alebo gyroskop BNO055.
- Komunikujú pomocou dvoch vodičov – SDA a SCL:
- SDA (Serial Data) – samotné dáta, prenášané medzi masterom a slave zariadením
- SCL (Serial Clock) – hodinový signál, ktorý synchronizuje prenos (generuje ho master)
Master, ako už z názvu vyplýva, riadi komunikáciu podľa vlastného časovania – podľa hodinového signálu na SCL posiela impulzy, a súčasne s nimi posiela alebo číta dáta cez SDA.
Dáta sa posielajú vo forme správ, ktoré sa skladajú z:
- štart podmienky (start condition)
- adresy zariadenia
- read/write bitu
- jedného alebo viacerých 8-bitových rámov dát
- potvrdzujúcich bitov (ACK/NACK) po každom ráme
- stop podmienky (stop condition)
Posielanie dát
1. Na začiatku je SCL aj SDA v pokoji HIGH. Komunikácia začína tzv. štart podmienkou: master zmení SDA z HIGH na LOW, zatiaľ čo SCL zostáva HIGH (práve táto kombinácia – zmena SDA počas HIGH na SCL – odlišuje štart podmienku od bežného prenosu dát, kde sa SDA mení iba keď je SCL LOW).
2. Master následne vyšle adresu zariadenia, s ktorým chce komunikovať.
3. Za adresou nasleduje read/write bit, ktorý určí, čo chce s daným zariadením robiť: ak chce dáta poslať, bit = 0 (LOW); ak chce dáta prijať zo zariadenia, bit = 1 (HIGH).
4. Slave zariadenie odpovie potvrdzujúcim bitom (ACK/NACK): ak zariadenie s danou adresou existuje, stiahne SDA na LOW (ACK). Ak žiadne zariadenie s takouto adresou neexistuje, nikto SDA nestiahne a linka zostane HIGH vďaka pull-up rezistoru (NACK), a master komunikáciu ukončí.
5. Ďalej sa posielajú 8-bitové rámy dát, každý nasledovaný potvrdzujúcim bitom od zariadenia, ktoré dáta prijíma. Bez ACK po ráme sa ďalší rám neposiela.
6. Nakoniec master ukončí komunikáciu tzv. stop podmienkou: zmení SDA z LOW na HIGH, zatiaľ čo SCL zostáva HIGH.
Príklad tejto komunikácie medzi RP2350-Zero a VL53L0X v kóde:
#include <Wire.h> // kniznica pre I2C komunikaciu
#include <VL53L0X.h>
VL53L0X sensor;
void setup() {
Serial.begin(115200);
Wire.setSDA(4); // nastavenie datoveho pinu
Wire.setSCL(5); // nastavenie hodinoveho pinu
Wire.begin(); // start podmienka pri kazdej komunikacii sa posle automaticky
// RP2350 posle adresu (0x29) VL53L0X a chce od neho citat data (read/write bit = 1)
if (!sensor.init()) { // ak zariadenie odpovie, stiahne SDA na LOW (ACK); ak nie, zostane HIGH (NACK)
Serial.println("Senzor nenájdený!");
while (1); // ziadne zariadenie s touto adresou neodpovedalo
}
sensor.setTimeout(500);
sensor.startContinuous(); // ACK prislo, mozu sa zacat posielat data
Serial.println("VL53L0X OK");
}
void loop() {
int dist = sensor.readRangeContinuousMillimeters(); // kniznica precita viacero 8-bitovych ramov, kazdy s ACK
if (sensor.timeoutOccurred()) {
Serial.println("Timeout!");
} else {
Serial.print("Vzdialenosť: ");
Serial.print(dist);
Serial.println(" mm");
}
delay(100);
// po kazdej transakcii sa posle stop podmienka, ale kniznica hned zacne dalsiu - preto stale citame nove data
}
Príklad – rovnaká komunikácia s BNO055
Rovnaký princíp, len iná adresa (0x28) a iná knižnica (Adafruit BNO055 + Adafruit Unified Sensor, obe cez Library Manager):
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);
void setup() {
Serial.begin(115200);
Wire.setSDA(4);
Wire.setSCL(5);
Wire.begin();
// RP2350 posle adresu (0x28) BNO055 a chce od neho citat data (read/write bit = 1)
if (!bno.begin()) { // ak BNO055 odpovie, stiahne SDA na LOW (ACK); ak nie, zostane HIGH (NACK)
Serial.println("BNO055 nenájdený!");
while (1); // ziadne zariadenie s touto adresou neodpovedalo
}
delay(1000);
bno.setExtCrystalUse(true);
Serial.println("BNO055 OK");
}
void loop() {
sensors_event_t event;
bno.getEvent(&event); // kniznica poziada o registre a precita viacero 8-bitovych ramov, kazdy s ACK
Serial.print("X: ");
Serial.print(event.orientation.x);
Serial.print(" Y: ");
Serial.print(event.orientation.y);
Serial.print(" Z: ");
Serial.println(event.orientation.z);
delay(200);
}
Zariadenia v našej stavebnici
| Zariadenie | Čo meria | Predvolená I2C adresa |
|---|---|---|
| BNO055 | Gyroskop / akcelerometer / kompas (9-DOF IMU) | 0x28 |
| VL53L0X | Laserový senzor vzdialenosti (Time-of-Flight) | 0x29 |
Keďže majú tieto dve zariadenia rôzne adresy, dajú sa obe pripojiť na tú istú I2C zbernicu súčasne bez konfliktu.
Poznámka: konkrétne GPIO piny pre SDA/SCL si over v pinoute RP2350-Zero – v príkladoch nižšie použijeme GPIO0 (SDA) a GPIO1 (SCL), keďže sú v našej stavebnici zatiaľ voľné, ale dajú sa nastaviť aj inak.
I2C skener (test zapojenia)
Skôr než skúšaš konkrétny senzor, oplatí sa overiť, či ho doska na zbernici vôbec "vidí". Na to slúži klasický I2C skener – prejde všetky možné adresy a vypíše, na ktorých našiel odpoveď:
#include <Wire.h>
const int PIN_SDA = 0;
const int PIN_SCL = 1;
void setup() {
Wire.setSDA(PIN_SDA);
Wire.setSCL(PIN_SCL);
Wire.begin();
Serial.begin(115200);
delay(1000);
Serial.println("I2C skener spusteny...");
}
void loop() {
byte pocetNajdenych = 0;
for (byte adresa = 1; adresa < 127; adresa++) {
Wire.beginTransmission(adresa);
byte chyba = Wire.endTransmission();
if (chyba == 0) {
Serial.print("Zariadenie najdene na adrese 0x");
if (adresa < 16) Serial.print("0");
Serial.println(adresa, HEX);
pocetNajdenych++;
}
}
if (pocetNajdenych == 0) {
Serial.println("Ziadne I2C zariadenie nenajdene.");
}
delay(3000);
}
Ak sa objaví 0x28, je zapojený BNO055. Ak 0x29, je zapojený VL53L0X. Ak sa nezobrazí nič, skontroluj zapojenie SDA/SCL/VCC/GND.