WaitCommEvent、SetCommMask方式串口收发数据
2023-06-15
79
0
以下是一个使用WaitCommEvent函数的简单的win32串口通信程序,该程序使用了Windows API中的CreateFile、SetCommTimeouts、SetCommState、.WriteFile和ReadFile等函数来进行串口通信。
#include <windows.h>
#include <stdio.h>
// 定义串口句柄
HANDLE hSerial;
// 定义接收线程函数
DWORD WINAPI receiveThread(LPVOID lpParameter)
{
// 定义变量用于读取串口数据
char buffer[1024];
DWORD bytesRead;
// 设置串口事件掩码
SetCommMask(hSerial, EV_RXCHAR);
// 等待串口事件
while (true)
{
DWORD dwEventMask;
if (WaitCommEvent(hSerial, &dwEventMask, NULL))
{
if (dwEventMask & EV_RXCHAR)
{
// 从串口读取数据
if (ReadFile(hSerial, buffer, sizeof(buffer), &bytesRead, NULL))
{
// 打印收到的数据
printf("Received data: %s\n", buffer);
}
}
}
}
}
int main()
{
// 打开串口
hSerial = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hSerial == INVALID_HANDLE_VALUE)
{
printf("Failed to open serial port!\n");
return 1;
}
// 配置串口参数
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);
// 创建线程用于接收串口数据
HANDLE hThread = CreateThread(NULL, 0, receiveThread, NULL, 0, NULL);
// 定时发送5个字符
while (true)
{
char buffer[] = "Hello";
DWORD bytesWritten;
// 发送数据到串口
if (WriteFile(hSerial, buffer, sizeof(buffer) - 1, &bytesWritten, NULL))
{
// 打印发送的数据
printf("Sent data: %s\n", buffer);
}
// 暂停1秒钟
Sleep(1000);
}
return 0;
}
上面的代码实现了一个简单的串口通信程序,主线程在每个1秒钟定时发送5个字符到串口,接收线程使用了WaitCommEvent函数,等待串口接收事件,如果有数据到达,则从缓冲区读取数据并打印。需要注意的是,由于串口通信时,可能存在不对称的数据发送与接收情况,因此需要对WaitCommEvent函数返回的事件类型进行有效判断,以保证程序的稳定性。
SetCommMask函数的第二个参数是一个掩码,用于指定等待的串口事件类型。其中,串口事件类型定义如下:
常量 | 值 | 描述 |
---|---|---|
EV_RXCHAR | 0x0001 | 接收到一个字符时发送 |
EV_RXFLAG | 0x0002 | 接收到一个指定字符时发送 |
EV_TXEMPTY | 0x0004 | 发送缓冲区为空时发送 |
EV_CTS | 0x0008 | CTS状态改变时发送 |
EV_DSR | 0x0010 | DSR状态改变时发送 |
EV_RLSD | 0x0020 | RLSD状态改变时发送 |
EV_BREAK | 0x0040 | BREAK状态改变时发送 |
EV_ERR | 0x0080 | 发生错误时发送 |
EV_RING | 0x0100 | 接收到一个RING信号时发送 |
EV_RX80FULL | 0x0200 | 接收到大于10个字符或DC1字节时发送 |
EV_EVENT1 | 0x0400 | 事件1,用于扩展事件 |
EV_EVENT2 | 0x0800 | 事件2,用于扩展事件 |
在SetCommMask函数的第二个参数中,可以使用“位或”运算符(|)组合多个事件类型,例如:
DWORD dwMask = EV_RXCHAR | EV_TXEMPTY | EV_ERR;
SetCommMask(hSerial, dwMask);
上面的代码设置了等待串口接收字符事件、串口发送缓冲区为空事件和错误事件,可以根据需要设置不同的事件类型,以实现不同的串口通信功能。