3.24. I2C koodissa¶
machine.I2C kapseloi laitteiston I2C-ohjaimen. Luo sellainen väylän id:llä ja valinnaisella kellotaajuudella:
from machine import I2C
i2c = I2C(2, freq=400_000)
id valitsee, mitä laitteiston I2C-lohkoa käytetään; käytettävissä olevat numerot ja niiden vastaavat SDA / SCL -nastat riippuvat kortista (katso OpenMV-kortit). freq on SCL:n kellotaajuus – 100_000 on standard mode, 400_000 on yleinen ”fast”-nopeus, jota useimmat sensorit tukevat.
3.24.1. Väylän skannaus¶
scan() käy läpi 7-bittisen osoiteavaruuden ja palauttaa listan jokaisesta laitteesta, joka kuittasi osoitteensa:
>>> i2c.scan()
[0x40, 0x68]
Tämä on ensimmäinen kokeiltava asia uuden väylän kytkemisen jälkeen. Jos laite on listassa, kytkentä ja ylösvetovastukset ovat kunnossa. Jos lista on tyhjä (tai odotettua lyhyempi), epäile ylösvetovastuksia, kytkentää tai laitteen osoitenastoja ennen kuin epäilet koodia.
3.24.2. Muistikartoitettu kaava¶
Useimmat I2C-sensorit paljastavat tilansa joukkona sisäisiä rekistereitä: tilaliput yhdessä osoitteessa, mittaustavut toisessa, asetukset kolmannessa. Kirjastossa on kaksi mukavuusmetodia, jotka kartoittuvat suoraan kaavaan ”osoita laite, osoita rekisteriin, lue tai kirjoita data”.
Rekisterin lukeminen:
addr = 0x68
reg = 0x3B
data = i2c.readfrom_mem(addr, reg, 6)
# `data` is 6 bytes starting at register 0x3B
Tämä yksittäinen kutsu antaa STARTin, lähettää laiteosoitteen kirjoitusbitin kanssa, lähettää rekisteriosoitteen (toistettu start), lähettää osoitteen uudelleen lukubitin kanssa, lukee 6 tavua, NACK:aa viimeisen ja antaa STOPin. Laite näkee vakiomuotoisen ”luku rekisteristä” -sekvenssin; skripti näkee yhden Python-kutsun.
Rekisteriin kirjoittaminen:
i2c.writeto_mem(addr, 0x6B, b"\x00")
Tämä sekvenssi on sama peilikuvana: START, osoite + kirjoitus, rekisteri, hyötykuormatavu, STOP.
Laitteille, joiden rekisteriosoite on kaksi tavua leveä (jotkin EEPROM-muistit ja 16-bittisesti osoitteistetut muistit), välitä addrsize=16:
data = i2c.readfrom_mem(addr, 0x0100, 32, addrsize=16)
3.24.3. Sensorin lukeminen¶
Lyhyt silmukka, joka lukee WHO_AM_I-tunnisteen ja kiihtyvyysanturin X-akselin tyypillisellä MEMS-sensorilla:
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() palauttaa bytes-olion, joten WHO_AM_I-luku indeksoi ensimmäisen (ja ainoan) tavun arvolla [0]. Kiihtyvyysanturin luku on kaksi raakatavua, jotka on koottava yhdeksi etumerkilliseksi 16-bittiseksi arvoksi; struct-muoto ">h" tekee sen etumerkillisenä big-endianina – tavujärjestys, jota useimmat I2C-sensorit käyttävät, päinvastoin kuin UART-yhteyksillä yleinen little-endian-konventio. struct.unpack() palauttaa aina monikon (yksi alkio muotomerkkiä kohden), joten [0] poimii ainoan arvon.
3.24.4. Matalamman tason pääsy¶
Laitteille, jotka eivät noudata rekisterikarttakaavaa, kaksi matalamman tason metodia antavat suoran hallinnan osoitevaiheeseen ja datan suuntaan:
i2c.writeto(addr, b"\x01\x02\x03") # write 3 bytes to addr
data = i2c.readfrom(addr, 4) # read 4 bytes from addr
Nämä ovat hyödyllisiä laitteille, joilla on komentovirtarajapinta (näytöt, jotkin reaaliaikakellot), joihin rekisterikartan mukavuusapurit eivät aivan sovi.
3.24.5. Bittien tahkominen, kun laitteistolohkoa ei ole saatavilla¶
machine.SoftI2C tarjoaa saman API:n mielivaltaisilla GPIO-nastoilla tahkoen protokollan bitit ohjelmistossa:
from machine import SoftI2C, Pin
i2c = SoftI2C(scl=Pin("P5"), sda=Pin("P4"), freq=100_000)
Käytä sitä, kun laitteen on oltava nastoissa, joita ei ole kytketty laitteiston I2C-lohkoon, tai kun jokainen laitteistolohko on käytössä. Bittien tahkomissilmukka on hitaampi kuin laitteiston I2C ja CPU pysyy varattuna koko tapahtuman ajan, mutta API on identtinen I2C:n kanssa, joten olemassa oleva koodi vaihtaa siihen muuttamalla vain konstruktoria.