前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Win10 串口通信 —— 同步异步

Win10 串口通信 —— 同步异步

作者头像
何其不顾四月天
发布2023-03-10 13:21:06
1.3K0
发布2023-03-10 13:21:06
举报
文章被收录于专栏:四月天的专栏

文章目录

Win10 串口通信 —— 同步/异步

简介

之前接到的一个小项目,好像不能算。win10下的串口通信,不需要界面,排除了Qt,MFC只剩C++ 底层了,调用WindowsApi来实现。翻了翻网上资料大致写出来了。

系统环境:Win10 IDE: VS2017 编译器:MSVC2017/C++11

实现

主要分为接收线程和主线程调度模块,由于没有共用数据体,就没有做线程锁。底层串口模块主要调用 上述git上的源码。WzSerialPort,并做了一些简单修改,实现了异步串口通信。

1.主函数

  • 入口说明 - 提示
代码语言:javascript
复制
void showHelp()
{
	std::cout << " portname(串口名): 在Windows下是\"COM1\"\"COM2\"" << std::endl;
	std::cout << " baudrate(波特率): 9600、19200、38400、43000、56000、57600、115200 " << std::endl;
	std::cout << " parity(校验位): 0为无校验,1为奇校验,2为偶校验,3为标记校验" << std::endl;
	std::cout << " databit(数据位): 4-8(windows),通常为8位" << std::endl;
	std::cout << " stopbit(停止位): 1为1位停止位,2为2位停止位,3为1.5位停止位" << std::endl;
}
  • 入口说明-main函数
代码语言:javascript
复制
	bool isHelp = false;
	std::cout << "请输入是否查看帮助(0:不查看 1:查看):";
	std::cin >> isHelp;
	if (isHelp) showHelp();

	std::string comName;
	std::cout << "请输入串口名称: ";
	std::cin >> comName;

	int bata = 0;
	std::cout << "请输入波特率:";
	std::cin >> bata;
	int checkBit = 0;

	std::cout << "请输入校验位:";
	std::cin >> checkBit;

	std::cout << "数据位默认为:8,停止位默认为:0" << std::endl;
	std::cout << "ComName:" << comName << " BaudRate:" << bata << " Parity:" << checkBit << std::endl;
	std::cout << "" << std::endl;
	std::cout << "---------------------" << std::endl;
  • 入口函数-串口初始化
代码语言:javascript
复制
	WzSerialPort w;
	serialPortInit(w,comName,bata, checkBit);
代码语言:javascript
复制
bool serialPortInit(WzSerialPort &w, std::string  comName, int bata, int checkBit)
{
	bool ret = false;
	if (w.open(comName.c_str(), bata, checkBit, 8, 1, 0))
	{
		ret = true;
		std::cout << "SerialPort Init OK!" << std::endl;
	}
	else
		std::cout << "SerialPort Init Fail!" << std::endl;
	return ret;
}
  • 接收线程 - 因为只是单纯的数据显示,并没有做数据解析
代码语言:javascript
复制
void receiveDemo(WzSerialPort w)
{
	char buf[1024];
	bool runFlag = true;
	while (runFlag)
	{
		if (closeFlag) runFlag = false;
		memset(buf, 0, 1024);
		if(w.receive(buf, 1024))
			std::cout << "接收数据为: " << buf << std::endl;
		Sleep(200);
	}
}
代码语言:javascript
复制
std::thread recv(receiveDemo, w); //线程启动
recv.detach(); //线程分离
  • 主线程-发送
代码语言:javascript
复制
	while (true)
	{
		int type = 0;
		std::cin >>  type;
		if (type == 15)
		{
			closeFlag = true;
			w.close();
			break;
		}
		sendThread(w,type);
	}
	std::cout << "程序退出成功" << std::endl;
代码语言:javascript
复制
void sendThread(WzSerialPort w,int type)
{
	protocol pro;
	getCmdData(pro, type);
	if (sendDemo(w, &pro, sizeof(pro)))
		std::cout << "数据发送完成!发送类型: " << type << " len:" << sizeof(pro) << std::endl;
	else
		std::cout << "数据发送失败!" << std::endl;
	std::cout << "请输入发送类型:" << std::endl;
}
代码语言:javascript
复制
bool sendDemo(WzSerialPort w, const void* buf,int len)
{	
	if (w.send(buf, len) == 0)
	{
		std::cout << "send data fail" << std::endl;
		return false;
	}
	return true;
}
  • 数据结构体、字转换、数据拼装
代码语言:javascript
复制
bool closeFlag = false;
#pragma pack(1) //设置为一字节对齐
typedef struct 
{
	unsigned short header; //数据头
	unsigned char devNo; //设备节点
	unsigned char len; //数据长度
	unsigned char cmd; //命令
	unsigned short data; //数据内容
}protocol,*pProtocol;

