Salta la barra di navigazione [1] - Vai alla barra di navigazione [3] - Scrivimi una mail [4]

PIC18 - Usare l'USB

Sommario - Novità - Tutorial - Progetti - Risorse - Non solo elettronica

Attenzione! Questa pagina contiene materiale obsoleto - Vai al tutorial relativo all'ambiente MPLAB X e XC8 Attenzione!

L'interfaccia USB ha da tempo sostituito la parallela e la seriale in tutti i PC moderni, a partire dai portatili. Questo, accanto ad innegabili vantaggi, ha creato non pochi problemi agli hobbisti che vogliono collegare i dispositivi hardware che realizzano ad un computer.

Una prima soluzione è quella di adottare soluzioni hardware specializzate (per esempio l'integrato FT2232H) ma non sempre è la scelta più semplice, meno costosa e più veloce da seguire. In alternativa è possibile utilizzare un PIC con integrato un modulo USB, quale il PIC18F14. In questo caso occorre ovviamente scrivere il codice per il micro, impresa non difficile anche se al primo approccio appare un poco "ostica".

Low Pin Count USB Development Kit

L'hardware utilizzato per le prove è il Low Pin Count USB Development Kit che contiene tutto quanto è necessario per lavorare, incluso il debugger /programmatore PICkit2. Nella prima fotografia è visibile la scheda con il PIC e, sulla destra, il connettore USB per i dati e l'alimentazione dal PC. I due LED sono stati accesi attraverso un comando dato dalla tastiera del PC. 

Per realizzare il circuito è comunque sufficiente usare una breadboard. Occorre un minimo di attenzione nel realizzare la sezione del clock (in primo piano nella fotografia seguente) e mantenere i collegamenti brevi. Per il connettore è possibile tagliare un cavo USB e lavorare un po' di fantasia (e colla a caldo... come si vede in secondo piano). Occorre ovviamente prestare sempre la massima attenzione, visto che il circuito andrà collegato ad un PC acceso.

Un mini-periferica USB realizzata su bradboard

Per scrivere il software è necessario disporre dei seguenti componenti software, possibilmente nella versione più aggiornata. Da scaricare direttamente dal sito Microchip insieme alla documentazione relativa:

L'installazione è in perfetto "stile Windows": avanti → accetta → avanti → avanti...

La documentazione la trovate nelle stessa pagine da cui scaricate il software. Per cominciare ho trovato utile la AN956 - Migrating Applications to USB from RS-232 della Microchip (anche se decisamente vecchia!) oltre ovviamente alla USB Device Firmware Framework User’s Guide. Per inquadrare l'USB nei suoi aspetti generali segnalo infine la presentazione Getting Started fornita con il CD del kit, sicuramente da leggere almeno una volta prima di "fare sul serio".

Innanzitutto occorre precisare che il software fornito da Microchip viene correttamente definito come Framework: non si tratta infatti di librerie nel senso proprio del termina ma di normale codice C, comune a tutti i PIC e a tutte le piattaforme hardware supportate, che deve essere compilato insieme al codice che il progettista dovrà scrivere. Purtroppo la genericità (e francamente una certa confusione...) rendono l'impresa ben poco amichevole, almeno come primo impatto. Di certo l'inizio del lavoro è facilitata da una breve descrizione che spiega dove "mettere le mani" in un codice suddiviso in decine di file e centinaia di righe. Questo è lo scopo di questa pagina!

Innanzitutto è bene precisare che molto del codice non verrà mai realmente compilato a causa delle numerose direttive #ifdef sparse ovunque. Come si capisce facilmente leggendo il codice in molti casi si tratta di codice specifico per un determinato hardware che viene compilato o meno a seconda del valore di alcune constanti.

All'inizio non è per nulla necessario esplorare in profondità il codice; al limite la prima volta può essere semplicemente ignorato...

Quale risultato otterremo

La scelta migliore per cominciare è probabilmente quella di utilizzare la demo fornita da Microchip definita "CDC", ovvero una Communication Device Class.

In breve il PIC si comporterà come una vecchia periferica seriale: il PC potrà inviare sequenza di caratteri al PIC e ricevere le risposte. Questa scelta è motivata essenzialmente da due ragioni:

Il driver da installare in ambiente windows

Come tutti i programmi demo il software qui presentato non fa nulla di utile:

Di seguito un esempio di funzionamento in ambiente Debian (GTKTerm)

Il terminale GTKTerm mostra le stringhe ricevute dal PIC

Ecco un esempio in ambiente MicroSoft Windows Vista (PuTTY)

Il terminale PuTTY mostra le stringhe ricevute dal PIC

Compilare l'esempio

Innanzitutto occorre individuare l'esempio fornito da Microchip e caricarlo in MPLAB. Se durante l'installazione avete utilizzato il percorso proposto il file si trova in una sotto-cartella dal nome simile a "C:/Microchip_solution_etc". Vi consiglio vivamente di fare una copia prima di ogni modifica.

Carica la demo USB di Microchip

Potrebbe essere necessario modificare alcuni percorsi relativi agli header file o alle librerie, come di seguito mostrato. I dettagli potrebbero evidentemente cambiare in base alla versione del compilatore che avete installato.

Modificare la configurazione del progetto

Aggiungere la cartella con gli header file

Aggiungere la cartella con le librerie precompilate

E' possibile a questo punto compilare l'esempio e, volendo, provare ad eseguirlo. Vi consiglio però di approfondire l'esempio qui presentato, più lineare di quello presentato da Microchip e quindi semplice per cominciare.

Il primo programma

Scriviamo ora il nostro primo programma. Un frammento del codice sorgente lo trovate a fondo pagina: si tratta di una singola funzione che sostituisce l'omonima contenuta nell'esempio Microchip.

Innanzitutto individuiamo il codice della funzione main() fornita da Microchip. Questa funzione può non essere modificata; anzi, all'inizio, meglio non modificarla per nulla.

Nel seguito ignoro la descrizione di  alcune delle linee di codice per il semplice fatto che, a causa delle direttive #if defined, non sono compilate usando il PIC18 in configurazione standard.

void main(void)
{ InitializeSystem();

Questa funzione inizializza l'hardware, sia nelle parti legate all'USB sia in quelle relativamente ad altre funzioni quali il pilotaggio del LED. Vengono inizializzate anche una serie di variabili.

while(1)

Il resto del programma è un ciclo infinito...

 if(USB_BUS_SENSE && (USBGetDeviceState() == DETACHED_STATE))
{ USBDeviceAttach(); }

Queste funzioni provvedono a collegare (o ricollegare) la periferica USB al computer.

ProcessIO();

Questa è la funzione che andremo a scrive e che effettua tutte le elaborazioni, sia relativamente alle operazioni di lettura e scrittura USB che ad altre funzioni che il vostro programma dovrà svolgere. In alternativa potete aggiungere direttamente qui la chiamata alle vostre funzioni.

Esaminiamo ora la funzione  ProcessIO() che trovate a fondo pagina e sostituisce integralmente quella fornita da Microchip.

if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;

La funzione prosegue solo se il modulo USB è configurato e l'USB non è in stato di sospensione

if (getsUSBUSART (USB_Out_Buffer, 1)) {
  switch (USB_Out_Buffer[0])
   { case '1': mLED_1_On(); break;

La funzione getsUSBUSART() legge alcuni (in questo esempio solo uno) byte ricevuti via USB e li salva nel vettore USB_In_Buffer. La funzione non è bloccante nel senso che vengono trasferiti solo i byte già arrivati nell'istante di chiamata della funzione. Si noti che il nome usato per il buffer in entrata (USB_Out_Buffer) rispecchia lo standard USB che vede l'host (il PC in questo caso) al centro: in questo frammento di codice sembra avere un nome innaturale...

Una nota importante: è necessario che nessuna funzione, in nessuna parte del codice, sia "bloccante" cioè possa entrare in un loop infinito, molto lungo, o semplicemente il cui tempo di esecuzione possa, anche occasionalmente, allungarsi di molto.

Vengono quindi elaborati i comandi ricevuti: è mostrato sopra solo il comando che accende il LED1 quando è ricevuto il carattere "1". Nel codice allegato trovate anche i comandi per gli altri tre LED.

if(USBUSARTIsTxTrfReady()) {                                                // USB ready ?
  itoa(++byte_counter, USB_In_Buffer);
  strcatpgm2ram(USB_In_Buffer,(const far rom char*) " Char received: ");
  USB_Out_Buffer[strlen(USB_In_Buffer) - 1] = USB_Out_Buffer[0];
  strcatpgm2ram(USB_In_Buffer,(const far rom char*) "\r\n");
  putsUSBUSART(USB_In_Buffer);                                            // Put buffer to USB
}

Questa parte del codice prepara alla trasmissione verso il PC una stringa (funzione putsUSBUSART()). Deve essere invocata solo se il modulo USB è pronto a trasmettere (macro USBUSARTIsTxTrfReady()).

La preparazione della stringa da trasmettere al PC è piuttosto laboriosa ma è una soluzione che occupa poco spazio.

Se volete usare la funzione sprintf() è necessario intervenire sulle configurazioni presenti nel file rm18f18K50.lkr e modificare l'ultima linea in qualcosa di simile alla seguente, ben sapendo che ciò sottrae RAM ad altre variabili:

STACK SIZE=0xB0 RAM=gpr1

In questo caso è possibile usare un codice simile al seguente, sicuramente più leggibile:

if(USBUSARTIsTxTrfReady()) {
  sprintf(USB_In_Buffer, (const far rom char*)"%i - Char received: %c\r\n", ++byte_counter, USB_In_Buffer[0]);
  putsUSBUSART(USB_In_Buffer);
}

In alcuni casi, per esempio se i dati non sono una stringa, può essere utile anche la seguente funzione in cui il numero di byte da inviare è utilizzato come parametro.

putUSBUSART(USB_In_Buffer, char_to_send );

Infine è importantissimo invocare con una certa frequenza la funzione CDCTxService(). Questa funzione è quella che effettivamente provvede all'invio dei byte verso il PC. Per la ricezione invece nel framework è attiva una specifica funzione di interrupt ad alta priorità: non è necessaria alcuna modifica.

A questo punto è possibile provare il codice programmando il PIC (o usando il debugger), collegando il cavetto USB,  facendo partire il terminale sul PC collegato alla porta seriale virtuale che viene automaticamente creata al momento della connessione della scheda con il PIC18 (per Windows è richiesto un driver presente tra le librerie Microchip).

COM13 (Vista)

Da notare che il circuito non richiede alimentazione separata in quanto fornita dal PC attraverso il cavetto USB. Per questo se usate il kit Microchip è necessario ponticellare i pin 2 e 3 di J14 e lasciare aperto J13. Prestare attenzione al fatto che la corrente disponibile è poca (500 mA massimo) e che vi è una connessione diretta al PC.

Ora siete pronti a modificare il programma demo:

Scarica il codice sorgente

PIC18F14K50 in C

Licenza "Creative Commons" - Attribuzione-Condividi allo stesso modo 3.0 Unported


EN - Pagina principale - Sommario - Accessibilità - Note legali e privacy policy - Posta elettronica

XHTML 1.0 Strict - CSS 3