使用Windows API實現一個簡單的串列埠助手
目錄
使用window API開發一個具有字串收發功能的串列埠助手
開發環境
- Visual Studio 2015
串列埠裝置相關的API
-
CreateFile
引數詳情見:https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea?redirectedfrom=MSDN -
SetCommState
引數詳情見:https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommstate?redirectedfrom=MSDN -
GetCommState
引數詳情見:https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcommstate?redirectedfrom=MSDN -
ReadFile
引數詳情見:https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ee489594(v=winembedded.80)?redirectedfrom=MSDN -
WriteFile
引數詳情見:https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ee490774(v=winembedded.80)?redirectedfrom=MSDN -
PurgeComm
引數詳情見:https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ee488020(v=winembedded.80)?redirectedfrom=MSDN -
CloseHandle
引數詳情見:https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ee490442(v=winembedded.80)?redirectedfrom=MSDN
// 函式原型 HANDLE WINAPI CreateFile( _In_ LPCTSTR lpFileName,_In_ DWORD dwDesiredAccess,_In_ DWORD dwShareMode,_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,_In_ DWORD dwCreationDisposition,_In_ DWORD dwFlagsAndAttributes,_In_opt_ HANDLE hTemplateFile ); BOOL WINAPI SetCommState( _In_ HANDLE hFile,_In_ LPDCB lpDCB ); BOOL WINAPI GetCommState( _In_ HANDLE hFile,_Inout_ LPDCB lpDCB ); BOOL ReadFile( HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped ); BOOL WriteFile( HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped ); BOOL PurgeComm( HANDLE hFile,DWORD dwFlags ); BOOL CloseHandle( HANDLE hObject );
步驟
- 建立一個裝置控制代碼
- 建立一個裝置檔案
- 配置串列埠引數
- 建立讀寫執行緒
- 對裝置檔案進行讀寫
- 退出執行緒後關閉裝置檔案
實現程式碼
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
HANDLE hCom; // 控制代碼,用於初始化串列埠
DWORD WINAPI ThreadWrite(LPVOID lpParameter)
{
char outputData[100] = { 0x00 }; // 輸出資料快取
if (hCom == INVALID_HANDLE_VALUE)
{
puts("開啟串列埠失敗");
return 0;
}
DWORD strLength = 0;
while (1)
{
for (int i = 0; i < 100; i++)
{
outputData[i] = 0;
}
fgets(outputData,100,stdin); // 從控制檯輸入字串
strLength = strlen(outputData);
printf("傳送了%d個位元組\r\n",strLength); // 列印字串長度
WriteFile(hCom,outputData,strLength,&strLength,NULL); // 串列埠傳送字串
fflush(stdout);
PurgeComm(hCom,PURGE_TXCLEAR | PURGE_RXCLEAR); // 清空緩衝區
Sleep(100);
}
return 0;
}
DWORD WINAPI ThreadRead(LPVOID lpParameter)
{
// INVALID_HANDLE_VALUE表示出錯,會設定GetLastError
if (hCom == INVALID_HANDLE_VALUE)
{
puts("開啟串列埠失敗");
return 0;
}
char getputData[100] = { 0x00 }; // 輸入資料快取
// 利用錯誤資訊來獲取進入串列埠緩衝區資料的位元組數
DWORD dwErrors; // 錯誤資訊
COMSTAT Rcs; // COMSTAT結構通訊裝置的當前資訊
int Len = 0;
DWORD length = 100; //用來接收讀取的位元組數
while (1)
{
for (int i = 0; i < 100; i++)
{
getputData[i] = 0;
}
ClearCommError(hCom,&dwErrors,&Rcs); // 獲取讀緩衝區資料長度
Len = Rcs.cbInQue;
ReadFile(hCom,getputData,Len,&length,NULL); // 獲取字串
PurgeComm(hCom,PURGE_TXCLEAR | PURGE_RXCLEAR); // 清空緩衝區
if (Len > 0)
{
printf("接收的資料為:%s\r\n",getputData);
fflush(stdout);
}
Sleep(100);
}
return 0;
}
int main()
{
// 初始化串列埠
TCHAR *com_name = (TCHAR *)malloc(10 * sizeof(TCHAR));
do
{
printf("請輸入需要開啟的串列埠號(示例:COM2):");
scanf("%s",com_name);
getchar();
hCom = CreateFile(com_name,GENERIC_READ | GENERIC_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hCom == INVALID_HANDLE_VALUE)
printf("串列埠號不存在,請重新輸入!\n");
else
break;
} while (1);
free(com_name);
// 獲取和設定串列埠引數
DCB myDCB;
myDCB.BaudRate = 115200; // 波特率
myDCB.Parity = NOPARITY; // 校驗位
myDCB.ByteSize = 8; // 資料位
myDCB.StopBits = ONESTOPBIT; // 停止位
SetCommState(hCom,&myDCB); // 設定串列埠引數
printf("baud rate is %d\n",(int)myDCB.BaudRate);
// 執行緒建立
HANDLE HRead,HWrite;
HWrite = CreateThread(NULL,ThreadWrite,NULL);
HRead = CreateThread(NULL,ThreadRead,NULL);
while (1);
CloseHandle(HRead);
CloseHandle(HWrite);
CloseHandle(hCom);
return 0;
}
收發測試圖
- 備註(左邊為自己開發的串列埠軟體,右邊為正點原子團隊開發的XCOM V2.0串列埠上位機軟體)