异步方式串口收发数据
在现代软件开发中,串口通信仍然是一个重要的领域,尤其是在嵌入式系统、工业控制和物联网设备中。Windows操作系统提供了一套完整的API来支持串口通信,包括同步和异步两种模式。本文将重点介绍如何在Windows平台上使用异步方式进行串口数据的收发。
-
异步串口通信概述
异步串口通信是指在数据传输过程中,发送方和接收方不需要严格的时钟同步,而是依赖于数据包的起始位和停止位来标识数据的开始和结束。这种方式适用于数据传输速率较低、传输距离较短的场景。 -
异步串口通信的特点
异步串口通信具有以下特点:
字符为单位:以字符为单位进行数据传输。
起始位和停止位:每个字符的开始和结束由起始位和停止位标识。
无外部时钟同步:发送方和接收方不需要外部时钟信号同步。
适用于低速传输:由于每个字符都需要额外的起始位和停止位,因此传输效率相对较低。
3. Windows串口编程API
Windows提供了一系列的API来支持串口编程,包括:
CreateFile:用于打开串口。
CloseHandle:用于关闭串口。
ReadFile和WriteFile:用于同步读取和写入串口数据。
SetCommMask和WaitCommEvent:用于设置串口事件和等待事件。
SetupComm:用于设置串口的输入输出缓冲区大小。
GetCommState和SetCommState:用于获取和设置串口的配置参数。
GetCommTimeouts和SetCommTimeouts:用于获取和设置串口的超时参数。
DeviceIoControl:用于发送IOCTL命令。
4. 异步串口通信的实现
4.1 打开串口
使用CreateFile函数打开串口时,需要指定FILE_FLAG_OVERLAPPED标志以启用异步模式。
HANDLE hSerial = CreateFile(L"COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hSerial == INVALID_HANDLE_VALUE) {
// 打开串口失败处理
}
4.2 配置串口
使用SetCommState函数配置串口的波特率、数据位、停止位和奇偶校验等参数。
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
GetCommState(hSerial, &dcbSerialParams);
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
SetCommState(hSerial, &dcbSerialParams);
4.3 设置异步读写缓冲区
使用SetupComm函数设置串口的输入输出缓冲区大小。
SetupComm(hSerial, 4096, 4096); // 设置输入输出缓冲区大小
4.4 异步读取串口数据
使用ReadFile函数进行异步读取时,需要提供一个OVERLAPPED结构体,并且可以指定一个事件句柄来等待操作完成。
OVERLAPPED overlappedRead;
ZeroMemory(&overlappedRead, sizeof(OVERLAPPED));
overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedRead.hEvent == NULL) {
// 创建事件失败处理
}
DWORD bytesRead;
BOOL bReadStatus = ReadFile(hSerial, buffer, sizeof(buffer), &bytesRead, &overlappedRead);
if (!bReadStatus && GetLastError() != ERROR_IO_PENDING) {
// 读取失败处理
}
4.5 异步发送串口数据
使用WriteFile函数进行异步发送时,同样需要提供一个OVERLAPPED结构体。
OVERLAPPED overlappedWrite;
ZeroMemory(&overlappedWrite, sizeof(OVERLAPPED));
overlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedWrite.hEvent == NULL) {
// 创建事件失败处理
}
DWORD bytesWritten;
BOOL bWriteStatus = WriteFile(hSerial, dataToSend, sizeof(dataToSend), &bytesWritten, &overlappedWrite);
if (!bWriteStatus && GetLastError() != ERROR_IO_PENDING) {
// 发送失败处理
}
4.6 等待异步操作完成
使用WaitForSingleObject或GetOverlappedResult函数等待异步操作完成。
DWORD waitResult = WaitForSingleObject(overlappedRead.hEvent, INFINITE);
if (waitResult == WAIT_OBJECT_0) {
// 读取操作完成
}
// 或者使用GetOverlappedResult函数
if (GetOverlappedResult(hSerial, &overlappedRead, &bytesRead, FALSE)) {
// 读取操作完成
}
4.7 关闭串口
完成串口操作后,应使用CloseHandle函数关闭串口。
CloseHandle(hSerial);
5. 异步串口通信的注意事项
在异步操作中,确保正确处理OVERLAPPED结构体和事件句柄。
使用ClearCommError和GetCommError函数来处理串口错误。
在多线程环境中,注意线程安全和同步问题。
- 点赞
- 收藏
- 关注作者
评论(0)