3.24. I2C u kodu

machine.I2C omata hardverski I2C upravljač. Stvorite ga s id-om sabirnice i opcionalnom frekvencijom takta:

from machine import I2C

i2c = I2C(2, freq=400_000)

id odabire koji hardverski I2C blok koristiti; dostupni brojevi i SDA / SCL pinovi na koje se preslikavaju ovise o pločici (vidi OpenMV ploče). freq je brzina SCL takta – 100_000 je standardni način, 400_000 je uobičajena „brza” brzina koju većina senzora podržava.

3.24.1. Skeniranje sabirnice

scan() prolazi 7-bitni adresni prostor i vraća popis svih uređaja koji su potvrdili svoju adresu:

>>> i2c.scan()
[0x40, 0x68]

To je prvo što treba isprobati nakon spajanja nove sabirnice. Ako je uređaj na popisu, ožičenje i pull-upovi su u redu. Ako je popis prazan (ili kraći od očekivanog), posumnjajte u pull-upove, ožičenje ili adresne pinove uređaja prije nego što posumnjate u kod.

3.24.2. Obrazac memorijskog preslikavanja

Većina I2C senzora svoje stanje izlaže kao skup internih registara: statusne zastavice na jednoj adresi, mjerne bajtove na drugoj, konfiguraciju na trećoj. Biblioteka ima dvije pogodne metode koje se izravno preslikavaju na obrazac „adresiraj uređaj, usmjeri na registar, zatim čitaj ili piši podatke”.

Čitanje registra:

addr = 0x68
reg  = 0x3B
data = i2c.readfrom_mem(addr, reg, 6)
# `data` is 6 bytes starting at register 0x3B

Taj jedan poziv izdaje START, šalje adresu uređaja s bitom za pisanje, šalje adresu registra (ponovljeni start), ponovno šalje adresu s bitom za čitanje, čita 6 bajtova, NACK-a posljednji i izdaje STOP. Uređaj vidi standardni slijed „čitanje iz registra”; skripta vidi jedan Python poziv.

Pisanje u registar:

i2c.writeto_mem(addr, 0x6B, b"\x00")

Taj je slijed isti u zrcalnoj slici: START, adresa + pisanje, registar, podatkovni bajt, STOP.

Za uređaje čija je adresa registra široka dva bajta (neki EEPROM-ovi i memorije s 16-bitnim adresiranjem) proslijedite addrsize=16:

data = i2c.readfrom_mem(addr, 0x0100, 32, addrsize=16)

3.24.3. Čitanje senzora

Kratka petlja koja čita WHO_AM_I identifikator i X os akcelerometra na tipičnom MEMS senzoru:

import time
import struct
from machine import I2C

i2c         = I2C(2, freq=400_000)
ADDR        = 0x68
WHO_AM_I    = 0x75
ACCEL_X_HI  = 0x3B

print("WHO_AM_I:", i2c.readfrom_mem(ADDR, WHO_AM_I, 1)[0])

while True:
    raw = i2c.readfrom_mem(ADDR, ACCEL_X_HI, 2)
    x   = struct.unpack(">h", raw)[0]
    print("accel X:", x)
    time.sleep_ms(100)

readfrom_mem() vraća bytes objekt, pa WHO_AM_I čitanje indeksira prvi (i jedini) bajt s [0]. Čitanje akcelerometra su dva sirova bajta koja se moraju sastaviti u jednu predznačenu 16-bitnu vrijednost; struct format ">h" to radi kao big-endian s predznakom – redoslijed bajtova koji koristi većina I2C senzora, suprotan little-endian konvenciji uobičajenoj na UART vezama. struct.unpack() uvijek vraća n-torku (jedan element po znaku formata), pa [0] izvlači tu jednu vrijednost.

3.24.4. Pristup na nižoj razini

Za uređaje koji ne slijede obrazac registarske mape, dvije metode niže razine daju izravnu kontrolu nad fazom adresiranja i smjerom podataka:

i2c.writeto(addr, b"\x01\x02\x03")    # write 3 bytes to addr
data = i2c.readfrom(addr, 4)          # read 4 bytes from addr

One su korisne za uređaje sa sučeljima toka naredbi (zasloni, neki satovi stvarnog vremena) gdje pomoćne metode za registarsku mapu ne pristaju sasvim.

3.24.5. Bit-banging kada nije dostupan hardverski blok

machine.SoftI2C pruža isti API na proizvoljnim GPIO pinovima, izvodeći protokol softverskim bit-bangingom:

from machine import SoftI2C, Pin

i2c = SoftI2C(scl=Pin("P5"), sda=Pin("P4"), freq=100_000)

Koristite ga kada uređaj mora biti na pinovima koji nisu spojeni na hardverski I2C blok, ili kada su svi hardverski blokovi zauzeti. Bit-bang petlja je sporija od hardverskog I2C-a i CPU ostaje zauzet tijekom cijele transakcije, ali je API identičan onome od I2C, pa postojeći kod prelazi promjenom samo konstruktora.