Tutorials - PIC - Corso A&C

 

Esercitazioni PIC - Assembly


Conclusioni

Una domanda comune è:  C o Assembler? 

Uno dei principali vantaggi di utilizzare un linguaggio di alto livello (come C, Pascal o BASIC) è che il programmatore non deve comprendere l'architettura dell' hardware usato, dato che il compilatore provvede a fornire la giusta interfaccia alle funzioni del linguaggio attraverso librerie. Così, ad esempio, nell' uso di memoria RAM in un microcontroller, questa può essere general purpose o condivisa, in banchi di varia dimensione e gestibili in modo diverso a seconda dell' hardware; chi scrive un programma di alto livello sa poco o nulla di questa gestione della memoria: questo compito è stato delegato a chi ha scritto il compilatore. Altrettanto nell' uso di periferiche come UART o I2C.

Assembly è una programmazione a basso livello; questo vuol dire che il linguaggio non mette a disposizione altro che il set di istruzioni del microcontroller. Un microcontroller può svolgere una serie di semplici operazioni, generalmente tra 30 e 100 , ognuna delle quali agisce su un numero di bit pari alla ampiezza del bus dati. La concatenazione di queste istruzioni elementari in forme logiche adeguate (algoritmi) determina azioni complesse.
Ad esempio, se ho a disposizione un processore con dati a 8 bit, per effettuare una operazione di somma su numeri di 16 o 32 bit dovrò ripetere più volte le istruzioni elementari su 8 bit, costruendo di un algoritmo. E ogni riga assembler riguarda una e una sola istruzione.

Con un linguaggio di alto livello, come C o BASIC, ogni riga scritta può essere tradotta dal compilatore in molte o moltissime istruzioni; non c'è un rapporto diretto tra i due. La scrittura di codice in C o Basic è molto più semplice volumetricamente. In particolare, affrontando calcoli (ad es. in virgola mobile) o operazioni logiche complesse, il linguaggio ad alto livello probabilmente dispone già al suo interno delle funzioni adeguate, cosa che non esiste nell' Assembly.
Per contro, posso comunque utilizzare librerie di funzioni esterne create per l' Assembly o posso crearmene di personali a seconda delle necessità.

In teoria, poi, un programma C può essere ricompilato per funzionare su diversi microcontrollori, con un numero limitato di modifiche, mentre un sorgente Assembly, utilizzando le istruzioni proprie di un processore specifico, non può essere portato su uno diverso se non riscrivendolo completamente. In pratica, però, le differenze di hardware, anche tra elementi della stessa famiglia, possono rendere la cosa meno semplice del previsto anche per i linguaggi ad alto livello. Oltre al fatto che non esiste "un C", ma una pletora di variazioni sullo standard, a volte tali da richiedere la riscrittura di ampie parti del sorgente.
Inoltre è tipico dei microcontroller la necessità di modificare le impostazioni hardware per accedere ad IO, impostare timer o utilizzare interfacce di comunicazione seriali; questo significa manipolare i registri di controllo hardware che sono specifici di quel tale chip e di cui occorre conoscere le caratteristiche.

La programmazione con C o BASIC o altri linguaggi evoluti ha l' essenziale pregio di derivare da una filosofia propria generalizzabile, ma contemporaneamente questo è un grave difetto, dato che fa il possibile per nascondere al programmatore la struttura dell' hardware su cui lavora.
Se questa situazione è poco rilevante per chi scrive programmi gestionali o su personal computer, dove sono disponibili potenti funzioni, librerie e dll, nel caso di una situazione strettamente legata al chip ed alle sue periferiche integrate, come nel caso dei microcontroller, la mancata conoscenza delle caratteristiche specifiche di queste periferiche può essere uno scoglio ben difficilmente superabile.  
È molto più facile capire l' hardware e come si interfaccia con il resto del microcontroller se si inizia con l'imparare l' Assembly, perché questo costringe a conoscere di più sul dispositivo usato, su come funziona e su come trarne il meglio. Dopo aver scritto qualcosa in Assembly, sarà possibile affrontare un linguaggio ad alto livello in modo molto più cosciente ed efficace.

Questo elemento è particolarmente importante, dato che, in qualsiasi caso, la conoscenza delle caratteristiche specifiche di un certo microcontroller è determinante per le possibilità di utilizzarlo correttamente; conoscere alla perfezione un linguaggio evoluto, ma non sapere come poterlo applicare sullo specifico componente, è, evidentemente, inutile. Un chip potrà avere certe risorse di memoria e moduli integrati differenti da un' altro: c'è bisogno di modificare le impostazioni hardware per accedere agli I / O, impostare i timer o utilizzare interfacce di comunicazione, come ad esempio le porte seriali, e questo significa la necessità di manipolare i registri di controllo hardware, specifici di quel microcontroller, in ogni caso a livello di bit.
È molto più facile capire il meccanismo di questi registri e come si interfacciano con il resto del microcontroller se si impegna un certo tempo a considerare il linguaggio Assembly, che mette in diretto contatto col dispositivo e con il suo funzionamento, con le diverse risorse disponibili e le relative limitazioni.

Da sfatare, poi, come abbiamo accennato, la leggenda della facile portatilità del programma tra microcontroller di famiglie molto diverse tra di loro. E, ancor più, tra i vari "C" disponibili anche per le stesse famiglie di microcontroller, dove le caratteristiche della versione del linguaggio possono essere tali da necessitare la riscrittura di molte righe. 

