异步方式串口收发数据
2023-06-15
79
0
以下是一个简单的win32串口异步通信程序,该程序使用了Windows API中的CreateIoCompletionPort、CreateFile、SetCommTimeouts、SetCommState、WriteFile和ReadFileEx等函数来进行串口通信。相较于同步通信,异步通信更加灵活高效。
#include <windows.h>
#include <stdio.h>
// 定义串口句柄和IO完成端口句柄
HANDLE hSerial;
HANDLE hIOCP;
// 定义OVERLAPPED结构体
OVERLAPPED overlappedRead;
OVERLAPPED overlappedWrite;
// 定义接收缓冲区和读取缓冲区的大小
char readBuffer[1024];
char writeBuffer[] = "Hello";
// ASCII转换函数
void asciiToHex(char* in, char* out, int length)
{
for (int i = 0; i < length; ++i)
{
out[i] = in[i] & 0x0F;
out[i] += (out[i] < 10 ? '0' : 'A' - 10);
}
}
// 串口接收完成回调函数
VOID CALLBACK readCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
// 指向OVERLAPPED结构体
OVERLAPPED* overlapped = (OVERLAPPED*)lpOverlapped;
// 读取串口数据
if (dwNumberOfBytesTransfered > 0)
{
// 将数据转换成十六进制字符串
char hexBuffer[1024];
asciiToHex(readBuffer, hexBuffer, dwNumberOfBytesTransfered);
// 打印收到的数据
printf("Received data: %s\n", hexBuffer);
}
// 继续读取串口数据
ReadFileEx(hSerial, readBuffer, sizeof(readBuffer), &overlappedRead, readCompletionRoutine);
}
int main()
{
// 创建IO完成端口
hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// 打开串口
hSerial = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hSerial == INVALID_HANDLE_VALUE)
{
printf("Failed to open serial port!\n");
return 1;
}
// 将串口绑定到IO完成端口
CreateIoCompletionPort(hSerial, hIOCP, (DWORD_PTR)hSerial, 0);
// 配置串口参数
DCB serialParams = { 0 };
serialParams.DCBlength = sizeof(serialParams);
GetCommState(hSerial, &serialParams);
serialParams.BaudRate = CBR_115200;
serialParams.ByteSize = 8;
serialParams.Parity = NOPARITY;
serialParams.StopBits = TWOSTOPBITS;
SetCommState(hSerial, &serialParams);
// 配置串口超时时间
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
SetCommTimeouts(hSerial, &timeouts);
// 配置异步读取
memset(&overlappedRead, 0, sizeof(overlappedRead));
overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ReadFileEx(hSerial, readBuffer, sizeof(readBuffer), &overlappedRead, readCompletionRoutine);
// 定时发送5个字符
while (true)
{
// 发送数据到串口
if (WriteFileEx(hSerial, writeBuffer, sizeof(writeBuffer) - 1, &overlappedWrite, NULL))
{
// 打印发送的数据
printf("Sent data: %s\n", writeBuffer);
}
// 暂停1秒钟
Sleep(1000);
}
return 0;
}
上面的代码实现了一个简单的串口异步通信程序,主线程在每个1秒钟定时发送5个字符到串口,接收线程使用了异步读取方式,使用IO完成端口来通知程序串口接收数据完成,并且在回调函数中进行数据处理。异步通信的优点是可以利用操作系统
的资源进行处理,不占用太多CPU资源,能够提高程序的效率和稳定性。需要注意的是,在程序中使用异步通信时,需要使用OVERLAPPED结构体来传递异步操作参数,同时需要使用IOCMP完成端口来管理异步操作和回调函数。回调函数一般都需要在主线程中进行数据处理,因为回调函数是在IOCP线程池中的线程中被调用的,不建议在该线程中直接进行数据处理操作,以免影响程序的响应速度,所以需要在主线程中进行数据处理。