3.1. Мікроконтролери¶
OpenMV Cam працює на мікроконтролері (MCU): єдиному чипі, який поєднує процесор (CPU), оперативну пам’ять (RAM), флеш-пам’ять для зберігання програми та набір периферійних пристроїв – апаратних блоків для взаємодії із зовнішнім світом.
Периферійні пристрої – найцікавіша частина. Кожен з них – це кремнієвий блок, призначений для однієї задачі: встановити вивід у високий або низький рівень, виміряти аналогову напругу, передати байти по послідовній шині. Процесор налаштовує кожен периферійний пристрій і зчитує з нього дані через регістри – фіксовані адреси пам’яті, за якими апаратна частина стежить та оновлює їх.
MicroPython огортає ці регістри у класи всередині модуля machine. machine.Pin(...) повертає об’єкт, що керує виводом GPIO (загального призначення) – провідником, який чип може утримувати у високому (близько 3,3 В) або низькому (близько 0 В) стані, або зчитувати як один із цих двох станів, коли ним керує зовнішній сигнал. machine.ADC(...) відкриває доступ до аналого-цифрового перетворювача, який вимірює напругу на виводі та повертає її у вигляді числа. machine.UART(...) реалізує UART (universal asynchronous receiver/transmitter) – периферійний пристрій, що надсилає і приймає байти по одному біту через пару провідників: TX (передача) та RX (приймання). Інші класи охоплюють решту периферійних пристроїв. Скрипт читає та записує Python-об’єкти; MicroPython перетворює кожне звернення на відповідні читання та записи регістрів, а ті переміщують біти на фізичних провідниках.
MCU об’єднує CPU, пам’ять і периферійні пристрої в одному чипі. Кожен периферійний пристрій доступний у Python через клас у модулі machine.¶
3.1.1. Головний цикл¶
Майже кожна програма для мікроконтролера має одну і ту ж структуру: одноразове налаштування на початку скрипта (імпорт модулів, конфігурація виводів, відкриття шин), а потім нескінченний цикл while True: наприкінці. Всередині циклу програма зчитує вхідні дані, приймає рішення та оновлює виходи знову і знову. Цикл і є програмою; коли скрипт завершується, пристрій перестає щось виконувати.
# setup, runs once
from machine import Pin
led = Pin("P0", Pin.OUT)
# main loop, runs forever
while True:
led.value(1)
# ... do work ...
led.value(0)
# ... do other work ...
Ця структура – одноразове налаштування, а потім нескінченний цикл – називається патерном головного циклу. Все, що описано далі, стосується того, що знаходиться всередині нього.
3.1.2. Керування реальним часом¶
Настільна програма виконується паралельно з іншими. Операційна система планує її роботу через один або кілька потоків – незалежних потоків виконання, між якими вона перемикається щомілісекунди. Коли один потік очікує введення-виведення (диск, мережа, переміщення миші), ОС передає CPU іншому потоку. Програма здебільшого керується подіями: менеджер вікон викликає ваш код, коли надходить ввід; бібліотека HTTP відновлює ваш код, коли байти надходять на сокет. Якась більша система викликає ваш код.
Програма для мікроконтролера – це протилежність. За замовчуванням немає операційної системи, планувальника і жодного іншого потоку. Щойно показаний головний цикл є єдиним циклом. Периферійні пристрої генерують переривання або виставляють прапорці стану; цикл опитує їх або безпосередньо обробляє переривання. Якщо цикл зупиняється у time.sleep_ms(1000), пристрій нічого не робить ту одну секунду; немає іншого потоку, який заповнив би паузу.
Із цього випливають два наслідки, що застосовуються повсюдно:
Час реальний. Двічі зчитати вивід у щільному циклі займає мікросекунди; затримка на десять мілісекунд означає десять мілісекунд, протягом яких нічого іншого не відбувається. Відповіддю на це є патерн неблокуючого таймінгу.
Апаратне забезпечення реальне. Встановлення
machine.Pin.valueу1подає приблизно 3,3 В на фізичний провідник; встановлення в0подає приблизно 0 В. Інші частини схеми відразу бачать цю напругу – включно з компонентами, яким вивід може завдати шкоди, якщо керується неправильно.