使用Windows API实现一个简单的串口助手
使用window API开发一个具有字符串收发功能的串口助手
开发环境
- Visual Studio 2015
串口设备相关的API
CreateFile
参数详情见:https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea?redirectedfrom=MSDNSetCommState
参数详情见:https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommstate?redirectedfrom=MSDNGetCommState
参数详情见:https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcommstate?redirectedfrom=MSDNReadFile
参数详情见:https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ee489594(v=winembedded.80)?redirectedfrom=MSDNWriteFile
参数详情见:https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ee490774(v=winembedded.80)?redirectedfrom=MSDNPurgeComm
参数详情见:https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ee488020(v=winembedded.80)?redirectedfrom=MSDNCloseHandle
参数详情见: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串口上位机软件)