OUTPUT DIGITALE: Esempio LED
Per provare il codice presentato in questa pagina occorre costruire il seguente circuito (serve una resistenza da 220 ohm e un led)
Ecco l'immagine del circuito
Codice Sorgente A
Obiettivo progetto: Utilizzando il circuito precedente accendere il led e spegnerlo ripetutamente ogni secondo
soluzione: Ecco il codice che risolve il nostro problema
/* ----------------------------------------------------------------------------------- Esempio creato partendo dal codice: Blink di pubblico dominio. Accende e spegne un LED per 1 secondo ripetutamente ---------------------------------------------------------------------------------- */ int led = 13; // Il Pin 13 è quello connesso al LED // La routine di "setup" parte appena premo il tasto di reset: void setup() { // imposta il pin 13 come pin di OUTPUT. pinMode(led, OUTPUT); } // La loop routine continua a girare: void loop() { digitalWrite(led, HIGH); // Accende il LED impostando il voltaggio a HIGH delay(1000); // attendo un secondo digitalWrite(led, LOW); // spengo il LED impostando il voltaggio a LOW delay(1000); // attendo un secondo }
Codice Sorgente B
Obiettivo progetto: Utilizzando il circuito precedente accendere il led utilizzando i comandi mostrati nella figura sottostante all'interno del serial monitor
soluzione: Ecco il codice che risolve il nostro problema
/* Esempio creato partendo dal codice Bernardo Giovanni - www.settorezero.com Accende e spegne il LED connesso sulla porta 13 mediante un comando inviato sulla porta seriale */ #define led 13 // Il Pin 13 è quello connesso al LED char rx = 0; // variabile per contenere il carattere ricevuto void setup() { Serial.begin(9600); // imposto la seriale per lavorare a 9600 baud pinMode(led, OUTPUT); // imposta il pin 13 come pin di OUTPUT. Serial.flush(); // Svuoto il buffer di ricezione seriale Serial.println("Comandi disponibili:\nA -> accendi\nS -> Spegni\nM -> Stato LED"); } void loop() { if (Serial.available() >0) // Controllo se il buffer di ricezione contiene qualcosa { rx = Serial.read(); // leggo il carattere ricevuto e lo memorizzo in rx Serial.flush(); // svuoto il buffer di ricezione seriale if (rx=='A' || rx=='a') // ho ricevuto la A maiuscola o minuscola { if (digitalRead(led) == LOW) // il led e' spento { digitalWrite(led,HIGH); // lo accendo Serial.println("Comando \"A\" -> Ho acceso il LED"); } else Serial.println("Comando \"A\" -> Ignorato! Il LED e' acceso!"); } else if (rx=='S' || rx=='s') // ho ricevuto la S maiuscola o minuscola { if (digitalRead(led) == HIGH) // il led è acceso { digitalWrite(led,LOW); // lo spengo Serial.println("Comando \"S\" -> Ho spento il LED"); } else Serial.println("Comando \"S\" -> Ignorato! Il LED e' spento!"); } else if (rx=='M' || rx=='m') // ho ricevuto la M maiuscola o minuscola { if (digitalRead(led) == HIGH) // il led era acceso? Serial.println("Comando \"M\" -> Stato LED: acceso"); else Serial.println("Comando \"M\" -> Stato LED: spento"); } else // Ho ricevuto un altro carattere { Serial.print("Comando \""); Serial.print((char)rx); Serial.println("\" -> Non riconosciuto!"); } } }
Codice Sorgente C++ - DOS
Obiettivo progetto: Utilizzando il circuito precedente accendere il led utilizzando un'applicazione dos come mostrato nella figura sottostante
soluzione: Compiliamo il codice C++ della seguente applicazione DOS.Possiamo utilizzare per la compilazione l'ide DEV C++ (http://orwelldevcpp.blogspot.it/). Occorre eventualmente modificare la porta
#include <stdio.h> #include <conio.h> #include <windows.h> #define PORTAARDUINO "com3:" // Forwarding HANDLE ApriSeriale(); void MostraMenu(); int LeggiComando(); int main() { HANDLE hComm; DWORD n; char Risposta[512]={'\0'}; int key; hComm=ApriSeriale(); if (hComm != INVALID_HANDLE_VALUE) { MostraMenu(); while(1) { key=LeggiComando(); WriteFile(hComm, &key, 1,&n,NULL); // Invio il comando Sleep(50); // attesa per leggere il risultato del comando ReadFile(hComm, Risposta, 512, &n, NULL); if (n!=0) { Risposta[n]='\0'; // terminatore di stringa printf("\nRisposta da ARDUINO (%d): %s", n, Risposta); printf("comando da inviare a ARDUINO: "); } } CloseHandle(hComm); } } /* -------------------------------------------------------------------- Funzione che continua a leggere da tastiera finché l'utente non digita un comando digitato dall'utente --------------------------------------------------------------------- */ int LeggiComando() { int key; do { key=getch(); if(key==27) { printf("Esc"); exit(0); } if ( (key=='a') || (key=='A') || (key=='s') || (key=='S') || (key=='m') || (key=='M')) { putch(key); return(key); } } while (1); } /* -------------------------------------------------------------------- Funzione che mostra il menu dei comandi --------------------------------------------------------------------- */ void MostraMenu() { printf("Help comandi disponibili:\n"); printf("-----------------------------\n"); printf("A -> Accende il LED\n"); printf("S -> Spegne il LED\n"); printf("M -> Legge lo stato del LED\n"); printf("Esc -> Per uscire\n"); printf("-----------------------------\n"); printf("comando da inviare a ARDUINO: "); } /* -------------------------------------------------------------------- Funzione che apre la porta seriale --------------------------------------------------------------------- */ HANDLE ApriSeriale() { HANDLE hComm; hComm = CreateFile( PORTAARDUINO, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0,//FILE_FLAG_OVERLAPPED, 0); if (hComm == INVALID_HANDLE_VALUE) { printf("Porta seriale %s non disponibile!",PORTAARDUINO); return INVALID_HANDLE_VALUE; } //SetupComm(hComm, 2, 128); // set buffer sizes DCB config = {0}; if((GetCommState(hComm, &config) == 0)) { printf("Lettura configurazione fallita!."); return 0; } //config.DCBlength = sizeof(config); config.BaudRate = CBR_9600; config.Parity = NOPARITY; // config.Parity = EVENPARITY; config.StopBits = ONESTOPBIT; config.ByteSize = DATABITS_8; config.fAbortOnError = TRUE; config.fOutX = FALSE; // XON/XOFF off for transmit config.fInX = FALSE; // XON/XOFF off for receive config.fDtrControl = DTR_CONTROL_DISABLE; config.fRtsControl = RTS_CONTROL_DISABLE; if (!SetCommState(hComm, &config)) { printf( "Configurazione porta seriale fallita! Errore nr.: %d\n",GetLastError()); return(0); } // printf("Configurazione seriale corrente:\n Baud Rate %d\n Parity %d\n Byte Size %d\n Stop Bits %d\n\n", // config.BaudRate, config.Parity, config.ByteSize, config.StopBits); // Communication timeouts are optional // Tell the program not to wait for data to show up COMMTIMEOUTS timeouts={0}; GetCommTimeouts(hComm, &timeouts); timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(hComm, &timeouts)) printf( "Configurazione dei timeouts fallita! Errore nr.: %d\n",GetLastError()); //SetCommMask(hComm,EV_RXCHAR); return(hComm); }Codice Sorgente VBA - XLS
Obiettivo progetto: Utilizzando il circuito precedente accendere il led utilizzando una macro Comanda_LED() in EXCEL implementata ad hoc come mostrato nella figura sottostante. Il sorgente caricato in Arduino resta lo stesso del precedente l'esempio B.
soluzione: tutto si basa sulla funzione personalizzata Comanda_LED()
Public Function Comanda_LED(Comando As String) as string Dim lngStatus As Long Dim Risposta As String Dim intPortID As Integer intPortID = 3 ' Porta utilizzata If UCase(Comando) = "A" Or UCase(Comando) = "S" Or UCase(Comando) = "M" Then Call Lib_Comm.CommOpen(intPortID, "COM" & intPortID, "baud=9600 parity=N data=8 stop=1") lngStatus = CommWrite(intPortID, Comando) Sleep (50) ' attesa per leggere il risultato del comando lngStatus = CommRead(intPortID, Risposta, 100) Call CommClose(intPortID) Comanda_LED = Risposta Else Comanda_LED = ("Comando """ & Comando & """ Errato!") End If End Function
è possibile scaricare il file di esempio cliccando su questo link: arduino.xls.
Al suo interno abbiamo la libreria Lib_Comm che consente la gestione
della comunicazione con la porta seriale.
Option Explicit '------------------------------------------------------------------------------- ' ' This VB module is a collection of routines to perform serial port I/O without ' using the Microsoft Comm Control component. This module uses the Windows API ' to perform the overlapped I/O operations necessary for serial communications. ' ' The routine can handle up to 4 serial ports which are identified with a ' Port ID. ' ' All routines (with the exception of CommRead and CommWrite) return an error ' code or 0 if no error occurs. The routine CommGetError can be used to get ' the complete error message. '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- ' Public Constants '------------------------------------------------------------------------------- ' Output Control Lines (CommSetLine) Const LINE_BREAK = 1 Const LINE_DTR = 2 Const LINE_RTS = 3 ' Input Control Lines (CommGetLine) Const LINE_CTS = &H10& Const LINE_DSR = &H20& Const LINE_RING = &H40& Const LINE_RLSD = &H80& Const LINE_CD = &H80& '------------------------------------------------------------------------------- ' System Constants '------------------------------------------------------------------------------- Private Const ERROR_IO_INCOMPLETE = 996& Private Const ERROR_IO_PENDING = 997 Private Const GENERIC_READ = &H80000000 Private Const GENERIC_WRITE = &H40000000 Private Const FILE_ATTRIBUTE_NORMAL = &H80 Private Const FILE_FLAG_OVERLAPPED = &H40000000 Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000 Private Const OPEN_EXISTING = 3 ' COMM Functions Private Const MS_CTS_ON = &H10& Private Const MS_DSR_ON = &H20& Private Const MS_RING_ON = &H40& Private Const MS_RLSD_ON = &H80& Private Const PURGE_RXABORT = &H2 Private Const PURGE_RXCLEAR = &H8 Private Const PURGE_TXABORT = &H1 Private Const PURGE_TXCLEAR = &H4 ' COMM Escape Functions Private Const CLRBREAK = 9 Private Const CLRDTR = 6 Private Const CLRRTS = 4 Private Const SETBREAK = 8 Private Const SETDTR = 5 Private Const SETRTS = 3 '------------------------------------------------------------------------------- ' System Structures '------------------------------------------------------------------------------- Private Type COMSTAT fBitFields As Long ' See Comment in Win32API.Txt cbInQue As Long cbOutQue As Long End Type Private Type COMMTIMEOUTS ReadIntervalTimeout As Long ReadTotalTimeoutMultiplier As Long ReadTotalTimeoutConstant As Long WriteTotalTimeoutMultiplier As Long WriteTotalTimeoutConstant As Long End Type ' ' The DCB structure defines the control setting for a serial ' communications device. ' Private Type DCB DCBlength As Long BaudRate As Long fBitFields As Long ' See Comments in Win32API.Txt wReserved As Integer XonLim As Integer XoffLim As Integer ByteSize As Byte Parity As Byte StopBits As Byte XonChar As Byte XoffChar As Byte ErrorChar As Byte EofChar As Byte EvtChar As Byte wReserved1 As Integer 'Reserved; Do Not Use End Type Private Type OVERLAPPED Internal As Long InternalHigh As Long offset As Long OffsetHigh As Long hEvent As Long End Type Private Type SECURITY_ATTRIBUTES nLength As Long lpSecurityDescriptor As Long bInheritHandle As Long End Type '------------------------------------------------------------------------------- ' System Functions '------------------------------------------------------------------------------- #If VBA7 Then Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr) 'For 64 Bit Systems #Else Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 'For 32 Bit Systems #End If ' ' Fills a specified DCB structure with values specified in ' a device-control string. ' Private Declare Function BuildCommDCB Lib "kernel32" Alias "BuildCommDCBA" _ (ByVal lpDef As String, lpDCB As DCB) As Long ' ' Retrieves information about a communications error and reports ' the current status of a communications device. The function is ' called when a communications error occurs, and it clears the ' device's error flag to enable additional input and output ' (I/O) operations. ' Private Declare Function ClearCommError Lib "kernel32" _ (ByVal hFile As Long, lpErrors As Long, lpStat As COMSTAT) As Long ' ' Closes an open communications device or file handle. ' Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long ' ' Creates or opens a communications resource and returns a handle ' that can be used to access the resource. ' Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _ (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, lpSecurityAttributes As Any, _ ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long) As Long ' ' Directs a specified communications device to perform a function. ' Private Declare Function EscapeCommFunction Lib "kernel32" _ (ByVal nCid As Long, ByVal nFunc As Long) As Long ' ' Formats a message string such as an error string returned ' by anoher function. ' Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" _ (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, _ ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, _ Arguments As Long) As Long ' ' Retrieves modem control-register values. ' Private Declare Function GetCommModemStatus Lib "kernel32" _ (ByVal hFile As Long, lpModemStat As Long) As Long ' ' Retrieves the current control settings for a specified ' communications device. ' Private Declare Function GetCommState Lib "kernel32" _ (ByVal nCid As Long, lpDCB As DCB) As Long ' ' Retrieves the calling thread's last-error code value. ' Private Declare Function GetLastError Lib "kernel32" () As Long ' ' Retrieves the results of an overlapped operation on the ' specified file, named pipe, or communications device. ' Private Declare Function GetOverlappedResult Lib "kernel32" _ (ByVal hFile As Long, lpOverlapped As OVERLAPPED, _ lpNumberOfBytesTransferred As Long, ByVal bWait As Long) As Long ' ' Discards all characters from the output or input buffer of a ' specified communications resource. It can also terminate ' pending read or write operations on the resource. ' Private Declare Function PurgeComm Lib "kernel32" _ (ByVal hFile As Long, ByVal dwFlags As Long) As Long ' ' Reads data from a file, starting at the position indicated by the ' file pointer. After the read operation has been completed, the ' file pointer is adjusted by the number of bytes actually read, ' unless the file handle is created with the overlapped attribute. ' If the file handle is created for overlapped input and output ' (I/O), the application must adjust the position of the file pointer ' after the read operation. ' Private Declare Function ReadFile Lib "kernel32" _ (ByVal hFile As Long, ByVal lpBuffer As String, _ ByVal nNumberOfBytesToRead As Long, ByRef lpNumberOfBytesRead As Long, _ lpOverlapped As OVERLAPPED) As Long ' ' Configures a communications device according to the specifications ' in a device-control block (a DCB structure). The function ' reinitializes all hardware and control settings, but it does not ' empty output or input queues. ' Private Declare Function SetCommState Lib "kernel32" _ (ByVal hCommDev As Long, lpDCB As DCB) As Long ' ' Sets the time-out parameters for all read and write operations on a ' specified communications device. ' Private Declare Function SetCommTimeouts Lib "kernel32" _ (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long ' ' Initializes the communications parameters for a specified ' communications device. ' Private Declare Function SetupComm Lib "kernel32" _ (ByVal hFile As Long, ByVal dwInQueue As Long, ByVal dwOutQueue As Long) As Long ' ' Writes data to a file and is designed for both synchronous and a ' synchronous operation. The function starts writing data to the file ' at the position indicated by the file pointer. After the write ' operation has been completed, the file pointer is adjusted by the ' number of bytes actually written, except when the file is opened with ' FILE_FLAG_OVERLAPPED. If the file handle was created for overlapped ' input and output (I/O), the application must adjust the position of ' the file pointer after the write operation is finished. ' Private Declare Function WriteFile Lib "kernel32" _ (ByVal hFile As Long, ByVal lpBuffer As String, _ ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, _ lpOverlapped As OVERLAPPED) As Long Private Declare Sub AppSleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long) '------------------------------------------------------------------------------- ' Program Constants '------------------------------------------------------------------------------- Private Const MAX_PORTS = 4 '------------------------------------------------------------------------------- ' Program Structures '------------------------------------------------------------------------------- Private Type COMM_ERROR lngErrorCode As Long strFunction As String strErrorMessage As String End Type Private Type COMM_PORT lngHandle As Long blnPortOpen As Boolean udtDCB As DCB End Type '------------------------------------------------------------------------------- ' Program Storage '------------------------------------------------------------------------------- Private udtCommOverlap As OVERLAPPED Private udtCommError As COMM_ERROR Private udtPorts(1 To MAX_PORTS) As COMM_PORT '------------------------------------------------------------------------------- ' GetSystemMessage - Gets system error text for the specified error code. '------------------------------------------------------------------------------- Public Function GetSystemMessage(lngErrorCode As Long) As String Dim intPos As Integer Dim strMessage As String, strMsgBuff As String * 256 Call FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, lngErrorCode, 0, strMsgBuff, 255, 0) intPos = InStr(1, strMsgBuff, vbNullChar) If intPos > 0 Then strMessage = Trim$(Left$(strMsgBuff, intPos - 1)) Else strMessage = Trim$(strMsgBuff) End If GetSystemMessage = strMessage End Function Public Function PauseApp(PauseInSeconds As Long) Call AppSleep(PauseInSeconds * 1000) End Function '------------------------------------------------------------------------------- ' CommOpen - Opens/Initializes serial port. ' ' ' Parameters: ' intPortID - Port ID used when port was opened. ' strPort - COM port name. (COM1, COM2, COM3, COM4) ' strSettings - Communication settings. ' Example: "baud=9600 parity=N data=8 stop=1" ' ' Returns: ' Error Code - 0 = No Error. ' '------------------------------------------------------------------------------- Public Function CommOpen(intPortID As Integer, strPort As String, _ strSettings As String) As Long Dim lngStatus As Long Dim udtCommTimeOuts As COMMTIMEOUTS On Error GoTo Routine_Error ' See if port already in use. If udtPorts(intPortID).blnPortOpen Then lngStatus = -1 With udtCommError .lngErrorCode = lngStatus .strFunction = "CommOpen" .strErrorMessage = "Port in use." End With GoTo Routine_Exit End If ' Open serial port. udtPorts(intPortID).lngHandle = CreateFile(strPort, GENERIC_READ Or _ GENERIC_WRITE, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) If udtPorts(intPortID).lngHandle = -1 Then lngStatus = SetCommError("CommOpen (CreateFile)") GoTo Routine_Exit End If udtPorts(intPortID).blnPortOpen = True ' Setup device buffers (1K each). lngStatus = SetupComm(udtPorts(intPortID).lngHandle, 1024, 1024) If lngStatus = 0 Then lngStatus = SetCommError("CommOpen (SetupComm)") GoTo Routine_Exit End If ' Purge buffers. lngStatus = PurgeComm(udtPorts(intPortID).lngHandle, PURGE_TXABORT Or _ PURGE_RXABORT Or PURGE_TXCLEAR Or PURGE_RXCLEAR) If lngStatus = 0 Then lngStatus = SetCommError("CommOpen (PurgeComm)") GoTo Routine_Exit End If ' Set serial port timeouts. With udtCommTimeOuts .ReadIntervalTimeout = -1 .ReadTotalTimeoutMultiplier = 0 .ReadTotalTimeoutConstant = 1000 .WriteTotalTimeoutMultiplier = 0 .WriteTotalTimeoutMultiplier = 1000 End With lngStatus = SetCommTimeouts(udtPorts(intPortID).lngHandle, udtCommTimeOuts) If lngStatus = 0 Then lngStatus = SetCommError("CommOpen (SetCommTimeouts)") GoTo Routine_Exit End If ' Get the current state (DCB). lngStatus = GetCommState(udtPorts(intPortID).lngHandle, _ udtPorts(intPortID).udtDCB) If lngStatus = 0 Then lngStatus = SetCommError("CommOpen (GetCommState)") GoTo Routine_Exit End If ' Modify the DCB to reflect the desired settings. lngStatus = BuildCommDCB(strSettings, udtPorts(intPortID).udtDCB) If lngStatus = 0 Then lngStatus = SetCommError("CommOpen (BuildCommDCB)") GoTo Routine_Exit End If ' Set the new state. lngStatus = SetCommState(udtPorts(intPortID).lngHandle, _ udtPorts(intPortID).udtDCB) If lngStatus = 0 Then lngStatus = SetCommError("CommOpen (SetCommState)") GoTo Routine_Exit End If lngStatus = 0 Routine_Exit: CommOpen = lngStatus Exit Function Routine_Error: lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommOpen" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function Private Function SetCommError(strFunction As String) As Long With udtCommError .lngErrorCode = Err.LastDllError .strFunction = strFunction .strErrorMessage = GetSystemMessage(.lngErrorCode) SetCommError = .lngErrorCode End With End Function Private Function SetCommErrorEx(strFunction As String, lngHnd As Long) As Long Dim lngErrorFlags As Long Dim udtCommStat As COMSTAT With udtCommError .lngErrorCode = GetLastError .strFunction = strFunction .strErrorMessage = GetSystemMessage(.lngErrorCode) Call ClearCommError(lngHnd, lngErrorFlags, udtCommStat) .strErrorMessage = .strErrorMessage & " COMM Error Flags = " & _ Hex$(lngErrorFlags) SetCommErrorEx = .lngErrorCode End With End Function '------------------------------------------------------------------------------- ' CommSet - Modifies the serial port settings. ' ' Parameters: ' intPortID - Port ID used when port was opened. ' strSettings - Communication settings. ' Example: "baud=9600 parity=N data=8 stop=1" ' ' Returns: ' Error Code - 0 = No Error. '------------------------------------------------------------------------------- Public Function CommSet(intPortID As Integer, strSettings As String) As Long Dim lngStatus As Long On Error GoTo Routine_Error lngStatus = GetCommState(udtPorts(intPortID).lngHandle, _ udtPorts(intPortID).udtDCB) If lngStatus = 0 Then lngStatus = SetCommError("CommSet (GetCommState)") GoTo Routine_Exit End If lngStatus = BuildCommDCB(strSettings, udtPorts(intPortID).udtDCB) If lngStatus = 0 Then lngStatus = SetCommError("CommSet (BuildCommDCB)") GoTo Routine_Exit End If lngStatus = SetCommState(udtPorts(intPortID).lngHandle, _ udtPorts(intPortID).udtDCB) If lngStatus = 0 Then lngStatus = SetCommError("CommSet (SetCommState)") GoTo Routine_Exit End If lngStatus = 0 Routine_Exit: CommSet = lngStatus Exit Function Routine_Error: lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommSet" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function '------------------------------------------------------------------------------- ' CommClose - Close the serial port. ' ' Parameters: ' intPortID - Port ID used when port was opened. ' ' Returns: ' Error Code - 0 = No Error. '------------------------------------------------------------------------------- Public Function CommClose(intPortID As Integer) As Long Dim lngStatus As Long On Error GoTo Routine_Error If udtPorts(intPortID).blnPortOpen Then lngStatus = CloseHandle(udtPorts(intPortID).lngHandle) If lngStatus = 0 Then lngStatus = SetCommError("CommClose (CloseHandle)") GoTo Routine_Exit End If udtPorts(intPortID).blnPortOpen = False End If lngStatus = 0 Routine_Exit: CommClose = lngStatus Exit Function Routine_Error: lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommClose" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function '------------------------------------------------------------------------------- ' CommFlush - Flush the send and receive serial port buffers. ' ' Parameters: ' intPortID - Port ID used when port was opened. ' ' Returns: ' Error Code - 0 = No Error. '------------------------------------------------------------------------------- Public Function CommFlush(intPortID As Integer) As Long Dim lngStatus As Long On Error GoTo Routine_Error lngStatus = PurgeComm(udtPorts(intPortID).lngHandle, PURGE_TXABORT Or _ PURGE_RXABORT Or PURGE_TXCLEAR Or PURGE_RXCLEAR) If lngStatus = 0 Then lngStatus = SetCommError("CommFlush (PurgeComm)") GoTo Routine_Exit End If lngStatus = 0 Routine_Exit: CommFlush = lngStatus Exit Function Routine_Error: lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommFlush" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function '------------------------------------------------------------------------------- ' CommRead - Read serial port input buffer. ' ' Parameters: ' intPortID - Port ID used when port was opened. ' strData - Data buffer. ' lngSize - Maximum number of bytes to be read. ' ' Returns: ' Error Code - 0 = No Error. '------------------------------------------------------------------------------- Public Function CommRead(intPortID As Integer, strData As String, _ lngSize As Long) As Long Dim lngStatus As Long Dim lngRdSize As Long, lngBytesRead As Long Dim lngRdStatus As Long, strRdBuffer As String * 1024 Dim lngErrorFlags As Long, udtCommStat As COMSTAT On Error GoTo Routine_Error strData = "" lngBytesRead = 0 DoEvents ' Clear any previous errors and get current status. lngStatus = ClearCommError(udtPorts(intPortID).lngHandle, lngErrorFlags, _ udtCommStat) If lngStatus = 0 Then lngBytesRead = -1 lngStatus = SetCommError("CommRead (ClearCommError)") GoTo Routine_Exit End If If udtCommStat.cbInQue > 0 Then If udtCommStat.cbInQue > lngSize Then lngRdSize = udtCommStat.cbInQue Else lngRdSize = lngSize End If Else lngRdSize = 0 End If If lngRdSize Then lngRdStatus = ReadFile(udtPorts(intPortID).lngHandle, strRdBuffer, _ lngRdSize, lngBytesRead, udtCommOverlap) If lngRdStatus = 0 Then lngStatus = GetLastError If lngStatus = ERROR_IO_PENDING Then ' Wait for read to complete. ' This function will timeout according to the ' COMMTIMEOUTS.ReadTotalTimeoutConstant variable. ' Every time it times out, check for port errors. ' Loop until operation is complete. While GetOverlappedResult(udtPorts(intPortID).lngHandle, _ udtCommOverlap, lngBytesRead, True) = 0 lngStatus = GetLastError If lngStatus = ERROR_IO_INCOMPLETE Then lngBytesRead = -1 lngStatus = SetCommErrorEx( _ "CommRead (GetOverlappedResult)", _ udtPorts(intPortID).lngHandle) GoTo Routine_Exit End If Wend Else ' Some other error occurred. lngBytesRead = -1 lngStatus = SetCommErrorEx("CommRead (ReadFile)", _ udtPorts(intPortID).lngHandle) GoTo Routine_Exit End If End If strData = Left$(strRdBuffer, lngBytesRead) End If Routine_Exit: CommRead = lngBytesRead Exit Function Routine_Error: lngBytesRead = -1 lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommRead" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function '------------------------------------------------------------------------------- ' CommWrite - Output data to the serial port. ' ' Parameters: ' intPortID - Port ID used when port was opened. ' strData - Data to be transmitted. ' ' Returns: ' Error Code - 0 = No Error. '------------------------------------------------------------------------------- Public Function CommWrite(intPortID As Integer, strData As String) As Long Dim i As Integer Dim lngStatus As Long, lngSize As Long Dim lngWrSize As Long, lngWrStatus As Long On Error GoTo Routine_Error ' Get the length of the data. lngSize = Len(strData) ' Output the data. lngWrStatus = WriteFile(udtPorts(intPortID).lngHandle, strData, lngSize, _ lngWrSize, udtCommOverlap) ' Note that normally the following code will not execute because the driver ' caches write operations. Small I/O requests (up to several thousand bytes) ' will normally be accepted immediately and WriteFile will return true even ' though an overlapped operation was specified. DoEvents If lngWrStatus = 0 Then lngStatus = GetLastError If lngStatus = 0 Then GoTo Routine_Exit ElseIf lngStatus = ERROR_IO_PENDING Then ' We should wait for the completion of the write operation so we know ' if it worked or not. ' ' This is only one way to do this. It might be beneficial to place the ' writing operation in a separate thread so that blocking on completion ' will not negatively affect the responsiveness of the UI. ' ' If the write takes long enough to complete, this function will timeout ' according to the CommTimeOuts.WriteTotalTimeoutConstant variable. ' At that time we can check for errors and then wait some more. ' Loop until operation is complete. While GetOverlappedResult(udtPorts(intPortID).lngHandle, _ udtCommOverlap, lngWrSize, True) = 0 lngStatus = GetLastError If lngStatus = ERROR_IO_INCOMPLETE Then lngStatus = SetCommErrorEx( _ "CommWrite (GetOverlappedResult)", _ udtPorts(intPortID).lngHandle) GoTo Routine_Exit End If Wend Else ' Some other error occurred. lngWrSize = -1 lngStatus = SetCommErrorEx("CommWrite (WriteFile)", _ udtPorts(intPortID).lngHandle) GoTo Routine_Exit End If End If For i = 1 To 10 DoEvents Next Routine_Exit: CommWrite = lngWrSize Exit Function Routine_Error: lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommWrite" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function '------------------------------------------------------------------------------- ' CommGetLine - Get the state of selected serial port control lines. ' ' Parameters: ' intPortID - Port ID used when port was opened. ' intLine - Serial port line. CTS, DSR, RING, RLSD (CD) ' blnState - Returns state of line (Cleared or Set). ' ' Returns: ' Error Code - 0 = No Error. '------------------------------------------------------------------------------- Public Function CommGetLine(intPortID As Integer, intLine As Integer, _ blnState As Boolean) As Long Dim lngStatus As Long Dim lngComStatus As Long, lngModemStatus As Long On Error GoTo Routine_Error lngStatus = GetCommModemStatus(udtPorts(intPortID).lngHandle, lngModemStatus) If lngStatus = 0 Then lngStatus = SetCommError("CommReadCD (GetCommModemStatus)") GoTo Routine_Exit End If If (lngModemStatus And intLine) Then blnState = True Else blnState = False End If lngStatus = 0 Routine_Exit: CommGetLine = lngStatus Exit Function Routine_Error: lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommReadCD" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function '------------------------------------------------------------------------------- ' CommSetLine - Set the state of selected serial port control lines. ' ' Parameters: ' intPortID - Port ID used when port was opened. ' intLine - Serial port line. BREAK, DTR, RTS ' Note: BREAK actually sets or clears a "break" condition on ' the transmit data line. ' blnState - Sets the state of line (Cleared or Set). ' ' Returns: ' Error Code - 0 = No Error. '------------------------------------------------------------------------------- Public Function CommSetLine(intPortID As Integer, intLine As Integer, _ blnState As Boolean) As Long Dim lngStatus As Long Dim lngNewState As Long On Error GoTo Routine_Error If intLine = LINE_BREAK Then If blnState Then lngNewState = SETBREAK Else lngNewState = CLRBREAK End If ElseIf intLine = LINE_DTR Then If blnState Then lngNewState = SETDTR Else lngNewState = CLRDTR End If ElseIf intLine = LINE_RTS Then If blnState Then lngNewState = SETRTS Else lngNewState = CLRRTS End If End If lngStatus = EscapeCommFunction(udtPorts(intPortID).lngHandle, lngNewState) If lngStatus = 0 Then lngStatus = SetCommError("CommSetLine (EscapeCommFunction)") GoTo Routine_Exit End If lngStatus = 0 Routine_Exit: CommSetLine = lngStatus Exit Function Routine_Error: lngStatus = Err.Number With udtCommError .lngErrorCode = lngStatus .strFunction = "CommSetLine" .strErrorMessage = Err.Description End With Resume Routine_Exit End Function '------------------------------------------------------------------------------- ' CommGetError - Get the last serial port error message. ' ' Parameters: ' strMessage - Error message from last serial port error. ' ' Returns: ' Error Code - Last serial port error code. '------------------------------------------------------------------------------- Public Function CommGetError(strMessage As String) As Long With udtCommError CommGetError = .lngErrorCode strMessage = "Error (" & CStr(.lngErrorCode) & "): " & .strFunction & _ " - " & .strErrorMessage End With End Function