Introduzione all'uso del periferiche principali del microcontrollore pic18F2420
In questa sede si vogliono dare delle indicazioni sul possibile utilizzo delle principali periferiche del microcontrollore,
fissando l'attenzione su come riuscire a indicare anche verbalmente, in linguaggio di progetto, le operazioni da compiere
per utilizzarle, senza scendere nei dettagli della programmazione e dell'utilizzo dei singoli bit di tutti i registri di stato e
comando, per la qual cosa si rimanda al manuale completo.
Tutte le periferiche hanno dei registri dati, stato e comando; spesso stato e comando sono combinati in uno stesso
registro. Praticamente tutte le periferiche sono sorgenti di interruzione mascherabile (cioè possono essere disabilitate a
interrompere) per la CPU. Abibiamo quindi registri di abilitazione delle interruzioni, registri di stato delle interruzioni e
registri di impostazione della priorità delle sorgenti di interruzione. Per la crescita tumultuosa dei dispositivi MicroChip, e
nel tentativo di rendere i nuovi modelli sw compatibili con quelli precedenti, abilitazioni, stato, priorità e configurazioni
varie si trovano sparpagliati in un modo che può sgomentare un utilizzatore che provenga da dispositivi più consolidati ed
ordinati, ad esempio ATMEL, ZILOG, MOTOROLA. L'accoppiamento pin / segnale (bit porta) dipende dal package.
La maggioranza dei registri dati a 16 bit sono accessibili o come un intero registro a 16 bit o come due registri a 8 bit
parte alta H e parte bassa L; così ADRES è il registro a 16 bit con il risultato della conversione AD; esso può essere visto
come ADRESH concatenato con ADRESL (sono però 10 bit su 16, giustificabili a sinistra(default) o a destra). Così TMR0
equivale a TMR0H concatenato con TMR0L.
Le varie periferiche hanno i loro segnali di ingresso e uscita MULTIPLEXATI sui vari (da 28 a 44) pin dell'integrato (per
ovvie ragioni di spazio: avendo ciascun pin mediamente quattro funzioni un 28 pin non multiplexato diventerebbe un 112
pin) per cui non possono, ovviamente essere usate tutte insieme e bisogna fare delle scelte a seconda delle nostre
esigenze e non sempre ci si riesce allora bisogna "mettere qualcosa fuori" ovvero collegare qualche periferica esterna o
cambiare microcontrollore, modello, famiglia o addirittura marca (e quindi compilatore!!)
Il compilatore MCC18 fornisce delle librerie di funzioni C per l'utilizzo ad alto livello di ogni periferica; in tal modo ci
possiamo preoccupare meno di come essa sia fatta dentro, dei suoi dettagli HW, anche se spesso può essere più
semplice e veloce operare a basso livello, manovrando i registri delle periferiche.
La descrizione delle funzioni di libreria si trova nel file C:\MCC18\doc\PIC18F Peripheral Library Help Document.chm
Si riporta la piedinatura del componente (per 2 versioni di package):
Elenco periferiche PRINCIPALI (riferimento pic18f2420, 28 pin dip):
1) 4 Porte A,B,C, E (1 bit solo input rinunciando al reset esterno) di I/O parallelo bidirezionale,bit programmabili
con possibilità di:
ingresso: con pull-up (debole, r alta) interno a vdd (questo evita di metterlo esterno, ad esempio per gestire tasti), trigger
di schmitt (serve a rendere precise le transizioni in presenza di livelli incerti in ingresso).
uscite: open drain (con pull-up esterno) o totem pole (senza pull-up esterno, cmos), three state (cioè elettricamente
sconnettibile dal circuito al quale il pin è collegato).
Le porte sono sostanzialmente gestite da 3 registri TRIS (direzione), PORT (ingresso, ma in realtà con il compilatore
MCC18 anche uscita, LAT (uscita). I bit si chiamano convenzionalmene RA0-RA7 e similmente per le altre porte. Si può
accedere ai singoli bit delle porte con il costrutto NOME_REGISTRObits.NOME_BIT ad esempio TRISAbits.TRIS0 o
PORTCbits.RC4. 3 bit della porta B (segnali RB0/INT0, RB1/INT1, RB2/INT2) possono generare interruzione su
transizione HL o LH, selezionabile. Anche i segnali RB4,5,6,7 possono generare una interruzione, ma si tratta di una
richiesta cumulativa di tipo OR: l'interruzione viene richiesta se uno o più di uno di tali segnali cambia stato, non sono 4
interruzioni singole. Esistono altri registri per configurare pull-up, open drain, trigger di schmitt, three-state; per default gli
ingressi hanno il pull-up (debole), trigger di schmitt, mentre le uscite sono totem-pole.
Nota1: la porta E consiste in un solo bit multiplexato con il reset (RE3, pin 1); in sede di programmazione, con un fusibile
di configurazione, decido se utilizzare tale bit come I/O, rinunciando alla possibilità di resettare il micro esternamente con
un pulsante o un segnale, o meno (#pragma config MCLRE = OFF o da settings MPLAB). E' una soluzione da extrema
ratio. Questo pin serve anche per fornire la tensione (più alta, 15V) necessaria per la programmazione della flash eprom.
Nota2: la porta A consiste in 8 bit o solo 6 se voglio usare l'oscillatore interno al quarzo; il quarzo va collegato ai pin RA6
RA7 (pin 10 e 9) che non possono essere usati come I/O (#pragma config OSC = INTIO67 o da settings MPLAB).
Nota3: Si può usare poi usare solo RA6 come ingresso di clock esterno, lasciando libero per I/O RA7 (#pragma config
OSC = INTIO7 o da settings MPLAB), o invece replicare il clock su questo piedino.
Segnali: RA0-7,RB0-7,RC0-7,RE3.
2) Convertitore AD sar a 10 bit con fino a 13 (10 nel 28 pin) canali multiplexati. Prescaler del clock selezionabile,
tempo fra una acquisizione e l'altra selezionabile (ADCON2), tensioni di riferimento interne o esterne selezionabili,
numero canali usati selezionabile (ADCON1). Registri associati ADCON0, ADCON1, ADCON2, ADRES; i tredici canali
del convertitore sono un pò sparpagliati sulle porte A, e B. Il convertitore può essere gestito a polling, controllando il bit
DONE del registro ADCON0 o ad interrupt, in quanto esso può generare una interruzione alla fine di una conversione;
quindi si può avviare la conversione dando GO in ADCON0, effettuare qualsiasi altro compito che viene
momentaneamente interrotto alla fine della conversione, il cui risultato viene utilizzato dalla routine di servizio, e poi
ripreso. La routine di interruzione può ad esempio, dopo aver utilizzato il risultato della conversione, avviare una
conversione successiva; in tal modo si ha una sequenza di acquisizioni in background mentre il programma principale
esegue altri compiti. Segnali:AN0,AN1,AN2/Vref-,AN3/Vref+,AN4,AN8,AN9,AN10,AN11,AN12.
3) Interfaccia seriale sincrona/asincrona: USART (universal synchronus asynchronous receiver transmitter):
Segnali: TX/CK, RX/DT; E' detta anche SCI: serial communication interface. Può funzionare in modalità asincrona
SIMPLEX, HALF o FULL duplex, ovvero senza trasmettere il clock e con bit di start e stop, oppure sincrona, ovvero il
clock che temporizza la serializzazione e deserializzazione dei bit inviato su una linea a parte facente capo al pin CK
(RC6). A livello di programma la interfaccia è visibile attraverso 5 registri: RCREG, TXREG (SIPO e PISO di ricezione e
trasmissione), RCSTA TXSTA: registri di stato/comando di ricevitore e trasmettitore rispettivamente e
BAUDCON: registro di configurazione del baud rate (frequenza di bit = velocità di trasmissione). Attraverso questi registri
è possibile, quanto meno: impostare baud rate, numero bit dati, parità, numero bit stop, controllare se il trasmettitore è
disponibile, e se ci sono stati errori nella trasmissione o nella ricezione dell'ultimo carattere. L'evento carattere ricevuto è
riportato, nel disordine tipico microchip, nel registro PIR1, nel bit RCIF. Questi eventi (ricezione avvenuta, trasmissione
possibile, errore) possono essere gestiti ad interruzione, previa abilitazione e implementazione di adatta routine di
interrupt. E' inoltre possibile impostare la modalità sincrona o asincrona e spegnere o accendere la USART (accesa: il bit
SPEN in RCSTA deve essere 1). Nella modalità sincrona, che è solo HALF DUPLEX, i pin TX e RX diventano CK (il
clock di trasmissione) e la linea dati DT, percorsa in un senso o nell'altro. Inoltre l'unità è configurabile come MASTER,
che produce il clock, per cui CK è una uscita, o come SLAVE, per cui CK è un ingresso. In questa modalità ci può essere
UN SOLO MASTER, e TANTI SLAVE. Il MASTER interroga gli SLAVE uno alla volta inviando loro una configurazione che
essi riconoscono come loro indirizzo, e rispondono. La linea DT viene quindi commutata di direzione fra quando il
MASTER interroga e quando il MASTER ascolta. Il compilatore MCC18 ci da una grossa mano per utilizzare la USART,
almeno in modalità asincrona; ci mette infatti a disposizione tutta una serie di funzioni di libreria per la inizializzazione
(OPENUSART), la scrittura e la lettura di stringhe e caratteri ASCII STAMPABILI (printf, sprintf, puts, putc, getsUSART)
e binari (anche non stampabili) getcUSART, putcUSART e due funzioni DATARDYUSART() e BUSYUSART() per
controllare rispettivamente se nel SIPO di ricezione c'è un carattere pronto e se è possibile utilizzare il PISO di
trasmissione (per l'elenco e la descrizione completa, per tutti i PIC18, con esempi: C:\MCC18\doc\PIC18F Peripheral
Library Help Document.chm, oppure il file MPLAB_C18_Libraries_51297f.pdf).
4) Interfaccia seriale sincrona MSSP (Master Synchronous Serial Port):
segnali: SDI/SDA, SDO,
SCK/SCL,
SS.
MSSP: nome microchip per una interfaccia che congloba due interfaccie standard industriali sincrone in un solo modulo:
la SPI (serial periphereal interface), e la I2C (Inter Integrated Circuit). Queste due interfacce seriali sincrone sono molto
utilizzate per colloquiare con: orologi RTC, RAM, EEPROM, DISPLAY, SENSORI che siano dotati di interfaccia seriale
corrispondente. La SPI permette ad un solo MASTER di comunicare con un solo SLAVE e prevede l'uso di 4 fili Serial
Data Out (SDO) – RC5/SDO, Serial Data In (SDI) – RC4/SDI/SDA, Serial Clock (SCK) – RC3/SCK/SCL, Slave Select (SS) – RA5/SS.
SS serve per impostare una unità come MASTER (SS = 1) o come SLAVE (SS = 0). La unità MASTER produce il clock SCK e quindi
RC3 è una uscita; una unita SLAVE lo riceve è quindi RC3 è ingresso. L'unità MASTER prende l'iniziativa nel colloquio, trasmettendo
per prima. La unità SLAVE risponde.
La SPI è governata principalmente dai registri: SSPBUF: registro dati, in esso
scriviamo/leggiamo il dato a 8 bit da trasmettere/ricevuto; SSPCON1: registro stato/controllo; SSPSTAT: registro di stato; con essi
selezioniamo la modalità di funzionamento che ci interessa fra le diverse disponibili e controlliamo se è stato ricevuto un carattere o se
è possibile trasmettere un nuovo carattere. La particolarità di questa interfaccia è che sostanzialmente si tratta di un PISO/SIPO (nel
master) collegato in loop con un SIPO/PISO (nello slave). Pertanto un invio con il PISO del master provoca la trasmissione bit per bit di
ciò che è contenuto nel PISO dello SLAVE che rientra dal SIPO del MASTER e così via. Lo slave quindi non può inviare
autonomamente al master, ma ha bisogno che questi "pompi" qualcosa nell'anello, per fare uscire dal suo PISO ed entrare nel SIPO
del MASTER la risposta eventualmente già preparata nel suo PISO. Anche questa periferica prevede funzionamento ad interrupt per
ricevitore pieno e trasmettitore disponibile.
I2C anche detta TWI (two wire interface): E' una interfaccia seriale sincrona molto complicata della quale daremo solo un cenno.
Essa provvede funzionalità di tipo MULTIMASTER-MULTISLAVE, ovvero ci sono tante unità slave che ricevono, ma ci può essere
anche più di una unità MASTER che trasmette. Pertanto ci deve essere un meccanismo di indirizzamento delle varie unità che le
contraddistingua e un meccanismo di gestione della contesa della linea del clock fra le varie unità che vogliono essere master. La I2C
utilizza solo 2 collegamenti che qui fanno capo a RC3/SCK/SCL-Serial clock (SCL) e RC4/SDI/SDA-Serial data (SDA),
bidirezionale. Esternamente l'interfaccia appare addiritura più semplice, ci sono solo 2 fili; in realtà, dovendo appunto trasmettere in
due direzioni sullo stesso filo (esercizio half duplex), dovendo trasmettere non solo dati ma anche indirizzi e dovendo risolvere la
contesa per le linee sia l'HW che il SW sono molto più complicati. Volendo utilizzare senza troppi problemi tale interfaccia possiamo
comunque utilizzare la libreria del compilatore.
5) EEPROM:
nessun segnale esterno.
Memoria non volatile. A seconda del modello la capacità varia da un minimo di 256 a un massimo di 1024 byte. E'
accessibile mediante un registro dati EEDATA nel quale scriviamo o leggiamo il dato da scrivere o leggere dall'array di
celle, un registro indirizzo EEADDR, nel quale scriviamo l'indirizzo della cella sulla quale vogliamo operare, un registro di
stato/comando (EECON1 EECON2) nel quale con appositi bit indichiamo se l'operazione è di lettura o scrittura e
controlliamo se l'operazione stessa è finita, in quanto il tempo di accesso al dispositivo è parecchio più elevato di quello di
una RAM convenzionale, e addirittura in scrittura si aggira su diversi ms. Per tal motivo la EEPROM può essere gestita a
polling, controllando il bit suddetto, ma anche a interruzione: si avvia la scrittura e mentre questa prosegue si esegue un
altro compito, quando la scrittura arriva a compimento viene scatenata una interruzione che ha lo scopo di gestire la fine
della scrittura, ad esempio avviando una altra scrittura. Una serie di 100 scritture può essere in tal modo eseguita in
background, con 100 minime interruzioni di qualche us (es 20us, il tempo di esecuzione della routine di interruzione) ogni
10 ms, impegando in tal modo 2ms invece 100*10ms = 1s !! Il compilatore ci fornisce 3 comode funzioni per lavorare
a polling con la EEPROM: Write_ee_b(i, b): scrive un byte b all'indirizzo i; Read_ee_b(i): restituisce il byte letto
all'indirizzo i; Busy_ee(); aspetta in loop che la scrittura o la lettura sia terminata. Si segnala
infine che la
EEPROM è protetta contro le scritture accidentali, che possono ad esempio accadere se il sw utente "impazzisce" o se
l'alimentazione è ballerina (si dice BROWN OUT = "smarronamento"); ciò fa "impazzire" il sw utente che inizia a scrivere
a caso in celle a caso; la protezione consiste nella necessità di dover compiere, prima della scrittura vera e propria una
sequenza di operazioni che è molto improbabile che accadano in sequenza per caso.
6) TIMER (temporizzatori).
Segnali: TMR0: T0CKI, TMR1: T13CKI, TMR2:no segnali esterni, TMR3: T13CKI
Sono presenti 4 timer a 8/16 bit: TMR0,1,2,3. I timer servono a contare eventi: o fronti del clock interno della macchina
opportunamente ridotto di frequenza mediante un apposito prescaler oppure transizioni di un pin denominato ad esempio
TCK0I per il timer 0 e TCK13I per i timer 1 e 3 insieme, mentre TMR2 è sprovvisto di possibilità di clock esterno. TMR1
può funzionare con un suo oscillatore al quarzo dedicato, a bassa frequenza (tipicamente 32768 Hz), per implementare
ad esempio un orologio. I timer servono essenzialmente per: misurare tempi, generare ritardi quando contano i fronti del
clock interno e per contare eventi quando contano le transizioni di un pin esterno (si pensi ad un contamonete nel quale
ogni moneta cadendo chiude un contatto e produce un impulso elettrico...). I timer hanno la possibilità di generare una
interruzione detta TOF = timer overflow) a fine conteggio. I timer possono funzionare in modo modulo, ovvero quando
arrivano a fine conteggio ripartono da 0, o in modo single-shot (sparo singolo), ovvero a fine conteggio si fermano e
vanno ricaricati e fatti ripartire (riarmati). Il loro modo di funzionamento, così come il prescaler, è impostabile in un registro
di configurazione, che ad esempio per TMR0 si chiama T0CON. Ogni timer possiede oltre al registro di configurazione un
registro di conteggio (il contatore vero e proprio) che per TMR0 si chiama TMR0x (x = H o L). Esso può eventualmente
essere precaricato con il valore di conteggio massimo - il numero di impulsi da contare per arrivare a fine conteggio; ad
esempio se voglio contare 1000 impulsi con TMR0 nella modalita a 16 bit (65535 max) lo precaricherò con 64535 =
65535-1000; in tal modo dopo 1000 impulsi mi segnalerà un TOF = overflow, che potrò gestire a polling o a interrupt. I
timer hanno dei bit di abilitazione a generare interruzione e dei corrispondenti flag di interruzione; possiamo trovare questi
bit denominati con suffisso Tx (x = 0,1,2,3) e desinenza IE per le abilitazioni e IF per i flag, sparpagliati, ahimè, nei vari
registri INTCON, PIE (abilitazioni interruzioni da periferiche) e PIR (richieste interruzione da periferiche). I timer possono
anche influenzare lo stato di un pin esterno detto ad esempio CCP1 per il timer 1 e 3. Questa funzionalità è però utlizzata
quando il timer è utilizzato insieme al blocco CCP del quale fa sostanzialmente parte (altre ditte produttrici chiamano
"timer" l'insieme dei 2 blocchi timer + CCP). TMR0: 8 o 16 bit, clock interno o esterno, prescaler; TMR1: usabile
come sorgente di clock a bassa frequenza/basso consumo, clock esterno o interno; sorgente per modulo CCP1.
TIMER2: solo clock interno, utilizzabile come clock per il modulo MSSP; funzione interrupt on compare match
dedicata. TIMER3: simile a TIMER1.
7) MODULI CCP 1 e 2: (CCP=input CAPTURE output COMPARE PWM). Segnali: RC2/CCP1 RB3/CCP2, RC1/CCP2
Sono moduli che funzionano in abbinamento con i timer 1,2 o 3.
Registri importanti: CCPxCON: configurazione; CCPR: cattura/confronto o duty cycle (pwm), PR: periodo (pwm).
Pin ingresso/uscita dei moduli: CCP1 e CCP2; CCP2 è associato per default ad RC1, ma può essere spostato su
RB3 azzerando il bit di configurazione CCP2MX in sede di programmazione con una direttiva #pragma o con settings MPLAB.
La modalità capture, compare e PWM e altre particolarità si impostano con i registri di controllo CCPxCON
input CAPTURE: il valore del timer (1,2,o 3), che conta fronti di clock interno o transizioni esterne in base alla
impostazione del registro di controllo del timer stesso, viene congelato in risposta ad una transizione LH o HL
(selezionabile) su un apposito pin esterno (per TMR1 è il pin denominato CCP1). Il valore congelato è disponibile nel
registro di cattura CCPR1 (CCPR2). La avvenuta cattura viene segnalata impostando una apposito bit in un registro PIR
e può essere configurata per generare una interruzione abilitandola nell'apposito registro PIE. CCP1 e CCP2 funzionano
in tale modalità abbinati a timer1 o a timer3. E' possibile selezionare se la cattura avviene con il fronte di salita o con il
fronte in discesa di CCP1(2).
La funzionalità input capture è utilizzabile ad esempio per misurare la durata di impulsi: ad esempio collego il
segnale impulsivo del quale voglio misurare la durata a RB0 (INT0) e a RC2 (CCP1); con l'interrupt da pin esterno INT0
(RB0) su fronte di salita azzero e faccio partire TMR1 che poi congelo con la cattura avviata con il fronte in discesa su
CCP1 (RC2). Il valore che trovo nel registro CCPR1 (il registro di cattura), moltiplicato per la durata di un ciclo di clock e
diviso per il prescaler adoperato rappresenta la durata dell'impulso. La funzionalità può essere utilizzata in diversi altri
modi per misurare durate e frequenze (quindi ad esempio velocità).
output COMPARE: quando il valore corrente del timer (1,2,3) diventa uguale ad un valore impostato nel registro CCPR1
(o CCPR2), cosa che in gergo viene indicata come COMPARE MATCH, viene impostato, resettato, commutato (a scelta)
lo stato del pin di uscita CCP1 (2). Inoltre può essere avviata una operazione su una periferica (ad esempio una
conversione AD). Infine viene impostato a 1 un apposito bit dentro il registro PIR e, posto che il corrispondente bit dentro
PIE sia 1, viene generata una interruzione per la cpu. Si può avere interrupt sia sul compare match che sul fine
conteggio. E' quindi possibile utilizzare due routine di servizio una sul compare match e una sull'overflow che
rispettivamente alzano e abbassano un bit di una porta, ottenendo cosi su tale bit una modulazione PWM della quale
(65535 - il valore caricato nel registro del timer cioè il periodo voluto, in n° di clock) * il periodo del clock e diviso il
prescaler rappresenta il periodo mentre il valore caricato nel registro CCPRx rappresenta il duty cycle. La routine di
interruzione di overflow dovrà anche ricaricare il timer con (65535-periodo voluto in clock ). Tuttavia la sola funzionalità
PWM può essere ottenuta molto più facilmente e pulitamente utilizzando l'apposito modo PWM descritto di seguito.
PWM: Tale modalità è utilizzabile solo con TMR2, abbinandolo a CCP1 e/o CCP2. In tale modalità è possibile
ottenere dai pin CCP1 e/o CCP2 una onda rettangolare modulata in durata con periodo impostabile scrivendo il valore del
periodo nella forma di numero di cicli di clock contati da TMR2, eventualmente prescalati, nel registro PR (period) e il
valore di duty cycle (in forma di n° cicli di clock prescalato) nel registro CCPRx. Occorre ricordarsi di rendere il bit CCP1
(2) una uscita mediante l'adeguato TRIS. Il timer2 sottostante può comunque generare interrupt di fine conteggio. Questa
funzionalità può essere utilizzata ad esempio per implementare un convertitore DA, collegando in uscita al pin CCP1 (2)
un adeguato filtro passa basso che estragga il valore medio scartando le componenti a frequenza maggiore o uguale a
quella dell'onda PWM (1/periodo fisso impostato con PR). Ancora possiamo utilizzare la modalità PWM per controllare la
potenza di un attuatore, la luminosita di una lampadina o la velocità di un motore CC, previa interposizione di
amplificatore ON/OFF.
8) 2 Comparatori:
Segnali: RA0/AN0 RA1/AN1,
RA2/AN2/VREF-/CVREF,
RA3/AN3/VREF+, RA5/AN4/SS/HLVDIN/C2OUT sono
presenti due comparatori analogici C1 e C2 facenti capo ai pin RA0 e RA3 e RA4 per quanto riguarda gli ingressi di e
l'uscita di C1 e ai pin RA1 e RA2 e RA5 relativamente agli ingressi e l'uscita di C2. Ingressi e uscite sono variamente
configurabili mediante 3 bit nel registro CMCON. Le uscite dei due comparatori influenzano due appositi bit nel registro di
stato controllo CMCON e le loro transizioni possono avviare operazioni su altre periferiche, ad esempio i timer e/o il
convertitore AD. Le transizioni delle uscite dei comparatori possono inoltre scatenare interruzioni (mascherabili) alla CPU.
I comparatori possono servire ad una molteplicità di scopi, ad esempio trasmettere un segnale di allarme mediante la
seriale se un livello di tensione supera una certa soglia, oppure salvare lo stato di alcune variabili critiche se la tensione
di alimentazione scende al di sotto di una certa soglia, o anche implementare un convertitore AD a rampa esponenziale o
lineare. AI comparatori può essere inviata, su uno dei due ingressi una tensione di riferimento programmabile,
eventualmente resa disponibile all'esterno sul segnale CVREF. La tensione è programmabile con il registro CVRCON.
Riferimenti:
pic18f2420.pdf : manuale del microcontrollore specifico
MPLAB-C18-Users-Guide_51288j.pdf : guida d'uso del compilatore MCC18
PIC18_config_settings.pdf : fusibili di configurazione (#pragma config)
microchip mcu tips amd tricks.pdf : trucchi di utilizzo
C:\MCC18\doc\PIC18F Peripheral Library Help Document.chm : documentazione librerie con esempi
MPLAB_C18_Libraries_51297f.pdf : documentazione librerie con esempi
Scarica

Introduzione all`uso del periferiche principali del microcontrollore