3.24. I2C i kod¶
machine.I2C omsluter en hårdvaru-I2C-styrenhet. Skapa en med buss-id och en valfri klockfrekvens:
from machine import I2C
i2c = I2C(2, freq=400_000)
id väljer vilket I2C-hårdvarublock som ska användas; de tillgängliga numren och de SDA / SCL-stift de mappar till beror på kortet (se OpenMV-kort). freq är SCL-klockhastigheten – 100_000 är standardläge, 400_000 är den vanliga ”snabba” hastighet som de flesta sensorer stöder.
3.24.1. Skanna bussen¶
scan() går igenom det 7-bitars adressutrymmet och returnerar en lista över varje enhet som bekräftade sin adress:
>>> i2c.scan()
[0x40, 0x68]
Detta är det första man bör prova efter att ha kopplat upp en ny buss. Om en enhet finns på listan är kopplingen och uppdragningarna i sin ordning. Om listan är tom (eller kortare än väntat), misstänk uppdragningarna, kopplingen eller enhetens adresstift innan du misstänker koden.
3.24.2. Det minnesmappade mönstret¶
De flesta I2C-sensorer exponerar sitt tillstånd som en uppsättning interna register: statusflaggor på en adress, mätbyte på en annan, konfiguration på en tredje. Biblioteket har två bekvämlighetsmetoder som mappar direkt till mönstret ”adressera enheten, peka på ett register, läs eller skriv sedan data”.
Läsa ett register:
addr = 0x68
reg = 0x3B
data = i2c.readfrom_mem(addr, reg, 6)
# `data` is 6 bytes starting at register 0x3B
Det enda anropet utfärdar en START, skickar enhetsadressen med skrivbiten, skickar registeradressen (en upprepad start), skickar adressen igen med läsbiten, läser 6 byte, NACK:ar den sista och STOP:ar. Enheten ser standardsekvensen ”läs från register”; skriptet ser ett Python-anrop.
Skriva till ett register:
i2c.writeto_mem(addr, 0x6B, b"\x00")
Den sekvensen är densamma i spegelbild: START, adress + skrivning, register, nyttolastsbyte, STOP.
För enheter vars registeradress är två byte bred (vissa EEPROM:er och 16-bitars-adresserade minnen) skicka addrsize=16:
data = i2c.readfrom_mem(addr, 0x0100, 32, addrsize=16)
3.24.3. Läsa en sensor¶
En kort loop som läser WHO_AM_I-identifieraren och accelerometerns X-axel på en typisk MEMS-sensor:
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() returnerar ett bytes-objekt, så WHO_AM_I-läsningen indexerar den första (och enda) byten med [0]. Accelerometerläsningen är två råa byte som måste sättas samman till ett enda 16-bitars värde med tecken; struct-formatet ">h" gör det som big-endian med tecken – den byteordning de flesta I2C-sensorer använder, motsatsen till den little-endian-konvention som är vanlig på UART-länkar. struct.unpack() returnerar alltid en tupel (ett element per formattecken), så [0] plockar ut det enda värdet.
3.24.4. Lägre nivå-åtkomst¶
För enheter som inte följer registermappsmönstret ger två metoder på lägre nivå direkt kontroll över adressfasen och datariktningen:
i2c.writeto(addr, b"\x01\x02\x03") # write 3 bytes to addr
data = i2c.readfrom(addr, 4) # read 4 bytes from addr
Dessa är användbara för enheter med kommandoströmsgränssnitt (displayer, vissa realtidsklockor) där registermappens bekvämlighetshjälpare inte riktigt passar.
3.24.5. Bit-banging när inget hårdvarublock är tillgängligt¶
machine.SoftI2C tillhandahåller samma API på godtyckliga GPIO-stift och bit-bangar protokollet i programvara:
from machine import SoftI2C, Pin
i2c = SoftI2C(scl=Pin("P5"), sda=Pin("P4"), freq=100_000)
Använd det när enheten behöver vara på stift som inte är kopplade till ett I2C-hårdvarublock, eller när alla hårdvarublock är upptagna. Bit-bang-loopen är långsammare än hårdvaru-I2C och CPU:n förblir upptagen under hela transaktionen, men API:et är identiskt med I2C så befintlig kod byter över genom att enbart ändra konstruktorn.