c++/c 串口读写

4 篇文章 0 订阅
这篇博客介绍了C++中通过Windows API进行串口通信的实现,包括连接端口、写入数据、读取数据的线程处理以及如何设置超时避免线程卡死。在遇到读取数据时可能出现的阻塞问题,作者提出了使用SetupComm和SetCommTimeouts来设定超时值,确保读取操作在一定时间内返回。
摘要由CSDN通过智能技术生成

大致就是以下代码,,串口读写

#include <iostream>
#include "stdlib.h"
#include <string>
#include <Windows.h>
//#include <afx.h>
using namespace std;

HANDLE hcom = 0;//端口
HANDLE tThread;
DWORD threadId = 0;


//连接端口
void connectPort(char* portName){
	/*
	CreateFileA(
	__in     LPCSTR lpFileName,
	__in     DWORD dwDesiredAccess,
	__in     DWORD dwShareMode,
	__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
	__in     DWORD dwCreationDisposition,
	__in     DWORD dwFlagsAndAttributes,
	__in_opt HANDLE hTemplateFile
	);*/
	hcom =CreateFile( portName,//串口名字
		GENERIC_READ|GENERIC_WRITE,//读写权限
		0,	//独占的方式打开
		NULL,//安全参数,默认就行
		OPEN_EXISTING,//打开已经存在的
		0 ,
		NULL
		);
	DCB dcb;//串口通讯中的DCB结构

	memset(&dcb,0,sizeof(dcb));
	GetCommState(hcom,&dcb);

	dcb.DCBlength= sizeof(dcb);//调用setcomm必须要的值
	dcb.BaudRate=9600;//这个必须要和设备那边匹配好;
	dcb.Parity= NOPARITY;//端口数据的校验方法,无校验
	SetCommState(hcom,&dcb);
}
//写数据
void writeData(){
	char datas[] ="往串口里写的数据";
	DWORD lpNumOfByteToWrite;//实际写入的字符数
	WriteFile(hcom,datas,sizeof(datas),&lpNumOfByteToWrite,NULL);
}
//接收串口数据的线程
DWORD WINAPI readThread(LPVOID lpParam ){
	char buff[1024] = {0};
	DWORD ret;
	DWORD byteRead = -1;
	/*
	ReadFile(
	__in        HANDLE hFile, //文件句柄
	__out_bcount_part_opt(nNumberOfBytesToRead, *lpNumberOfBytesRead) __out_data_source(FILE) LPVOID lpBuffer//接收数据用的buff
	__in        DWORD nNumberOfBytesToRead,	//读取的数据量
	__out_opt   LPDWORD lpNumberOfBytesRead,	//实际读取的数据
	__inout_opt LPOVERLAPPED lpOverlapped	//OVERLAPPED 结构,一般设定为 NULL 
	);
	*/
	ret = ReadFile(hcom,buff,sizeof(buff),&byteRead,NULL);

}


//读取数据
void readData(){
	tThread = CreateThread(NULL,0,readThread,hcom,0,&threadId);
	
}
//关闭线程和端口句柄
void closeHandleAndTimer(){
	CloseHandle(hcom);
	TerminateThread(tThread , 0);
	CloseHandle(tThread);
}

获取所有可用串口,下方打印里面的commNam就是我们平时需要的串口名
int main()
{
	HKEY hkey;
	/*打开一个指定的注册表键
	RegOpenKeyExA (
	__in HKEY hKey, //需要打开的主键的名字
	__in_opt LPCSTR lpSubKey, //需要打开的子健的名字
	__in_opt DWORD ulOptions,	//无用
	__in REGSAM samDesired,	// 安全访问标记,也就是权限,读或者写
	__out PHKEY phkResult	//得到的将要打开键的句柄
	);
	*/
	LONG retVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Hardware\\DeviceMap\\SerialComm",NULL, KEY_READ, &hkey);
	if (retVal == ERROR_SUCCESS)
	{
		DWORD comm_index =0;
		char portName[256] = {0};
		char  commNam[256]= {0};
		DWORD dLong,dSize ;
		dLong=dSize=sizeof(portName);
		while (1)
		{
			//枚举结果 返回0标识成功
			/*egEnumValueA (
			__in HKEY hKey,//句柄
			__in DWORD dwIndex,//索引 0开始
			__out_ecount_part_opt(*lpcchValueName, *lpcchValueName + 1) LPSTR lpValueName, //用于装载位于指定索引处值名的一个缓冲区
			__inout LPDWORD lpcchValueName, //指定索引处值名的字符长度
			__reserved LPDWORD lpReserved, //无 
			__out_opt LPDWORD lpType,	//装载值的类型代码的变量 无
			__out_bcount_part_opt(*lpcbData, *lpcbData) __out_data_source(REGISTRY) LPBYTE lpData,串口名
			__inout_opt LPDWORD lpcbData 串口名字的长度
			*/
			retVal = RegEnumValue(hkey,comm_index,portName,&dLong,NULL,NULL,(LPBYTE)commNam,&dSize);
			if (retVal == ERROR_NO_MORE_ITEMS)
			{
				break;
			}
			//我电脑的结果 index =0, portname = \Device\Serial2, dLong = 15 ,commNam=COM3  ,dSize= 5
				
			printf("index =%d, portname = %s, dLong = %d ,commNam=%s  ,dSize= %d ",comm_index,portName,dLong, commNam , dSize);
			comm_index++;
			dLong=dSize=100;
		}

		RegCloseKey(hkey);
	}

	system("pause");
	return 0;
}

2022/1/18 更新

串口读取有时会停在readfile,就不往下执行了,导致线程直接卡死,串口这个时候在等待读取数据,readFile是阻塞的状态。出现这样的情况可以设置一个超时。

SetupComm(hCom, 1024, 1024); //输入缓冲区和输出缓冲区的大小都是1024
	COMMTIMEOUTS TimeOuts;
	TimeOuts.ReadIntervalTimeout = 1000; //设定读超时 
	TimeOuts.ReadTotalTimeoutMultiplier = 2;
	TimeOuts.ReadTotalTimeoutConstant = 500;
	TimeOuts.WriteTotalTimeoutMultiplier = 20; //设定写超时 
	TimeOuts.WriteTotalTimeoutConstant = 30;
	SetCommTimeouts(hCom, &TimeOuts); //设置超时 

读取的时候,buff定的1024,所以在readFile的时候,超时的时间就是2*1024+500,也就是上面的

ReadTotalTimeoutMultiplier*1024 +ReadTotalTimeoutConstant ,大概两秒多的时间,debug一下看到,确实是3秒内就返回了

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值