3.26. Bus CAN dalam kode¶
machine.CAN membungkus pengendali CAN perangkat keras. Aktifkan dengan id bus dan laju bit:
from machine import CAN
can = CAN(1, 500_000)
can.set_filters(None) # accept all incoming IDs
Laju bit harus cocok persis dengan setiap simpul lain pada bus -- 125_000, 250_000, 500_000 dan 1_000_000 adalah nilai-nilai yang umum. set_filters() mengonfigurasi ID mana yang akan diteruskan oleh pengendali; None berarti menerima semua (berguna saat menghidupkan tautan, kurang berguna setelah bus sibuk).
3.26.1. Di dalam pengendali¶
Tiga bagian perangkat keras berada di antara kode Python kamera dan bus -- kotak surat TX, sebuah filter penerimaan, dan FIFO RX. Masing-masing dipetakan ke bagian dari API CAN yang digunakan di bawah ini.
Kotak surat TX, filter penerimaan, dan FIFO RX pengendali antara perangkat lunak dan bus.¶
Kotak surat TX. Sekumpulan kecil slot perangkat keras (biasanya tiga) yang menampung bingkai keluar yang telah diserahkan kamera melalui
send()namun belum sampai ke bus. Ketika bus idle, pengendali memilih kotak surat dengan ID bernomor terendah (prioritas tertinggi) dan melakukan arbitrase untuk bus atas namanya. Kamera tidak memilih kotak surat; pengendali menetapkan satu dan mengembalikan indeksnya darisend().Filter penerimaan. Perangkat keras yang dapat dikonfigurasi yang membandingkan ID setiap bingkai masuk terhadap daftar pola dan membuang apa pun yang tidak cocok. Bingkai yang lolos dilanjutkan ke FIFO RX; bingkai yang ditolak dibuang oleh pengendali tanpa pernah mencapai Python.
set_filters()mengonfigurasi pola-pola ini.FIFO RX. Antrean first-in, first-out -- bingkai pertama yang masuk juga merupakan bingkai pertama yang keluar, seperti antrean di loket tiket. Pengendali menambahkan bingkai yang diterima ke belakang antrean saat tiba, dan
recv()mengambilnya dari depan dalam urutan yang sama. Antrean penting karena bus menangkap bingkai di latar belakang sementara Python sedang sibuk di tempat lain; kamera kemudian mengosongkannya satu per satu tanpa kehilangan satu pun, selama FIFO tidak meluap.
3.26.2. Mengirim bingkai¶
send() mengantrekan bingkai untuk transmisi:
can.send(0x123, b"\x01\x02\x03\x04")
Argumen pertama adalah ID (bilangan bulat 11-bit untuk bingkai standar); yang kedua adalah payload (0 hingga 8 byte untuk CAN Classic). Panggilan mengembalikan indeks bilangan bulat kecil yang mengidentifikasi kotak surat perangkat keras tempat bingkai masuk. Pengendali melakukan arbitrase dengan transmitter lain pada bus dan mentransmisi ulang sesuai kebutuhan tanpa bantuan lebih lanjut dari perangkat lunak.
Untuk ID yang diperluas (29-bit), OR-kan flag CAN.FLAG_EXT_ID ke dalam argumen ketiga:
can.send(0x18FF1234, b"hello", CAN.FLAG_EXT_ID)
3.26.3. Menerima bingkai¶
Pengendali dimulai tanpa filter yang dipasang dan membuang setiap bingkai masuk. Sebelum recv() akan mengembalikan apa pun, panggil set_filters() sekali -- bentuk paling sederhana adalah None, yang menerima setiap ID:
can.set_filters(None) # accept every frame
recv() kemudian mengembalikan bingkai berikutnya dalam FIFO penerimaan, atau None jika tidak ada yang menunggu:
msg = can.recv()
if msg is not None:
can_id, data, flags, errs = msg
print("got", hex(can_id), bytes(data))
Bus mengisi FIFO RX di latar belakang, sehingga loop utama hanya mengosongkannya secepat iterasinya. Selama FIFO lebih dalam dari jeda terpanjang antara pengosongan, tidak ada bingkai yang hilang.
3.26.4. Filter¶
Bus nyata biasanya sibuk dengan bingkai yang tidak dipedulikan kamera. Filter perangkat keras membiarkan pengendali membuang ID yang tidak diinginkan sebelum mencapai FIFO. set_filters() mengambil daftar tuple (id, mask, flags); sebuah bingkai lolos filter jika ID-nya, yang di-mask oleh mask, cocok dengan id yang dikonfigurasi:
# Accept only IDs 0x100 - 0x10F (mask off the bottom 4 bits)
can.set_filters(((0x100, 0x7F0, 0),))
# Accept IDs 0x300 and 0x700 exactly
can.set_filters(((0x300, 0x7FF, 0),
(0x700, 0x7FF, 0)))
Bingkai yang tidak cocok dibuang oleh pengendali dan tidak pernah muncul di recv(), yang menghemat ruang buffer dan waktu CPU.
3.26.5. Kondisi kesalahan dan pemulihan¶
Bus CAN nyata mengalami kesalahan transmisi -- hubungan singkat ke ground, simpul yang hilang, noise elektrikal yang merusak bit. Pengendali menyimpan dua penghitung yang melacak perilaku ini: Transmit Error Counter (TEC) dan Receive Error Counter (REC), masing-masing ditambah ketika pengendali mendeteksi kesalahan dan dikurangi setelah transfer yang berhasil. Nilai penghitung menempatkan pengendali ke dalam salah satu dari empat kondisi:
Error Active (TEC dan REC keduanya di bawah 96). Operasi normal. Ketika simpul mendeteksi kesalahan bus, ia mentransmisikan bingkai kesalahan aktif yang dominan, yang memaksa setiap simpul lain untuk membuang bingkai yang sedang berlangsung sehingga pengirim dapat mencoba ulang.
Error Warning (salah satu penghitung mencapai 96). Masih sepenuhnya aktif di bus -- kondisi peringatan adalah sinyal perangkat lunak bahwa kesalahan sedang menumpuk, bukan perubahan perilaku.
Error Passive (salah satu penghitung mencapai 128). Simpul masih berada di bus namun berhenti mengirimkan bingkai kesalahan dominan; kesalahan sekarang diberi sinyal dengan bingkai kesalahan pasif (resesif) sehingga simpul yang rusak tidak dapat terus mengganggu bus bagi semua orang.
Bus Off (TEC mencapai 256). Pengendali telah memutuskan bahwa simpul ini terlalu tidak dapat diandalkan untuk berpartisipasi. Ia terputus dari bus, berhenti mentransmisikan dan mengakui, dan tetap keluar sampai perangkat lunak secara eksplisit memulai ulangnya.
Tiga transisi pertama sepenuhnya otomatis -- saat penghitung berkurang setelah bingkai yang berhasil, pengendali memindahkan dirinya kembali ke Error Active tanpa intervensi.
Bus Off adalah satu-satunya kondisi yang memerlukan tindakan perangkat lunak. restart() mereset pengendali dan mengembalikannya ke Error Active. Pola khas adalah memeriksa kondisi dari loop utama dan memulai ulang setelah penundaan singkat untuk memberi bus waktu untuk stabil:
import time
from machine import CAN
can = CAN(1, 500_000)
can.set_filters(None)
while True:
if can.state() == CAN.STATE_BUS_OFF:
time.sleep_ms(100)
can.restart()
# ... rest of the loop
Nilai penghitung saat ini tersedia dari get_counters() untuk diagnostik -- TEC yang naik secara stabil di bus yang sebaliknya tenang biasanya menunjuk pada pengkabelan, terminasi, atau laju bit yang salah dikonfigurasi.