使用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,
0, 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, 0, ThreadWrite, NULL, 0, NULL);
HRead = CreateThread(NULL, 0, ThreadRead, NULL, 0, NULL);
while (1);
CloseHandle(HRead);
CloseHandle(HWrite);
CloseHandle(hCom);
return 0;
}
收發測試圖
- 備注(左邊為自己開發的串口軟件,右邊為正點原子團隊開發的XCOM V2.0串口上位機軟件)