3.1. Microcontroladores

A OpenMV Cam funciona num microcontrolador (MCU): um único chip que combina uma CPU, memória de trabalho (RAM), armazenamento de programas (flash) e um conjunto de periféricos – blocos de hardware para interagir com o mundo exterior.

Os periféricos são a parte interessante. Cada um é uma peça de silício dedicada a uma única tarefa: colocar um pino a alto ou baixo, medir uma tensão analógica, enviar bytes por um barramento série. A CPU configura e lê cada periférico através de registos – endereços de memória fixos que o hardware monitoriza e atualiza.

O MicroPython encapsula esses registos em classes dentro do módulo machine. machine.Pin(...) devolve um objeto que controla um pino de entrada/saída de uso geral (GPIO) – um fio que o chip pode manter a alto (cerca de 3,3 V) ou a baixo (cerca de 0 V), ou ler como um desses dois estados quando algo externo o aciona. machine.ADC(...) expõe o conversor analógico-digital, que mede a tensão num pino e a reporta como um número. machine.UART(...) executa um transmissor/recetor assíncrono universal (UART) – um periférico que envia e recebe bytes um bit de cada vez através de um par de fios, TX (transmissão) e RX (receção). Outras classes cobrem os restantes periféricos. O script lê e escreve objetos Python; o MicroPython traduz cada acesso nas leituras e escritas de registo correspondentes, e essas movem bits em fios físicos.

A single chip outline containing labelled blocks -- CPU, RAM, flash, and a row of peripheral blocks (GPIO, ADC, Timer/PWM, UART/SPI/I2C, CAN) connected by an internal bus, with arrows from each peripheral exiting the chip toward physical pin labels.

Um MCU agrupa CPU, memória e periféricos num único chip. Cada periférico é exposto ao Python por uma classe no módulo machine.

3.1.1. O ciclo principal

Quase todos os programas de microcontrolador partilham a mesma estrutura: configuração única no início do script (importar módulos, configurar pinos, abrir barramentos), depois um ciclo infinito while True: no final. Dentro do ciclo, o programa lê entradas, toma decisões e atualiza saídas repetidamente. O ciclo é o programa; quando o script termina, o dispositivo deixa de fazer qualquer coisa.

# 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 ...

Esta estrutura – configurar uma vez, depois ciclar para sempre – é o padrão do ciclo principal. Tudo o que se segue diz respeito ao que vai dentro dele.

3.1.2. Controlo em tempo real

Um programa de ambiente de trabalho funciona ao lado de muitos outros. O sistema operativo agenda o seu trabalho em uma ou mais threads – fluxos de execução independentes entre os quais alterna milissegundo a milissegundo. Quando uma thread aguarda I/O (disco, rede, o utilizador a mover o rato), o SO entrega a CPU a outra. O programa é maioritariamente orientado a eventos: o gestor de janelas chama o seu código quando chega um input, a biblioteca HTTP retoma o seu código quando chegam bytes no socket. Algo maior está a chamá-lo.

Um programa de microcontrolador é o oposto. Por defeito não há sistema operativo, não há agendador e não há outra thread. O ciclo principal mostrado anteriormente é o único ciclo. Os periféricos disparam interrupções ou expõem flags de estado; o ciclo faz polling ou trata as interrupções diretamente. Se o ciclo ficar parado num time.sleep_ms(1000), o dispositivo não faz nada durante esse segundo; não há outra thread para preencher o vazio.

Duas consequências surgem e aplicam-se em todo o lado:

  • O tempo é real. Ler um pino duas vezes num ciclo apertado demora microssegundos; dormir dez milissegundos significa dez milissegundos durante os quais mais nada acontece. O padrão de temporização não bloqueante é a resposta.

  • O hardware é real. Definir machine.Pin.value para 1 coloca aproximadamente 3,3 V num fio físico; defini-lo para 0 coloca aproximadamente 0 V. Outras partes do circuito veem essa tensão imediatamente – incluindo quaisquer componentes que o pino pode danificar se for acionado incorretamente.