Il chip FT232BM di FTDI è un convertitore seriale USB che permette di implementare una comunicazione USB nella propria applicazione senza entrare nel merito dello standard USB, ma comunicando semplicemente attraverso un UART. Dal punto di vista software dal lato USB il dispositivo può essere gestito in due diverse modalità.
La più semplice è quella che vede l’impiego di un driver (fornito dal costruttore) che permette la creazione di una porta seriale virtuale, per cui l’applicazione software dovrà essere configurata per inviare e ricevere dati su tale porta. L’altra modalità è quella di utilizzare il Direct Driver D2XX anch’esso fornito da FTDI, che consente di comunicare via USB evitando l’uso di una porta seriale virtuale. In questo articolo spiegheremo come utilizzare la libreria pubblica for nita da FTDI, includendola nel compilatore Microsoft Visual Basic®. Da ora in poi si farà riferimento al compilatore Versione 5, ma non sarà difficile adattare le considerazioni anche alle versioni successive. La prima cosa da dire è che per comunicare direttamente con il chip FTDI avremo bisogno di una libreria che includa tutte le funzioni per colloquiare a basso livello attraverso il bus USB. Tale libreria non dovremmo crearla, ma già esiste e distribuita da FTDI gratuitamente. Sul sito www.ftdichip.com troveremo i componenti necessari per comunicare con il chip FT232BM. La libreria da scaricare è inclusa nel Direct Driver D2XX. In dettaglio, il compilatore avrà bisogno del file FTD2XX.dll che dovrà trovarsi nella stessa directory del progetto oppure nella directory ‘SYSTEM‘ del sistema operativo.
Includere la libreria FTD2XX.DLL
Al fine di poter utilizzare tutte le funzioni messe a disposizione della libreria FTDI, è necessario che l’ambiente di sviluppo riconosca la libreria e che ciascuna funzione sia dichiarata nel programma. Per far riconoscere una funzione di una DLL, è necessario utilizzare la sintassi ‘Declare’, ed inoltre se si desidera che tale funzione sia disponibile in tutto il progetto (form, moduli, ecc..) deve essere dichiarata a livello globale. Un altro avviso importante è quello di fare molta attenzione nella dichiarazione di una funzione esterna contenuta in una DLL. Il tipo di parametri ed il loro passaggio (byVal o byRef) deve corrispondere rispettivamente al passaggio di un valore o di un puntatore (nel linguaggio C++). Inoltre la natura dei parametri e la loro lunghezza (Integer, Long, Byte o String) deve corrispondere, in termini di lunghezza in byte alla stessa dichiarazione che è stata fatta nel linguaggio C++ al momento della compilazione della DLL. Se non si fa attenzione a questi dettagli, si rischia di perdere il controllo dell’applicazione quando vengono eseguite le funzioni, con il conseguente ‘crash’ del sistema. Si consiglia di salvare il progetto prima di ogni esecuzione. Per sapere quali parametri e con quale dimensione devono essere passati, è necessario sapere, in ciascuna funzione, il numero di parametri e le loro caratteristiche.
Come far riconoscere le librerie al programma sorgente
Aprite un nuovo progetto e aggiungete un nuovo modulo .bas. All’interno del modulo devono essere inserite tutte le dichiarazioni riferite a tutte le funzioni che si desiderano utilizzare. Come già accennato, metteremo qui le dichiarazioni al fine di poter eseguirle in qualsiasi punto del programma e in qualsiasi modulo. Nel listato 1 riportiamo le dichiarazioni riferite alle funzioni di maggiore utilizzo come FT_OPEN, FT_CLOSE, FT_SETBAUDRATE, ecc..., sono disponibili anche altre funzioni e la loro descrizione si trova sempre nella documentazione del costruttore. Ciascuna funzione, al termine dell’esecuzione restituirà un risultato (FT_STATUS) che rispecchia il buon esito dell’operazione. Se FT_STATUS sarà eguale a FT_OK (zero) significa che l’operazione richiesta è stata eseguita correttamente, altrimenti verrà restituito un numero che corrisponde al tipo di errore verificatosi.
Declare Function FT_ListDevices Lib “FTD2XX.DLL” (ByRef Arg1 As Integer, ByRef Arg2 As Integer, ByVal dwFlags As Long) As Long Declare Function FT_Open Lib “FTD2XX.DLL” (ByVal iDevice As Integer, ByRef ftHandle As Long) As Long Declare Function FT_Close Lib “FTD2XX.DLL” (ByVal ftHandle As Long) As Long Declare Function FT_SetBaudRate Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal dwBaudRate As Long) As Long Declare Function FT_SetDataCharacteristics Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal wWordLenght As Byte, ByVal uStopBits As Byte, ByVal uParity As Byte) As Long Declare Function FT_SetFlowControl Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal usFlowControl As Integer, ByVal uXon As Byte, ByVal uXoff As Byte) As Long Declare Function FT_Write Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal lpBuffer As String, ByVal dwBytesToWrite As Long, ByRef lpwdBytesWritten As Long) As Long Declare Function FT_Read Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal lpBuffer As String, ByVal BufferSize As Long, ByRef BytesReturned As Long) As Long Declare Function FT_ResetDevice Lib “FTD2XX.DLL” (ByVal ftHandle As Long) As Long Declare Function FT_Purge Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal Mask As Long) As Long Declare Function FT_GetStatus Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByRef RxBytes As Long, ByRef TxBytes As Long, ByRef EventsDWord As Long) As Long
Listato 1 |
Il significato di ftHandle.
Noterete che in tutte le funzioni comparirà la variabile ftHandle. Ma a cosa serve? Sul bus USB potremmo collegare ‘n’ dispositivi FT232BM e quindi questo significa che potremmo utilizzarli contemporaneamente. Ma come possiamo distinguerli tra loro se le librerie sono sempre le stesse? Allora a questo punto entra in gioco l’importanza della variabile ftHandle. Quando decidiamo di collegarci ad uno degli ‘n’ dispositivi FT232BM collegati, dovremmo utilizzare la funzione FT_OPEN per indicare al sistema operativo che la periferica sta per essere utilizzata. La funzione FT_OPEN restituirà in ftHandle, un numero univoco che identifica la periferica. Da questo momento in poi, tutte le funzioni che utilizzeremo, avranno bisogno di sapere su quale dispositivo intendiamo operare e quindi lo comunicheremo passando ogni volta il numero univoco contenuto in ftHandle. Il ciclo di vita di ftHandle si chiuderà quando utilizzeremo FT_CLOSE. Da questo momento in poi il sistema operativo capirà che tale periferica non è più in uso. Capita l’importanza di questa variabile, è ora necessario dire che essa deve essere dichiarata a livello globale se si desidera sapere in qualsiasi punto del programma il numero univoco da comunicare. Pertanto sul modulo .bas aggiungeremo:
Global ftHandle As Long Se si desidera comunicare con più dispositivi FT232BM, dovremmo utilizzare due variabili diverse tra loro, ciascuna con il suo ‘Handle’.
Dichiarazioni delle costanti per la libreria FTD2XX.
Nell’impostazione delle caratteristiche della porta, sono di sicura utilità delle costanti già pronte per identificare in modo semplice quale parametro si desidera comunicare alla funzione. A tal proposito, il listato 2 riporta un breve esempio. Quando useremo le funzioni tipo FT_SetBaudRate o FT_SetDataCharacteristics, potremmo inserire direttamente il nome della costante... decisamente molto più intuitivo.
Global Const FT_LIST_NUMBER_ONLY As Long = &H80000000 Global Const FT_LIST_BY_INDEX As Long = &H40000000 Global Const FT_LIST_ALL As Long = &H20000000 in alternativa: Global Const FT_FLOW_NONE As Integer = &H0 Global Const FT_FLOW_RTS_CTS As Integer = &H100 Global Const FT_FLOW_DTR_DSR As Integer = &H200 Global Const FT_FLOW_XON_XOFF As Integer = &H400
Listato 2 |
Funzioni disponibili nella libreria FTD2XX.
Ora siamo pronti a scrivere le prime linee di programma. La libreria FTD2XX possiede molte funzioni per comunicare, configurare ed impartire ordini al chip FT232BM, di seguito ci soffermeremo solo alle funzioni principali, facendo anche qualche esempio. Per la lista completa delle funzioni e come si utilizzano, fate riferimento al ‘D2XX Programmer’s Guide’ originale FTDI.
Funzione FT_ListDevices
FT_ListDevices Lib “FTD2XX.DLL” (ByRef Arg1 As Integer, ByRef Arg2 As Integer, ByVal dwFlags As Long) As Long
Questa funzione darà un risultato che dipende dal contenuto di dwFlags. Per fare un esempio, se dwFlag s = FT_LIST_NUMBER_ONLY, otterremo come risultato, in Arg1, il numero totale di dispositivi FT232BM collegati al bus USB. Invece se dwFlags = FT_OPEN_BY_DESCRIPTION, otterremo come risultato la stringa di descrizione associata alla periferica USB. Il risultato della funzione è sempre ‘FT_OK’ se la funzione ha avuto esito positivo, altrimenti se con risultato diverso, significa che il sistema operativo non è stato in grado di comunicare con il ‘Direct Driver’ e/o con il bus USB, restituendo un codice di errore. Facciamo un esempio di utilizzo di questa funzione:
Private Sub Command_FT_ListDevices_Click()
Dim Arg1 As Integer
Dim FT_STATUS As Long
FT_STATUS = FT_ListDevices(Arg1,
vbNull, FT_LIST_NUMBER_ONLY) If FT_STATUS = FT_OK Then
MsgBox “Il numero di dispositivi trovati è: “ & Format(Arg1)
Else
MsgBox “Errore “ & Format(FT_STATUS)
End If
End Sub
Funzione FT_Open
FT_Open Lib “FTD2XX.DLL” (ByVal iDevice As Integer, ByRef ftHandle As Long) As Long
Se si vuole cominciare a comunicare con il chip FT232BM, la prima cosa da fare è aprire la porta di comunicazione verso il dispositivo, in modo analogo a come si faceva per le porte seriali RS232. FT_Open è la funzione dedicata a questo lavoro, iDevice deve contenere il numero del dispositivo collegato (iDevice = 0 se un solo dispositivo collegato).
Facciamo un esempio di utilizzo:
Private Sub Command_FT_Open_Click() Dim FT_STATUS As Long
FT_STATUS = FT_Open(0, ftHandle) If FT_STATUS <> FT_OK Then Msg-
Box “Apertura porta fallita.”
End Sub
Funzione FT_Close
FT_Close Lib “FTD2XX.DLL” (ByVal ftHandle As Long) As Long
La porta di comunicazione, come viene aperta, deve necessariamente essere chiusa al termine dell’utilizzo. Questa funzione esegue il compito di chiusura della porta. Si consiglia di eseguire questa funzione nell’evento ‘UnLoad’ del form principale. E’ buona cosa chiudere la porta al termine del programma, altrimenti il sistema operativo non riuscirà a riaprirla nuovamente alla successiva esecuzione. In questo caso l’unica soluzione è disconnettere l’hardware e ricollegarlo (reset).
Private Sub Form_Unload(Cancel
As Integer)
FT_STATUS = FT_Close(ftHandle)
If FT_STATUS <> FT_OK Then Msg-
Box “Chiusura porta fallita.” End Sub
Funzione FT_Read
FT_Read Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal lpBuffer As String, ByVal BufferSize As Long, ByRef BytesReturned As Long) As Long
Questa è la funzione per la lettura dei dati provenienti dal canale di ricezione RX del chip FT232BM.
ftHandle è l’handle del dispositivo da leggere.
lpBuffer è il puntatore del buffer che dovrà contenere i dati.
BufferSize contiene il numero dei bytes che devono essere letti dalla porta.
BytesReturned è il puntatore riferito alla variabile che restituisce il numero di bytes ricevuti.
Come sempre la funzione restituisce ‘FT_OK’ se eseguita con successo. Esempio:
Private Sub Timer1_Timer() Dim RxBytes As Long
Dim TxBytes As Long
Dim EventWord As Long
Dim RxBuffer As String * 256
Dim BytesReturned As Long FT_GetStatus ftHandle, RxBytes, TxBytes, EvendWord
If RxBytes > 1 Then
FT_STATUS = FT_Read(ftHandle, RxBuffer, RxBytes, BytesReturned)
If FT_STATUS = FT_OK Then Text1.Text = Text1.Text + RxBuffer
End If End If End Sub
In questo esempio, la funzione FT_Read viene eseguita all’interno di un oggetto Timer impostato a 1000ms (1 secondo). Questo significa che, in ogni secondo viene effettuato il controllo del buffer di ricezione e la finestra di testo Text1 ne riporterà il contenuto. Notate che la funzione FT_GetStatus, restituisce il numero di caratteri in attesa nel buffer di ricezione della porta. Se il numero di caratteri in attesa nel buffer è maggiore di uno, la funzione FT_Read viene eseguita, altrimenti nulla accade. La funzione FT_GetStatus può essere inoltre utilizzata anche per sapere il numero di caratteri in attesa sul buffer di trasmissione (puntatore TxBytes).
Funzione FT_Write
FT_Write Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal lpBuffer As String, ByVal dwBytesToWrite As Long, ByRef lpwdBytesWritten As Long) As Long
Questa è la funzione che vi permette d’inviare dati sulla linea TX del chip FT232BM.
ftHandle è l’handle del dispositivo su cui scrivere.
lpBuffer è il puntatore del buffer che contiene i dati da inviare alla porta. dwBytesToWrite indica il numero di bytes da inviare alla porta.
lpdwBytesWritten è il puntatore che restituisce il numero dei bytes inviati alla porta.
La funzione restituisce ‘FT_OK’ se eseguita con successo.
Esempio di utilizzo:
Private Sub Command_FT_Write_Click() Dim FT_STATUS As Long
Dim WriteBuffer As String * 256
Dim BytesToWrite As Long Dim BytesWritten As Long WriteBuffer = “Hello” BytesToWrite = 5
FT_STATUS = FT_Write(ftHandle, WriteBuffer, BytesToWrite, BytesWritten)
If FT_STATUS = FT_OK Then
MsgBox “Bytes inviati: “ & Format(BytesWritten)
Else
MsgBox “Invio dati non riuscito.”
MsgBox FT_STATUS End If
End Sub
In questo esempio la scritta ‘Hello’ contenuta in WriteBuffer viene inviata alla porta.
Funzione FT_SetBaudRate
FT_SetBaudRate Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal dwBaudRate As Long) As Long
Funzione dedicata all’impostazione della velocità di comunicazione della porta. Restituisce FT_OK se eseguita con successo, altrimenti restituisce il codice di errore.
ftHandle è l’handle del dispositivo da impostare.
dwBaudRate è il valore in baud ‘standard’ da impostare (300, 1200, 2400, 4800, 9600, ecc...)
Molto semplice da utilizzare: Esempio:
FT_SetBaudRate(ftHandle, 1200);
oppure:
F T _ S e t B a u d R a t e ( f t H a n d l e , FT_BAUD_1200);
NOTA: Se desiderate impostare velocità non standard, utilizzate la funzione FT_SetDivisor
Funzione FT_SetDataCharacteristics
FT_SetDataCharacteristics Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal wWordLenght As Byte, ByVal
uStopBits As Byte, ByVal uParity
As Byte) As Long
Questa funzione permette d’impostare le caratteristiche di trasmissione/ricezione della porta.
ftHandle è l’handle del dispositivo da impostare.
uWordLength imposta la lunghezza del dato (7 o 8 bits)
FT_BITS_7
FT_BITS_8
uStopBits Imposta il bit di stop (1 o 2) FT_STOP_BITS_1
FT_STOP_BITS_2
uParity Imposta la parità (Nessuna, pari, dispari, Mark, Space)
FT_PARITY_NONE FT_PARITY_ODD
FT_PARITY_EVEN FT_PARITY_MARK
FT_PARITY_SPACE Esempio:
FT_STATUS = FT_SetDataCharacteristics(ftHandle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE) If FT_STATUS <> FT_OK Then MsgBox “Impostazione DATA CHARACTERISTICS fallita.”
Funzione FT_SetFlowControl
FT_SetFlowControl Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal usFlowControl As Integer, ByVal
uXon As Byte, ByVal uXoff As Byte) As Long
Permette d’impostare il controllo di flusso dei dati della porta.
ftHandle è l’handle del dispositivo da impostare.
usFlowControl dipo di flusso da impostare:
FT_FLOW_NONE (Nessuno) FT_FLOW_RTS_CTS
FT_FLOW_DTR_DSR
FT_FLOW_XON_XOFF
uXon e uXoff indicano i caratteri da utilizzare per il controllo di flusso XON/XOFF (Considerati solo se impostato questo tipo di flusso). Esempio:
FT_STATUS = FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0)
If FT_STATUS <> FT_OK Then Msg-
Box “Impostazione FLOW CONTROL fallita.”
Funzione FT_Purge
Questa funzione cancella i buffers di ricezione e trasmissione.
FT_Purge Lib “FTD2XX.DLL” (ByVal ftHandle As Long, ByVal Mask As Long) As Long
Restituisce FT_OK se eseguita correttamente, altrimenti restituisce il codice di errore.
Esempio:
FT_STATUS = FT_Purge ftHandle, FT_PURGE_RX
oppure:
FT_STATUS = FT_Purge ftHandle, FT_PURGE_TX
Conclusioni
Con queste funzioni potrete aprire una connessione per lo scambio di dati con il modulo FT232BM da Visual Basic senza utilizzare porte COM virtuali. Se decidete invece di usare le porte seriali virtuali, in Viasual Basic sarà sufficiente usare l’oggetto MSComm configurato sulla COM virtuale creata dal driver ed implementare una comune comunicazione seriale. Sarà cura del chip FT232BM instradare i dati attraverso l’USB.