3.24. I2C dalam kode¶
machine.I2C membungkus kontroler I2C perangkat keras. Buat satu dengan id bus dan frekuensi clock opsional:
from machine import I2C
i2c = I2C(2, freq=400_000)
id memilih blok I2C perangkat keras yang akan digunakan; nomor yang tersedia dan pin SDA / SCL yang dipetakannya bergantung pada papan (lihat Papan OpenMV). freq adalah laju clock SCL -- 100_000 adalah mode standar, 400_000 adalah kecepatan "cepat" umum yang didukung sebagian besar sensor.
3.24.1. Memindai bus¶
scan() menelusuri ruang alamat 7-bit dan mengembalikan daftar setiap perangkat yang memberikan ACK pada alamatnya:
>>> i2c.scan()
[0x40, 0x68]
Ini adalah hal pertama yang dicoba setelah menyambungkan bus baru. Jika perangkat ada dalam daftar, pengkabelan dan pull-up baik. Jika daftar kosong (atau lebih pendek dari yang diharapkan), curigai pull-up, pengkabelan, atau pin alamat perangkat sebelum mencurigai kode.
3.24.2. Pola memory-mapped¶
Sebagian besar sensor I2C mengekspos kondisinya sebagai sekumpulan register internal: flag status di satu alamat, byte pengukuran di alamat lain, konfigurasi di yang ketiga. Pustaka memiliki dua metode kenyamanan yang langsung memetakan ke pola "alamati perangkat, tunjuk ke register, kemudian baca atau tulis data".
Membaca sebuah register:
addr = 0x68
reg = 0x3B
data = i2c.readfrom_mem(addr, reg, 6)
# `data` is 6 bytes starting at register 0x3B
Satu panggilan tersebut mengeluarkan START, mengirimkan alamat perangkat dengan bit tulis, mengirimkan alamat register (sebuah repeated start), mengirim ulang alamat dengan bit baca, membaca 6 byte, memberikan NACK pada byte terakhir, dan STOP. Perangkat melihat urutan standar "baca dari register"; skrip melihat satu panggilan Python.
Menulis ke sebuah register:
i2c.writeto_mem(addr, 0x6B, b"\x00")
Urutan tersebut adalah cerminan: START, alamat + tulis, register, byte payload, STOP.
Untuk perangkat yang alamat registernya lebar dua byte (beberapa EEPROM dan memori beralamat 16-bit), berikan addrsize=16:
data = i2c.readfrom_mem(addr, 0x0100, 32, addrsize=16)
3.24.3. Membaca sensor¶
Loop singkat yang membaca identifier WHO_AM_I dan sumbu X akselerometer pada sensor MEMS yang tipikal:
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() mengembalikan objek bytes, sehingga pembacaan WHO_AM_I mengindeks byte pertama (dan satu-satunya) dengan [0]. Pembacaan akselerometer adalah dua byte mentah yang harus digabungkan menjadi satu nilai 16-bit bertanda; format struct ">h" melakukan itu sebagai big-endian bertanda -- urutan byte yang digunakan sebagian besar sensor I2C, kebalikan dari konvensi little-endian yang umum pada tautan UART. struct.unpack() selalu mengembalikan tuple (satu elemen per karakter format), sehingga [0] mengekstrak nilai tunggal.
3.24.4. Akses tingkat lebih rendah¶
Untuk perangkat yang tidak mengikuti pola peta register, dua metode tingkat lebih rendah memberikan kendali langsung atas fase alamat dan arah data:
i2c.writeto(addr, b"\x01\x02\x03") # write 3 bytes to addr
data = i2c.readfrom(addr, 4) # read 4 bytes from addr
Ini berguna untuk perangkat dengan antarmuka aliran perintah (tampilan, beberapa jam waktu nyata) di mana helper kenyamanan peta register tidak sepenuhnya cocok.
3.24.5. Bit-banging ketika tidak ada blok perangkat keras yang tersedia¶
machine.SoftI2C menyediakan API yang sama pada pin GPIO sembarang, melakukan bit-banging protokol dalam perangkat lunak:
from machine import SoftI2C, Pin
i2c = SoftI2C(scl=Pin("P5"), sda=Pin("P4"), freq=100_000)
Gunakan ini ketika perangkat perlu berada di pin yang tidak terhubung ke blok I2C perangkat keras, atau ketika setiap blok perangkat keras sedang digunakan. Loop bit-bang lebih lambat dari I2C perangkat keras dan CPU tetap sibuk selama seluruh transaksi, tetapi API-nya identik dengan I2C sehingga kode yang ada dapat beralih hanya dengan mengubah konstruktor.