3.24. Kodda I2C

machine.I2C, bir donanımsal I2C denetleyicisini sarmalar. Veriyolu kimliği ve isteğe bağlı bir saat frekansı ile bir tane oluşturun:

from machine import I2C

i2c = I2C(2, freq=400_000)

id, hangi donanımsal I2C bloğunun kullanılacağını seçer; mevcut numaralar ve bunların eşlendiği SDA / SCL pinleri karta bağlıdır (bkz. OpenMV Kartları). freq, SCL saat hızıdır – 100_000 standart moddur, 400_000 çoğu sensörün desteklediği yaygın “hızlı” hızdır.

3.24.1. Veriyolunu tarama

scan(), 7 bitlik adres alanını dolaşır ve adresini onaylayan her cihazın bir listesini döndürür:

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

Bu, yeni bir veriyolunu kabloladıktan sonra denenecek ilk şeydir. Bir cihaz listedeyse, kablolama ve pull-up’lar iyidir. Liste boşsa (ya da beklenenden kısaysa), koddan şüphelenmeden önce pull-up’lardan, kablolamadan veya cihazın adres pinlerinden şüphelenin.

3.24.2. Belleğe eşlenmiş desen

Çoğu I2C sensörü durumunu bir dizi dahili yazmaç olarak açığa çıkarır: bir adreste durum bayrakları, bir başkasında ölçüm baytları, bir üçüncüsünde yapılandırma. Kütüphanenin, doğrudan “cihazı adresle, bir yazmacı işaret et, ardından veriyi oku veya yaz” desenine eşlenen iki kolaylık yöntemi vardır.

Bir yazmacı okuma:

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

O tek çağrı bir START verir, cihaz adresini yazma biti ile gönderir, yazmaç adresini gönderir (tekrarlanan başlangıç), adresi okuma biti ile yeniden gönderir, 6 bayt okur, sonuncusuna NACK verir ve STOP yapar. Cihaz standart “yazmaçtan oku” dizisini görür; betik ise tek bir Python çağrısı görür.

Bir yazmaca yazma:

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

O dizi, ayna görüntüsünde aynısıdır: START, adres + yazma, yazmaç, yük baytı, STOP.

Yazmaç adresi iki bayt genişliğinde olan cihazlar için (bazı EEPROM’lar ve 16 bit adreslemeli bellekler) addrsize=16 geçirin:

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

3.24.3. Bir sensörü okuma

Tipik bir MEMS sensöründe WHO_AM_I tanımlayıcısını ve ivmeölçer X eksenini okuyan kısa bir döngü:

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() bir bytes nesnesi döndürür, bu nedenle WHO_AM_I okuması ilk (ve tek) bayta [0] ile indeksler. İvmeölçer okuması, tek bir işaretli 16 bitlik değere birleştirilmesi gereken iki ham bayttır; struct biçimi ">h" bunu büyük-endian işaretli olarak yapar – çoğu I2C sensörünün kullandığı bayt sırası, UART bağlantılarında yaygın olan küçük-endian geleneğinin tersi. struct.unpack() her zaman bir demet döndürür (her biçim karakteri için bir öğe), bu nedenle [0] tek değeri çekip çıkarır.

3.24.4. Daha düşük seviyeli erişim

Yazmaç-haritası desenini izlemeyen cihazlar için, iki düşük seviyeli yöntem adres aşaması ve veri yönü üzerinde doğrudan kontrol sağlar:

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

Bunlar, yazmaç-haritası kolaylık yardımcılarının tam uymadığı komut akışı arayüzlü cihazlar (ekranlar, bazı gerçek zamanlı saatler) için yararlıdır.

3.24.5. Donanım bloğu yokken bit-banging

machine.SoftI2C, protokolü yazılımda bit-banging yaparak rastgele GPIO pinlerinde aynı API’yi sağlar:

from machine import SoftI2C, Pin

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

Cihazın bir donanımsal I2C bloğuna kablolanmamış pinlerde olması gerektiğinde ya da her donanım bloğu kullanımdayken kullanın. Bit-bang döngüsü donanımsal I2C’den daha yavaştır ve işlemin tamamı boyunca CPU meşgul kalır, ancak API I2C ile aynıdır, böylece mevcut kod yalnızca yapıcıyı değiştirerek geçiş yapar.