//大小端转换函数
unsigned short BLEndianUshort(unsigned short value)
{
	return ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
}
//因为数据格式为固定,这里边就写死了,根据实际需要来做修改。
void getCmdData(protocol &pro, int type)
{
	if (type > 14 || type < 0)
	{
		std::cout << "输入类型错误!请重新输入!" << std::endl;
	}
	pro.header = BLEndianUshort(0XAA96);
	pro.devNo = 0X00;
	pro.len = 0X03;
	pro.cmd = 0X01;
	pro.data = BLEndianUshort(data[type]);
}

2.串口模块

只做一些简单说明,为什么上述博文中说明异步通信为什么没有实现,把错误地方给贴出来修改。

利用WindowsAPI实现,C++实现,在windows系统,移植或者适用匹配度很高。

修改部分,最先测试同步通信一直没有问题,异步通信没有实现。

  • 修改部分 - 头文件说明 – 同步异步 之前为 1异步 0 同步 --实际代码中 1为同步,0为异步,默认同步
代码语言:javascript
复制
	// 打开串口,成功返回true,失败返回false
	// portname(串口名): 在Windows下是"COM1""COM2"等,在Linux下是"/dev/ttyS1"等
	// baudrate(波特率): 9600、19200、38400、43000、56000、57600、115200 
	// parity(校验位): 0为无校验,1为奇校验,2为偶校验,3为标记校验(仅适用于windows)
	// databit(数据位): 4-8(windows),5-8(linux),通常为8位
	// stopbit(停止位): 1为1位停止位,2为2位停止位,3为1.5位停止位
	// synchronizeflag(同步、异步,仅适用与windows): 0为异步,1为同步
	bool open(const char* portname, int baudrate, char parity, char databit, char stopbit, char synchronizeflag=1);
  • 修改部分-发送部分–异步发送一直为失败。 WaitForSingleObject(m_osWrite.hEvent, 1000); 原先为并没有对等待写入事件成功失败处理,主要是成功,成功为发送成功,但返回值还为0.所以在主线程做发送判断时会一直提示失败,此处做修改,实现异步通信
代码语言:javascript
复制
int WzSerialPort::send(const void *buf,int len)
{
	HANDLE hCom = *(HANDLE*)pHandle;

	if (this->synchronizeflag)
	{
		// 同步方式
		DWORD dwBytesWrite = len; //成功写入的数据字节数
		BOOL bWriteStat = WriteFile(hCom, //串口句柄
									buf, //数据首地址
									dwBytesWrite, //要发送的数据字节数
									&dwBytesWrite, //DWORD*,用来接收返回成功发送的数据字节数
									NULL); //NULL为同步发送,OVERLAPPED*为异步发送
		if (!bWriteStat)
		{
			return 0;
		}
		return dwBytesWrite;
	}
	else
	{
		//异步方式
		DWORD dwBytesWrite = len; //成功写入的数据字节数
		DWORD dwErrorFlags; //错误标志
		COMSTAT comStat; //通讯状态
		OVERLAPPED m_osWrite; //异步输入输出结构体

		//创建一个用于OVERLAPPED的事件处理,不会真正用到,但系统要求这么做
		memset(&m_osWrite, 0, sizeof(m_osWrite));
		m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, L"WriteEvent");

		ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通讯错误,获得设备当前状态
		BOOL bWriteStat = WriteFile(hCom, //串口句柄
			buf, //数据首地址
			dwBytesWrite, //要发送的数据字节数
			&dwBytesWrite, //DWORD*,用来接收返回成功发送的数据字节数
			&m_osWrite); //NULL为同步发送,OVERLAPPED*为异步发送
		if (!bWriteStat)
		{
			if (GetLastError() == ERROR_IO_PENDING) //如果串口正在写入
			{
                //WaitForSingleObject(m_osWrite.hEvent, 1000); 原先为并没有对等待写入事件成功失败处理,主要是成功,成功为发送成功,但返回值还为0.所以在主线程做发送判断时会一直提示失败,此处做修改,实现异步通信
				if (WaitForSingleObject(m_osWrite.hEvent, 1000) == WAIT_OBJECT_0) //等待写入事件1秒钟
				{
					bWriteStat = true;	//写入事件完成,修改写入状态
					dwBytesWrite = len; //修改写入字节长度为实际字节长度
				}
			}
			else
			{
				ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通讯错误
				CloseHandle(m_osWrite.hEvent); //关闭并释放hEvent内存
				return 0;
			}
		}
		return dwBytesWrite;
	}
}

```

源码

等待上传中,上传成功做修改。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-08-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • Win10 串口通信 —— 同步/异步
    • 简介
      • 实现
        • 1.主函数
        • 2.串口模块
      • 源码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档