Certamente C, con la sua offerta di operazioni matematiche, tipi, funzioni, cicli for, while, if .. else, è più semplice nell' uso di questi elementi.  In Assembly, tipicamente ogni riga del codice ha un suo valore unitario e solo in dipendenza delle possibilità dell' Assembler, più linee costituiscono un determinato blocco; le " funzioni" devono essere create a seconda delle esigenze o ottenute da librerie disponibili. Un algoritmo complesso può richiedere la concatenazione di molte linee, anche centinaia. 

Per contro, un vantaggio dell'Assembly è che il codice ottenuto può essere il minimo possibile e l' impiego di risorse (memoria) minimizzato. Meno istruzioni, esecuzione più veloce, cosa che sui piccoli microcontroller, con poche risorse disponibili, può diventare l' unica via percorribile per realizzare con essi una applicazione pratica.

In ultimo possiamo dire che comunemente si ritiene che Assembly sia più "complesso" e difficile da imparare del C o del BASIC. Questa impressione è del tutto errata.
I linguaggi evoluti richiedono un tempo di apprendimento che può essere anche molto elevato, in quanto, sono  "complessi", proprio per la particolarità di mettere a disposizione molte funzioni e possibilità logiche. Questo corrisponde ad una quantità sensibile di regole per applicare correttamente tutta questa complessità.
Per contro Assembly, in sostanza, non richiede che la conoscenza di pochissime regole formali e del set di istruzioni usato, cose che sono abbastanza semplici e si apprendono in brevissimo tempo. 

Anche la "leggibilità" maggiore del C rispetto all' Assembly o viceversa dipende solamente dalle capacità del programmatore, dato che la leggibilità intrinseca di un programma BASIC o C, disordinato o privo del supporto di adeguati commenti, è molto minore di quella di un sorgente Assembly scritto con un minimo di buon senso.
Ricordiamo che esiste una gara internazionale che premia il programma in C meno comprensibile !
Certamente un programma Assembly, richiedendo molte più righe di sorgente, se non è supportato da macro, subroutines, librerie, può essere più pesante da correggere, gestire, mantenere. Ma è sufficiente una forma di lavoro ordinata ed un efficace commento per poter scrivere codice che risulti leggibile sia ad altri programmatori come anche a sé stessi dopo qualche tempo. Per queste ragioni ha importanza la forma che deve assumere il sorgente per essere un vero "lavoro" e non un pasticcio poco sensato (cose queste, assolutamente vere per qualsiasi altro linguaggio).

Quello che realmente "spaventa" il programmatore nato nell' ambiente di linguaggi ad alto livello è costituito da due elementi:

  • la necessità di utilizzare le istruzioni del processore
  • la necessità di conoscere come funziona l' hardware

Le istruzioni non sono le funzioni del C e se non si hanno a disposizione librerie adeguate, l' impresa di scrivere da zero algoritmi complessi con gli opcodes può non essere una cosa semplice, sopratutto per il principiante.
Ed è certamente (troppo) comune che un programmatore abbia una sufficiente conoscenza del linguaggio ad alto livello, ma poca o nulla conoscenza di come farlo agire nel manipolare bit di controllo di periferiche; usando le funzioni pre programmate del linguaggio può evitare la necessità di conoscere come funziona l' UART o l' MSSP, ma se deve scrivere una qualunque applicazioni al di fuori delle possibilità di queste funzioni, si trova del tutto spaesato.

Possiamo concludere che, certamente, a causa della sua essenzialità e semplicità, il linguaggio Assembly non può che risultare più difficoltoso quando si tratta di manovrare dati complessi (matrici, floating point, ecc), in quanto NON comprende alcuna funzione pre definita, come è comune per il C, ma demanda al programmatore la responsabilità di occuparsi di ogni dettaglio della gestione dei registri, della memoria, delle operazioni complesse, oltre che dello sviluppo logico di algoritmi, componendo in modo opportuno le istruzioni elementari, il che porta a listati piuttosto lunghi rispetto a quelli equivalenti per linguaggi più evoluti.
Per questi casi la soluzione è disporre di librerie adeguate, che esistono in quanto fornite, ad esempio, dal costruttore del microcontroller. Se non disponibili, è necessario costruirsele. Con qualche tecnica adeguata si possono ridurre i disagi dell' Assembly, ad esempio, facendo uso di modularità nella programmazione, realizzando librerie, subroutines e macro istruzioni si alleggerisce in modo sensibile il lavoro di programmazione.
Per contro, Assembly sarà imbattibile in applicazioni su microcontroller con risorse limitate e quando si voglia un completo e massimamente efficiente controllo dell'hardware (tanto che i linguaggi ad alto livello prevedono la possibilità di inserire tratti di codice Assembly).

Quindi, ha senso programmare in C (o altro) quando si è di fronte a strutture di una certa estensione, con calcoli matematici o logiche complesse, ma questo non permetterà da solo di capire il modo in cui il programma agisce sulle diverse risorse disponibili o le sue limitazioni se non si impara anche il linguaggio Assembly prima. Iniziare con Assembly, comprendere il dispositivo, per poi passare a C, dove è necessario, è il nostro consiglio.


 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 18/12/14.