Front matter
Alexjan Carraturo, Andrea Trentini SISTEMI EMBEDDED: TEORIA E PRATICA Carraturo, Trentini SISTEMI EMBEDDED: TEORIA E PRATICA L’esplosione del mercato legato alla telefonia mobile, all’automazione, la domotica, ai sistemi di infotainment e guida automatica, alla progettazione di droni e stampanti 3D hanno portato alla ribalta l’interesse per le tecnologie “embedded”. Negli ultimi anni vi è stato un progressivo aumento nella domanda di competenze in questo settore, sia in ambito professionale/ industriale sia per le comunità di appassionati e principianti. Questo testo offre un percorso didattico per coloro che hanno già competenze informatiche di base e vogliono iniziare un percorso multidisciplinare di introduzione ai sistemi embedded. Si inizia con le conoscenze basilari di elettronica ed hardware per poi passare alle nozioni per muovere i primi passi dal punto di vista del software, in modo semplice, pratico e sintetico. ALEXJAN CARRATURO Laureato in informatica presso l’Università degli studi di Milano, da anni promuove attivamente il Software Libero e l’uso dei sistemi GNU Linux. Negli ultimi anni ha lavorato per aziende leader nel settore embedded/mobile/grafica tra le quali ST - Microelectronics (Cornaredo, Milano) e Imagination Technologies (Kings Langley, Hertfordshire, United Kingdom). In particolare si è prevalentemente occupato di integrazione e porting di sistemi GNU/Linux su piattaforme embedded. ANDREA TRENTINI Ph.D. in Informatica, oggi è ricercatore presso il Dipartimento di Informatica dell’Università degli Studi di Milano dove insegna “Programmazione”, “Cittadinanza Digitale e Tecnocivismo” e “Sistemi Embedded”. Da sempre a favore del Software Libero e della condivisione della conoscenza, si considera un “hacker” nel significato originale del termine. Fondatore di ArduinoAfternoon e di HackLabCormano. www.ledizioni.it www.ledipublishing.com 16 euro
Sistemi Embedded Teoria e pratica Alexjan Carraturo, Andrea Trentini Ledizioni
© 2017 Ledizioni LediPublishing Via Alamanni 11 – 20141 Milano – Italy www.ledizioni.it info@ledizioni.it Alexjan Carraturo, Andrea Trentini, Sistemi Embedded: Teoria e Pratica Prima edizione: settembre 2017 ISBN: 9788867056583 Tutti i marchi ed i loghi appartengono ai legittimi proprietari: marchi di terzi, nomi di prodotti, nomi commerciali, nomi corporativi e società citati possono essere marchi di proprietà dei rispettivi titolari o marchi registrati di altre società e sono stati utilizzati a puro scopo esplicativo. La stesura del testo, l’impaginazione e la realizzazione delle immagini è stata eseguita sfruttando programmi rilasciati con licenze libere. Per tutto il resto consultare le note di licenza. Questo testo è rilasciato in versione digitale con licenza Creative Commons ‘Attribuzione - Non Commerciale - Condividi allo stesso modo’, versione 3.0, Italiano. Per maggiori dettagli sulla licenza consultare il sito https: // creativecommons.org/ licenses/ by-nc-sa/ 3. 0/ it/ legalcode Informazioni sul catalogo e sulle ristampe: www.ledizioni.it Le riproduzioni a uso differente da quello personale potranno avvenire, per un numero di pagine non superiore al 15% del presente volume, solo a seguito di specifica autorizzazione rilasciata da Ledizioni, Via Alamanni 11 – 20141 Milano.
CAPITOLO 1. INTRODUZIONE 1.3 Sistemi “monoprogrammati” e “multiprogrammati”
La distinzione tra sistemi cosiddetti “monoprogrammati” e “multiprogrammati” ha senso ormai solo in due casi: nella trattazione della storia dell’Informatica e nel contesto embedded. Intuitivamente, e forse anche ovviamente, i due termini si riferiscono ad ambienti operativi che supportano l’esecuzione “contemporanea”12 di un solo programma o di più programmi. I sistemi monoprogrammati rappresentano la realizzazione “naturale” di un computer. Storicamente, infatti, le prime istanze di calcolatori erano in grado di eseguire un solo programma (e una sola istruzione) alla volta. I più avanzati potevano eventualmente essere riprogrammati, cosa che normalmente prevedeva lo “spegnimento”13, la nuova programmazione 14 e la ripresa/riavvio del programma.
Una architettura semplice che si può immaginare per un computer è una più o meno elaborata Macchina di Turing[15] (in breve “MdT”, un esempio è rappresentato in figura 1.1) in cui la macchina a stati è la CPU, il nastro è la memoria, l’alfabeto dei simboli sul nastro è rappresentato da numeri binari (di dimensione arbitraria, es. 8/16/32 bit) e i movimenti sul nastro sono di lunghezza arbitraria compatibilmente con la lunghezza finita del nastro/dimensione della memoria. In particolare, sia la cosiddetta architettura di Von Neumann[13] (un personal computer odierno) che la Harvard (la board Arduino) prevedono la possibilità di rappresentare la definizione della macchina a stati sotto forma di numeri binari scritti su un nastro in modo che all’“accensione” la MdT possa “caricare” (boot ) dal nastro di la- 12La contemporaneità (più o meno reale), il time-sharing, ecc. sono concetti che possono essere approfonditi dal lettore interessato anche ai temi tipici dei corsi di Sistemi Operativi[47]. Al nostro lettore basti il significato intuitivo. 13Non necessariamente elettrico, si trattava di sospensione della normale esecuzione 14Ad es. mediante sostituzione dei nastri o delle schede perforate o mediante riscrittura (anche a mano, mediante interruttori!) della memoria
... a d b a a c a a ... nastro I/O S0S1 S2 S3 . . .
Sn automa a stati r/w testina di lettura/scrittura (si muove in ambo le direzioni) Figura 1.1: Macchina di Turing voro (eventualmente su un “nastro interno”) la definizione del proprio comportamento e poi implementare tale comportamento. In tale configurazione una MdT esegue in continuazione il seguente loop: • legge il simbolo sotto al cursore (fetch ) • interpreta il simbolo secondo la macchina a stati caricata (execute) • sposta il cursore (aggiornamento program counter) Per cambiare comportamento (programma) bisogna sospendere il loop, riscrivere la parte di nastro contenente il programma e riavviare la MdT. È anche immaginabile il caso in cui il programma possa modificare se stesso (l’esempio canonico è il linguaggio LISP[44]), ma il principio di funzionamento non cambia. La definizione di “monoprogrammato” deriva proprio da questa limitazione, un sistema monoprogrammato è quello su cui è possibile eseguire un solo programma per volta. Ovviamente il programma può essere complesso ad libitum e prevedere molti “subcomportamenti” (funzioni/ subroutine) che vengono attivati su condizione, ad es., simboli particolari incontrati sul nastro della
CAPITOLO 1. INTRODUZIONE MdT, ma le istruzioni (letture di un simbolo dal nastro di lavoro) v engono eseguite una ad una, senza nessun tipo di parallelismo. Ergo se è stata attivata una certa subroutine il resto del programma è disattivato finché tale subroutine non “esce”, i.e., restituisce il controllo alla routine cosiddetta “principale” . 1.4 Modo di pensare Il titolo è altisonante, vero, ma il contesto embedded, rispetto ai sistemi cui oggi i programmatori “normali” sono abituati, è molto particolare e spesso obbliga a pensare diversamente per quanto riguarda lo sviluppo software (ma non solo). Le “risorse” (CPU, RAM, dischi, potenza elettrica, ecc.) di un sistema embedded sono sovente estremamente limitate, ergo lo sviluppatore deve entrare in una modalità di progettazione/- programmazione molto attenta a non “sforare” . Cominciamo con l’aspetto che ogni sviluppatore ha maggiormente a cuore: l’ambiente di runtime e quindi il contesto della progettazione e programmazione del software. Lo sviluppo di un programma, sia esso scritto in un linguaggio imperativo tradizionale o in un più moderno a oggetti (o altri paradigmi anche esoterici), comporta comunque il trattamento di dati che prima o poi dovranno transitare dalla memoria che è di gran lunga inferiore a quella a cui potremmo essere abituati. In molti casi, Arduino su tutti (si veda sezione 3.7.2), parliamo di pochi kilobyte di RAM. Ergo nella progettazione di un programma lo sviluppatore dovrà ragionare molto bene e a priori sul numero e sul tipo delle variabili dichiarate nel corso del programma stesso.
Ecco il motivo per cui prima ancora di cominciare a scrivere codice è bene studiare i tipi di dato (esempio in 7.4.1) disponibili nel linguaggio di programmazione scelto (o, a volte, imposto) per la piattaforma in uso. Utilizzare un int - tipicamente 2 byte - al posto di un long - tipicamente 4 byte - ove possibile (cioè se non si devono rappresentare numeri “grandi”) fa risparmiare, ovviamente, 2 byte. Altra attenzione importante da mettere in atto è che molte “librerie” 15 p er funzionare utilizzano memoria e, a meno di non andare a leggerne il codice sorgente, non è dato sapere quali e quante variabili dichiarano, purtroppo è raro che venga esplicitato il consumo di memoria nella documentazione. Rimanendo sul tema memoria, oltre alle variabili esistono sono altri modi di consumarla: invocando funzioni . Ogni invocazione di funzione “costa” memoria: per chiamare una funzione l’ambiente di runtime deve salvare il contesto di provenienza 16 nello “stack ” (area di memoria, contrapposta di solito allo “ heap”, dove vengono memorizzati dati di passaggio, appunto). A ciascuna invocazione corrisponde una crescita dello stack che verrà poi parzialmente svuotato al ritorno dalla funzione. Naturalmente questa situazione non deve spingerci a tornare al GOTO17. Semplicemente sarà sufficiente fare attenzione alla struttura di insieme del programma in modo da evitare per quanto possibile invocazioni multiple che rischierebbero uno “sfondamento” dello stack (il famoso errore “StackOverflow” che dà origine al nome di un notissimo sito 18).
Infine, per concludere l’argomento “invocazione funzioni”, diventa ora palese il motivo per cui si dovrebbe evitare l’uso della ricorsione in un contesto a bassa disponibilità di memoria. Anche riuscendo a scrivere correttamente una funzione ricorsiva complessa (cioè avendo una condizione di uscita sempre verificata) il costo di esecuzione è enorme in termini di memoria. Lo stack 15Insiemi di funzioni predefinite disponibili in molti ambienti per scopi usuali come accedere alla rete, leggere una SD card, ecc. 16Al minimo va memorizzato il PC (Program Counter, indirizzo di memoria della prossima istruzione da eseguire, è un registro della CPU) per sapere dove si trovava l’esecuzione prima di attivare la funzione, quindi 2, 4 o più byte a seconda dell’architettura del sistema. Nella peggiore delle ipotesi va salvato il PC, altri registri della CPU e i parametri passati alla funzione: tanti byte quanti sono i tipi degli argomenti della funzione stessa. Ad esempio, invocare una funzione somma(int a, long b, double c) ipotizzando 2 byte per int e 4 byte cadauno per long e double costa 10 byte solo di parametri passati. 17Si veda la famosa lettera di Dijkstra[12] e si divaghi poi, se il lettore vorrà anche divertirsi un po’, sulla pletora di articoli “Considered harmful” culminata in un meta-articolo di Meyer ( http://meyerweb.com/eric/ comment/chech.html 18http://stackoverflow.com/
CAPITOLO 1. INTRODUZIONE cresce monotonicamente fino al raggiungimento della condizione d i termine per poi svuotarsi rapidamente. Se il procedimento ricorsivo genera un numero di iterazioni elevato lo stack viene “sfondato” con elevata probabilità.
E non dobbiamo dimenticarci della “ memoria di programma” cioè dello spazio impegnato dal codice compilato: il “codice binario” che viene caricato sulla board occupa spazio (che può andare a scapito della “memoria di lavoro” in funzione della architettura interna della memoria, se condivisa o meno) in RAM e tale spazio, sovente limitato, deve essere gestito in maniera “centellinata” . Mai come nel contesto embedded bisogna interpretare attentamente le informazioni emesse del compilatore sul binario generato: dimensione del file “oggetto” (object file ), totale dei byte occupati dalle variabili statiche, ecc. Un fattore importante che influisce sulla dimensione finale del compilato è la “bravura” del compilatore nell’ottimizzare il codice e nella sua capacità di “linkare”19 dinamicamente solo le parti di codice (ad esempio le librerie incluse nel sorgente principale) effettivamente utilizzate. Rispetto ai sistemi desktop/server, molti sistemi embedded espongono architetture estremamente semplici, ed è abbastanza raro avere a disposizione una MMU (Memory Management Unit). Senza MMU non si ha nessuna protezione della memoria e non è possibile gestire memoria virtuale o indirizzamenti “esoterici”, rilocazioni, ecc. Ergo, a meno di circonvoluzioni software (che comunque rallenterebbero fin troppo l’esecuzione e quindi raramente vengono messe in atto) per inserire controlli di coerenza nell’accesso alla memoria, tutti gli accessi alla memoria non sono controllati se non dal programmatore stesso, ad esempio: • accesso ad un array: sforare l’indice vuol dire andare a leggere/scrivere in zone di memoria non previste con effetti potenzialmente catastrofici (si “sporca” la memoria dedicata ad altre variabili); 19La traduzione letterale sarebbe “collegare”, ma non si usa nella terminologia corrente italiana. Il linking è il processo per cui il compilatore realizza il “collage” dei pezzi di codice compilato dai vari file sorgente creando l’eseguibile finale.
• s foramento stack/heap: riempire lo stack oltre il suo limite (andando quindi a “coprire” parte dello heap) non scatena nessun “avviso”, anche in questo caso gli effetti sono potenzialmente catastrofici (idem).
I processori, salvo nei sistemi di fascia alta, sono molto semplici e non forniscono istruzioni dedicate alla gestione del multitasking/multithreading. Ciò che viene supportata normalmente è la funzionalità di trattamento degli interrupt (cfr. la sezione 7.4.14 e il Capitolo 4 di [51]) per cui è ad esempio possibile creare un programma che non sia obbligato a fare polling sulle porte di I/O. È possibile semplicemente “agganciare” una funzione all’arrivo di un segnale su una determinata porta, tale funzione verrà eseguita, interrompendo (da cui il nome interrupt) temporaneamente l’esecuzione normale del programma, alla ricezione del segnale. Non avendo disponibilità di funzioni per il multithreading vero e proprio (cioè con capacità di interrompere un flusso, salvarne lo stato, attivare un altro flusso, interromperlo e riprendere il precedente dallo stato in cui era stato lasciato) si ricorre spesso al cosiddetto “multitasking cooperativo ” . Il multitasking cooperativo è principalmente un modo di organizzare il proprio codice per permettere l’esecuzione di più flussi (in simulazione di contemporaneità) usando un singolo thread di esecuzione. Il meccanismo ruota attorno ad un main che esegue un loop il cui unico scopo è quello di invocare altre funzioni (“ task”) a istanti predefiniti nel tempo (es. ai secondi 5, 10, ecc. di ogni minuto chiama la “f1”, ai 6, 11, ecc. la “f2” e via così). Ogni funzione-task deve essere breve (perché altrimenti mantiene il controllo per troppo tempo e fa sforare l’invocazione temporizzata delle altre) e deve, ove opportuno, saper gestire uno “stato” memorizzato in alcune variabili per poter lavorare “iterativamente” 20. Ovviamente questo approccio complica la struttura del codice e non è esente da errori. 20Si immagini di dover elaborare i dati di un array e che l’elaborazione di un dato sia “costosa” dal punto di vista del tempo di elaborazione. La funzione che deve gestire l’elaborazione dovrà trattare un sottoinsieme degli elementi dell’array (invece che tutta la struttura) ad ogni invocazione, salvando in una variabile “globale” il punto a cui era giunta (es. l’indice dell’array) per poi riprendere da lì alla successiva invocazione da parte del main loop .
CAPITOLO 1. INTRODUZIONE Gli argomenti trattati in questa introduzione possono essere ap profonditi in [33] e [45]. 1.5 Struttura del testo Questo testo è organizzato secondo la seguente struttura: • Capitolo 2, “elettronica”: fornisce le conoscenze minime per capire l’interfacciamento elettrico tra un sistema embedded e il mondo fisico; • Capitolo 3, “architetture”: panoramica delle piattaforme embedded più diffuse; • Capitolo 4, “I/O e memorie”: panoramica sulle tecnologie e i protocolli per la comunicazione e lo storage; • Capitolo 5, “sistema operativo”: approfondimento sui sistemi embedded di fascia “alta”, quelli dotati di sistema operativo, con particolare riferimento a GNU/Linux; • Capitolo 6, “build di un sistema”: preparazione di un sistema operativo (basato su GNU/Linux) da installare su una piattaforma embedded; • Capitolo 7, “Arduino”: approfondimento su una piattaforma embedded di fascia “bassa”, senza sistema operativo, scelta la più diffusa attualmente; • Capitolo 8, “Ambiente di test”: preparazione di un ambiente di sviluppo/testing basato sull’interazione fra board e workstation.
Capitolo 2 Ric hiami di elettronica Il presente capitolo è dedicato al riassunto di alcuni basilari concetti di elettricità, elettronica e fisica, il minimo indispensabile per poter collegare una piattaforma embedded (es. un Arduino o un RaspberryPI con i suoi GPIO - General Purpose I/O) al mondo fisico mediante qualche sensore e/o attuatore senza distruggere nulla né farsi del male 1.
Per approfondimenti consigliamo un testo atipico nel formato di impaginazione, ma completo e ben spiegato, il famoso Mims[32]. Volendo approfondire ulteriormente senza per forza arrivare ad un testo universitario sull’elettronica si può affrontare tranquillamente il Neri[35], il testo per l’esame da radioamatore, in cui si trovano anche alcuni esercizi sulle leggi di Ohm. 2.1 Richiami sui principi 2.1.1 Elettricità Elettricità (ed elettrone) è un termine che deriva dal greco “electron” (ambra, materiale noto per la facilità con cui permette di produrre carica elettrostatica per sfregamento): raggruppa 1Gli informatici puri non toccano mai un saldatore né si trovano mai ad affrontare alte tensioni a mani nude l’insieme dei fenomeni fisici che coinvolgono il trattamento e lo s postamento di cariche elettriche e degli effetti ad essi collegati (calore, magnetismo, ecc.).
Ai fini di questo testo ci interesserà principalmente la gestione dei segnali elettrici, cioè di quelle grandezze di tensione e corrente che interessano i conduttori (o i semiconduttori) e a cui possiamo associare un’informazione. Non verrà trattata l’elettrostatica se non limitatamente alla descrizione di un condensatore. Il termine “corrente” richiama il concetto di movimento, infatti si ha passaggio di corrente quando degli elettroni (le particelle subatomiche caricate negativamente che “orbitano” intorno ai nuclei degli atomi) liberi si muovono lungo un conduttore trainati da una differenza di potenziale elettrico. Tali elettroni possono essere usati per effettuare un lavoro, generare calore, scatenare reazioni chimiche, trasportare informazione, ecc. Il potenziale elettrico è una forza di attrazione (creabile mediante pile/batterie, dinamo, condensatori, ecc.) che cerca di spostare degli elettroni da un punto all’altro (poli) di un circuito. Maggiore il potenziale, maggiore la forza (“elettromotrice”) e quindi maggiore la quantità di elettroni che si possono spostare nell’unità di tempo. La velocità con cui si spostano gli elettroni dipende dal materiale che li trasporta: nel rame viaggiano a circa 2/3 della velocità della luce. Il flusso effettivo dipende dalle condizioni del conduttore che normalmente presenta una certa “resistenza naturale” (non nulla) al passaggio della corrente. Il potenziale prende il nome tecnico di “tensione” e si misura in Volt (simbolo V) mentre la quantità di corrente che scorre nell’unità di tempo si chiama “intensità” e si misura in Ampere (simbolo A). L’Ampere corrisponde alla quantità di carica (Coulomb, un “tot” di elettroni, per la precisione ∼ 6.24 · 1018) trasportata in un secondo. Quindi, in un conduttore, a tensione più elevata corrisponde maggiore intensità di corrente. 2.1.2 Legge di Ohm In particolare fu Georg Ohm a studiare la relazione fra tensione e (intensità di) corrente, la c.d. “Legge di Ohm”[1] infatti lega
CAPITOLO 2. RICHIAMI DI ELETTRONICA queste due grandezze alla resistenza, così: I = VR (2.1) Cio è l’intensità di corrente in un conduttore è direttamente proporzionale alla tensione e inversamente proporzionale alla resistenza del conduttore (che trasporta gli elettroni). L’unità di misura della resistenza, che prende il nome dallo scienziato, è per l’appunto l’Ohm (simbolo Ω).
La resistenza “naturale” (chiamata resistività, simbolo ρ) di un conduttore è dovuta al tipo di materiale usato. La resistenza di un circuito può essere modificata (maggiorandola) mediante l’inserzione di un componente elettronico chiamato, appunto, “resistore” (cfr. Sezione 2.3.4). Ciò può servire ad esempio a limitare la corrente, a parità di tensione, ove non servano valori elevati, anche perché il calore dissipato da un circuito è proporzionale al quadrato della corrente che vi scorre, secondo la: P (otenza) = R · I 2 (2.2) Naturalmente l’equazione 2.1 può essere esplicitata in tutte le sue forme, cioè: R = V /I e V = R · I a seconda di quale sia l’incognita e quali i dati noti.
E combinando la formula 2.1 con la 2.2 si può esprimere la potenza in funzione della tensione e resistenza invece che della corrente e resistenza o in funzione di tensione e corrente: P (otenza) = R · I 2 = R · ( V R )2 = V 2 R = V · I (2.3) 2.1.3 Continua e alternata La corrente esiste in due forme: continua e alternata. La differenza consta nel comportamento degli elettroni che fluiscono nei conduttori, nel caso della corrente continua essi si muovono sempre nella stessa direzione, nella alternata cambiano verso, vanno cioè avanti e indietro secondo un periodo che prende il nome di “frequenza” che si misura in Hertz (ad esempio i 50 Hz della corrente a 220 V di rete italiana). In molti schemi si trovan o simboli specifici che indicano i valori di tensione esplicitando se “continua” (e.g., 12 Vcc , 12 V=) o “alternata” (e.g., 220 Vac, 220 V ˜-).
Le differenze fra i due tipi di corrente sono notevoli. Ad esempio nella produzione: • la corrente alternata viene prodotta meccanicamente (o elettronicamente negli “inverter”2 moderni) muovendo/facendo ruotare un insieme di conduttori all’interno di un campo magnetico creando quindi per induzione elettromagnetica , appunto, una corrente nei conduttori stessi; • la corrente continua invece viene prodotta chimicamente (pile/batterie, cfr. sezione 2.3.6), per accumulo elettrostatico e anche meccanicamente tramite dinamo (per la precisione in quest’ultimo caso si tratta di corrente c.d. “pulsante”).
L’aspetto dell’immagazzinamento è fondamentale e dipende essenzialmente dalle tecniche di produzione citate. Infatti la corrente continua è immagazzinabile, negli “accumulatori” (chimici: batterie a base di materiali disparati come piombo, litio, nickel, ecc.) o nei “condensatori” (elettrostatici, cfr. sezione 2.3.5), mentre quella alternata non è direttamente accumulabile a meno di non trasformare l’energia elettrica associata in altri tipi di energia (e.g., potenziale nei bacini idroelettrici). Altro fattore importante è la trasformabilità (e quindi indirettamente la trasmissibilità): la corrente continua non è trasformabile facilmente 3 mentre per quella alternata è sufficiente, appunto, un trasformatore (figura 2.1). Il trasformatore è un componente meccanicamente semplice: non ha parti in movimento e non contiene componenti attivi (semiconduttori), deve solo essere eventualmente raffreddato (tipicamente a olio) se deve ge- 2Apparato che trasforma una corrente in ingresso continua in una alternata in uscita, tipicamente a tensione diversa da quella di ingresso, e.g., gli inverter da auto/barca/camper che accettano 12/24 Vcc in ingresso e forniscono 220 Vac in uscita. 3Esistono convertitori continua-continua a semiconduttore, ma le dimensioni e il calore dissipato da tali apparecchi salgono molto rapidamente al crescere di tensione e soprattutto corrente gestite.
CAPITOLO 2. RICHIAMI DI ELETTRONICA stire flussi elevati di corrente. Nella sua forma base è composto d a due bobine (avvolgimenti di filo conduttore) vicine (normalmente sono avvolte sullo stesso nucleo) in modo che il campo elettromagnetico prodotto da una di esse (c.d. “avvolgimento primario”) possa influenzare l’altra (c.d. “avvolgimento secondario”) inducendo una corrente la cui tensione dipende da quella della prima bobina e dal rapporto fra i numeri di spire delle due bobine. Il trasformatore non funziona con una corrente continua (deve essere alternata o pulsante).
A1 A2 B1 B2 Figu ra 2.1: Simbolo del trasformatore La trasformabilità influisce pes antemente sulla trasmissibilità a grandi distanze della corrente elettrica. Infatti, applicando le varie forme della Legge di Ohm (vedi formula 2.1), si può intuire che per portare “potenza” (capacità di produrre lavoro) a distanza si deve trasportare tensione (forza) e corrente (intensità) dato che la potenza è il prodotto V · I. Purtroppo il calore dissipato da un conduttore è proporzionale al quadrato della intensità di corrente (R · I 2) ergo è più conveniente alzare la tensione per elevare l’energia trasportata. È per questo che le linee (elettrodotti) che distribuiscono corrente elettrica sul territorio utilizzano tensioni molto elevate (ordine di grandezza delle centinaia di migliaia di Volt), la tensione viene poi ridotta nelle stazioni di trasformazione man mano che si “avvicina” all’utente finale.
Interessante, significativa e densa di valore storico la diatriba[26] avvenuta alla fine del ’800 fra i fautori della corrente continua (in primis Thomas Alva Edison[25] con la sua società) e di quella alternata (George Westinghouse - fondatore della omonima società - e Nikola Tesla[37]) che alla fine vide vincere (per fortuna!) la seconda.
2.1.4 Segnali Figura 2.2: Codice Morse L’elettricità ha però un imp ortante funzione: quella di trasportare/trasmettere informazione a grande distanza e velocemente.
Prima dell’avvento dell’elettricità l’unico modo per trasmettere informazione a distanza era quello di trasportare atomi in giro per il mondo: ad es. un libro di carta/pergamena recava con sè informazione sotto forma dei caratteri stampati con inchiostro chimico che un lettore umano doveva interpretare per carpirne il contenuto e farlo proprio. La velocità di trasmissione era limitata dalla velocità dei mezzi di trasporto: cavalli, velieri e persone a piedi. Nella migliore delle ipotesi stiamo pensando a qualche decina di km/h.
Anche quando verso la fine del 1700 si cominciano a vedere i primi treni a vapore la situazione non cambia di molto, si guadagna giusto qualche km/h. Bisogna trovare un “carrier”, un trasportatore, più veloce. E, no, i piccioni non vanno benissimo: trasportano troppo poco carico e non sempre arrivano a destinazione[52].
Una prima idea interessante di fine XVIII secolo è il telegrafo ottico Chappe: un sistema di segnalamento basato su “pale” (gli apparati sembravano dei mulini a vento con due bracci) che trasmettevano simboli secondo un codice convenzionale variandone la configurazione, i messaggi venivano letti a grande distanza mediante cannocchiali. Il meccanismo è analogo alle segnalazioni
CAPITOLO 2. RICHIAMI DI ELETTRONICA che si vedono fare sulle portaerei dagli “omini con le bandiere” agli aerei che stanno decollando o agli elicotteri che stanno atterrando: ogni posizione della braccia corrisponde ad una semantica nota da entrambi i partecipanti alla conversazione. In questo caso la velocità di trasmissione del singolo simbolo (una configurazione delle pale) era pressoché “istantanea” (velocità della luce), ma il problema era rappresentato dalla impraticabilità del meccanismo di configurazione: spostare le pale era un’operazione relativamente lunga (qualche minuto) per cui il numero di simboli trasmessi per unità di tempo rimaneva molto bassa. E col tempo cattivo la comunicazione era interrotta.
La vera svolta si ha nel 1837 (collochiamo questa data: sono passati solo dieci anni dalla pubblicazione della legge di Ohm) quando il quarantaseienne Samuel Morse, dopo alcuni anni di esperimenti, realizza (e brevetterà, qualche anno dopo) il primo telegrafo elettrico . La novità di questa invenzione è l’uso dell’elettricità che permette: • un’ottima velocità di trasmissione del segnale, certo meno veloce della luce usata dal telegrafo Chappe, ma dato che utilizza dei cavi sospesi o interrati la mancanza di visibilità “ottica” non influenza la comunicazione; • il cavo segue i rilievi del terreno, ergo può portare il segnale anche al di là di una montagna o, come accade oggi, al di là di un oceano (curvatura terrestre); • il meccanismo di invio del segnale è semplicissimo, è solo un pulsante elettrico che chiude un circuito (il lato ricevente è un elettromagnete che scatta quando riceve l’impulso), non ci sono “pale” da muovere, si può “digitare” (proprio con un singolo dito!) il proprio messaggio (quasi) alla velocità del pensiero 4; • la distanza massima alla quale si può portare l’informazione dipende, guarda caso, dalla legge di Ohm, infatti il cavo ha una sua resistenza propria (chiamata “resistività”, ad esempio il rame: 1.68·10−8Ω/m) e usando materiale a bassa 4Oggi il Codice Morse non si utilizza più (ufficialmente) nelle comunicazioni ma quando era ancora in uso estensivo i “ recordmen del tasto” riuscivano a trasmettere centinaia di caratteri al minuto!
resistività come il rame è possibile fare cavi molto lunghi s u cui mandare segnali elettrici con voltaggi relativamente bassi, tali da poter alimentare gli apparecchi telegrafici con delle semplici batterie piombo+acido; • costruire una linea telegrafica, nella sua forma più semplice, comporta solo la stesura di un cavo, anche a terra se isolato, srotolando una bobina mentre si cammina... i primi esempi di “cablaggi” per telecomunicazioni!
L’informazione trasportata dal telegrafo elettrico era codificata mediante un segnale elettrico che faceva scattare un elettromagnete. Il ricevente doveva “ascoltare” i ticchettii dell’elettromagnete e tradurre la sequenza di impulsi nelle lettere corrispondenti (figura 2.2).
Citiamo questo meccanismo perché è interessante notare come questo codice rappresenti il primo esempio d’uso estensivo della cosiddetta PWM (Pulse Width Modulation, si veda più avanti, sezione 2.4), anche se in senso molto lato. I due simboli, “punto” e “linea”, vengono codificati per durata dell’impulso, il punto è un breve click e rilascio subitaneo, mentre la linea è un impulso più lungo, click + pausa + rilascio. Chiaramente non è possibile usare la sola presenza/assenza (acceso/spento, 1 e 0) di segnale per trasmettere informazione perché l’assenza di segnale è la condizione di riposo del sistema (silenzio) e in questo caso l’assenza dell’impulso non sarebbe interpretabile (è “silenzio” o è uno “0”?).
Ancora, intuitivamente, il Codice Morse definisce solo due (e non di più) simboli primari (punto e linea) che differiscono per durata dell’impulso perché un umano non sarebbe in grado di distinguere facilmente e senza errori durate diverse che potrebbero corrispondere a più simboli. Un circuito elettrico o un computer invece non avrebbero grossi problemi a fare misurazioni di precisione, sebbene a costo di complicazioni circuitali e di bassa protezione contro il “rumore” .
Il telegrafo elettrico è la prima applicazione pratica dell’uso della corrente elettrica per la trasmissione di segnali a lunga distanza e ad “alta” velocità. È la prima volta che vengono trasmessi “bit” (sotto forma di elettroni lungo un conduttore) invece
CAPITOLO 2. RICHIAMI DI ELETTRONICA V t Figura 2.3: Tensione continua c he atomi
Questa parentesi storica ci serve anche come scusa per introdurre il concetto di “forma d’onda”, un modo grafico di rappresentare lo stato della tensione o della corrente elettrica in un punto/ramo di un circuito nel tempo. 2.2 Forme d’onda In elettronica si parla spesso di “forme d’onda” per rappresentare segnali.
Una forma d’onda è la rappresentazione cartesiana dell’andamento della grandezza elettrica (tensione o corrente) nel tempo. Una forma d’onda ci dice in modo estremamente visuale come varia nel tempo la [tensione in un certo punto] o la [corrente in un certo ramo] di un circuito. Normalmente i segnali vengono definiti matematicamente, scrivendone la funzione che ne modella l’andamento, ma attraverso un grafico di forma d’onda si coglie al volo (a colpo d’occhio) il tipo di segnale che si sta trattando e/o il comportamento di un determinato circuito che crea o influenza i segnali in gioco.
Per cominciare con un esempio banale vediamo (in figura 2.3) l’aspetto di una corrente continua come potrebbe uscire da un alimentatore cosiddetto “stabilizzato” (la cui tensione viene mantenuta costante, appunto): il valore della V non varia nel tempo.
V t Figura 2.4: Tensione di scarica V t Vp icco −Vp icco Figura 2.5: Tensione alternata In vece la figura 2.4 esprime un’ipotetica (idealizzata! In realtà è ben lungi dall’essere lineare) situazione di “scarica” (ad esempio pile, condensatori) in cui la tensione cala nel tempo fino a raggiungere lo 0.
Per finire, la figura 2.5 esprime una tensione alternata, come potrebbe essere quella della rete domestica, in cui la tensione varia continuamente tra positivo e negativo. Nel caso di forme d’onda “periodiche” (sinusoidali, a impulsi, eccetera) regolari si esprime anche una “frequenza”, misurata in Hz (Hertz, cicli al secondo) e multipli, cioè l’informazione che ci dice il periodo tipico di variazione del segnale ciclico. Ad esempio, un segnale sinusoidale a 50 Hz (la rete elettrica domestica) è quello il cui ciclo completo (da picco a picco) si svolge 50 volte al secondo.
The opening of the book is shown; the full text loads in the reader.
Loading the full text…
The end
You’ve reached the end of Sistemi Embedded: teoria e pratica.
