L'ATmega328 (il cuore dell'Arduino UNO e Nano) è il microcontrollore più popolare, meglio documentato, e più semplice per chi vuole iniziare a capire come funziona davvero l'informatica.
Qui non ti insegno a programmare solo in Assembly, ma a capire cosa succede nel profondo. Perché tutto – sia nei PC moderni, sia nei microcontrollori – gira attorno a registri fatti di bit, cioè 0 e 1.
Con il tool costycnc.it/avr1 puoi compilare e caricare il codice direttamente dal browser: niente installazioni, solo risultati!
E ricorda: quello che impari qui, non lo sanno nemmeno molti ingegneri. Sii fiero di aver toccato un bit e acceso un LED scrivendo solo 1 in un registro!
Immagina Arduino come un armadio pieno di casetti numerati. Ogni casetto è un registro, un piccolo contenitore dove possiamo mettere uno o zero. Qui non userò nomi astratti o complicati, ma solo numeri. Perché?
Perché questa scelta è fatta apposta, con un obiettivo didattico molto preciso: togliere ogni distrazione e rendere semplice e chiaro il funzionamento di un computer o microcontrollore. Anche chi non ha mai programmato può capire facilmente che stiamo solo mettendo dei valori (uno o zero) in questi casetti numerati.
Questo metodo semplice e diretto è come una lente d’ingrandimento che ci permette di vedere cosa succede davvero dentro a ogni PC o MCU, senza perdersi nei nomi complicati o nelle astrazioni.
Lo scopo non è solo insegnarti a leggere un carattere dalla seriale, ma mostrarti passo passo COME ogni PC o MCU lavora davvero, a livello più profondo, con un approccio semplice e concreto.
Nei miei esempi futuri troverai sempre questa stessa tecnica, questo stesso modo di spiegare: semplice, chiaro e unico, perché crediamo che capire il funzionamento reale sia il primo vero passo per imparare a programmare davvero.
Nei microcontrollori (come gli ATmega) la comunicazione seriale funziona scrivendo e leggendo bit in registri speciali, cioè piccole scatole di memoria con significati precisi.
In questo esempio useremo i registri con i loro numeri, non i nomi. Non serve conoscere i nomi, basta il numero. E quei numeri sono veri: li puoi trovare nel datasheet ufficiale del microcontrollore.
Ti consiglio vivamente di aprire il datasheet e guardare con i tuoi occhi: tanti programmatori avanzati non sanno leggere un datasheet perché non capiscono che tutto si riduce a questi registri numerati.
Tutto quello che impari con migliaia, anzi miliardi di nomi diversi, alla fine è solo un numero d’ordine di un registro nella gerarchia del microcontrollore. È tutto qui.
Chi vede l’informatica così, senza astrazioni inutili, avrà più coraggio e più voglia di imparare davvero.
Nel codice:
ldi r16, 0b00000110
diciamo: “8 bit per carattere, 1 bit di stop, senza parità”.ldi r16, 0b00011000
accendiamo RX e TX, cioè abilitiamo la comunicazione.In pratica, tutta la magia avviene scrivendo o leggendo bit nei registri. Questa è la vera programmazione a basso livello, quella che succede “sotto il cofano”. Molti programmatori moderni non la vedono mai, ma è qui che inizia tutto.
.org 0
rjmp init
.org 0x68
init:
rcall init_uart
read:
rcall read_byte
mov r16, r20
andi r16, 0b10111111
;rcall send_char
rcall led
rjmp read
; init_uart: inizializza UART a 9600 baud, 8N1
init_uart:
ldi r16, 103
sts 0xC4, r16
ldi r16, 0
sts 0xC5, r16
ldi r16, 0b00000110
sts 0xC2, r16
ldi r16, 0b00011000
sts 0xC1, r16
ret
; read_byte: legge byte dalla seriale se presente
read_byte:
lds r18, 0xC0
sbrc r18, 7
rjmp read_done
ret
read_done:
lds r20, 0xC6
ret
; led: lampeggia usando delay via loop
led:
sbi 4, 5
dec r19
brne led
dec r17
brne led
dec r16
brne led
sbi 3, 5
ret
; send_char: invia carattere via UART
send_char:
lds r18, 0xC0
sbrs r18, 5
rjmp send_char
sts 0xC6, r16
ret
.org 0
→ Indirizzo iniziale: qui parte il programma dopo il reset.
rjmp init
→ Salta alla parte principale del programma.
.org 0x68
→ Dove inizia davvero il codice dell'applicazione.
init:
→ Etichetta di inizio.
rcall init_uart
→ Inizializza la comunicazione seriale.
read:
→ Etichetta per leggere dati in loop.
rcall read_byte
→ Tenta di leggere un byte dalla seriale.
mov r16, r20
→ Copia il dato ricevuto nel registro r16.
andi r16, 0b10111111
→ Rimuove il bit 6 (solo per esempio).
rcall led
→ Usa il valore per accendere il LED (delay dipendente dal carattere).
rjmp read
→ Ripete il ciclo all'infinito.
ldi r16, 103
→ Calcolo per 9600 baud a 16 MHz.sts 0xC4, r16
→ Scrivi in UBRR0L.sts 0xC5, r16
→ Scrivi in UBRR0H (alto).ldi r16, 0b00000110
→ Formato dati: 8 bit, 1 stop, nessuna parità.ldi r16, 0b00011000
→ Abilita RX e TX.sts 0xC1, r16
→ Abilita RX e TX.lds r18, 0xC0
→ Leggi stato USART (UCSR0A).sbrc r18, 7
→ Se bit 7 = 1 (dato pronto), salta.lds r20, 0xC6
→ Legge il dato dalla porta seriale (UDR0).sbi 4,5
→ DDRB bit 5: imposta pin 13 come output.dec r19/r17/r16
→ Ritardi per simulare attesa visibile.sbi 3,5
→ PORTB bit 5: accende il LED.sbrs r18, 5
→ Attende che il buffer seriale sia pronto.sts 0xC6, r16
→ Invia r16 sulla seriale.Collega un Arduino Nano via USB, apri costycnc.it/avr1, incolla il codice e premi UPLOAD. Il LED lampeggerà con ogni carattere ricevuto!
Non stai solo programmando. Stai capendo il cuore dell'informatica.