C++串口通信:打开、读取数据和关闭串口

本文介绍了使用C++语言实现串口通信的完整过程,包括打开串口、读取数据和关闭串口。代码示例详细展示了如何使用Win32 API函数进行串口操作,并针对常见问题进行了优化。

1. 打开串口

void Sensor_v1::slot5() //打开串口
{
	//查看所有串口信息
	/*vector<string> vecCom;
	char strCom[255], tempCom[255];
	for (int i = 0; i < 20; i++)
	{
		//strCom.Format("\\.\COM%d", i + 1);
		sprintf_s(strCom, "\\.\COM%d", i + 1);
		sprintf_s(tempCom, "COM%d", i + 1);
		USES_CONVERSION;
		hCom = CreateFile(A2W(strCom), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hCom == INVALID_HANDLE_VALUE) continue;
		else
		{
			vecCom.push_back(strCom);
			
			QString labeltext3 = QStringLiteral("串口状态:打开"), labeltext4 = QString::fromStdString(tempCom);
			ui.label_3->setText(labeltext3);
			ui.label_4->setText(labeltext4);
			QString text = QStringLiteral("串口打开成功!");
			emit sendtext(text); //传出子窗体信号
			newW->show();
			break;
		}
	}*/
	hCom = CreateFile(L"\\.\COM5", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hCom == INVALID_HANDLE_VALUE)
	{
		QString text = QStringLiteral("串口打开失败!");
		emit sendtext(text); //传出子窗体信号
		newW->show();
	}
	else
	{
		QString labeltext3 = QStringLiteral("串口状态:打开"), labeltext4 = QStringLiteral("COM5");
		ui.label_3->setText(labeltext3);
		ui.label_4->setText(labeltext4);
		QString text = QStringLiteral("串口打开成功!");
		emit sendtext(text); //传出子窗体信号
		newW->show();
	}

	//设备属性值 获取+修改+设置
	DCB mDCB;
	GetCommState(hCom, &mDCB);
	mDCB.Parity = NOPARITY;
	mDCB.ByteSize = 8;
	mDCB.StopBits = ONESTOPBIT;
	mDCB.BaudRate = CBR_9600;
	SetCommState(hCom, &mDCB);

	//设置串口写和读的缓冲区大小
	SetupComm(&mDCB, 1024, 1024);

	//设置超时时间
	COMMTIMEOUTS TimeOuts;
	//设定读超时
	TimeOuts.ReadIntervalTimeout = MAXDWORD;//读间隔超时
	TimeOuts.ReadTotalTimeoutMultiplier = 0;//读时间系数
	TimeOuts.ReadTotalTimeoutConstant = 0;//读时间常量
	//设定写超时
	TimeOuts.WriteTotalTimeoutMultiplier = 1;//写时间系数
	TimeOuts.WriteTotalTimeoutConstant = 1;//写时间常量
	SetCommTimeouts(hCom, &TimeOuts); //设置超时

	//在发送和接收前,清空读和写的缓冲区域
	PurgeComm(&mDCB, PURGE_TXCLEAR | PURGE_RXCLEAR);
}

2. 读取数据

void Sensor_v1::slot6() //开始读取数据
{
	BOOL status;
	DWORD bytesRead;
	char requestBuffer[] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x08, 0x44, 0x0C };
	char responseBuffer[256];
	float v[12], vsum = 0;
	int upnum = 0, upvnum = 0;
	int downnum = 0, downvnum = 0;
	//设置表格行数列数
	ui.tableWidget_2->setRowCount(11);
	ui.tableWidget_2->setColumnCount(3);
	//设置表格中每一行的表头
	QString tablehead1 = QStringLiteral("实测值"), tablehead2 = QStringLiteral("理想值"), tablehead3 = QStringLiteral("误差");
	ui.tableWidget_2->setHorizontalHeaderLabels(QStringList() << tablehead1 << tablehead2 << tablehead3);
	//设置表格数据区内的所有单元格双击编辑
	ui.tableWidget_2->setEditTriggers(QAbstractItemView::DoubleClicked);
	//设置列的宽度
	for (int col = 0; col < ui.tableWidget_2->columnCount(); ++col)
	{
		ui.tableWidget_2->setColumnWidth(col, 121);
	}
	while (1)
	{
		// 发送请求数据
		status = WriteFile(hCom, requestBuffer, sizeof(requestBuffer), &bytesRead, NULL);
		if (!status)
		{
			QString text = QStringLiteral("发送请求数据失败!");
			emit sendtext(text); //传出子窗体信号
			newW->show();
			break;
		}
		// 读取响应数据
		status = ReadFile(hCom, responseBuffer, sizeof(responseBuffer), &bytesRead, NULL);
		if (!status)
		{
			QString text = QStringLiteral("读取响应数据失败!");
			emit sendtext(text); //传出子窗体信号
			newW->show();
			break;
		}
		// 输出响应数据
		for (DWORD i = 0; i < bytesRead; i++) printf("Received: %d\n", (int)responseBuffer[i]);
		uint8_t responseBuffer4 = responseBuffer[4];
		uint8_t responseBuffer6 = responseBuffer[6];
		double voltage = (responseBuffer[3] << 8) | responseBuffer4;// 转换为实际电压值
		double flag = (responseBuffer[5] << 8) | responseBuffer6;// 转换为实际电压值
		if (flag > 3300)
		{
			upvnum++;
			downvnum = 0;
			if (upnum <= 11)
			{
				if (upvnum == 1) upnum++;
				vsum += voltage;
				//设置表格数据
				v[upnum] = vsum / upvnum;
				//设置表格中每一行的内容
				ui.tableWidget_2->setItem(upnum - 1, 0, new QTableWidgetItem(QString::number(v[upnum])));
			}
			else break;
		}
		else
		{
			downvnum++;
			upvnum = 0;
			if (downvnum == 1) downnum++;
			if (downnum == 12) break;
			vsum = 0;
		}
		Sleep(50);
	}

	float k = (v[11] - v[1]) / 10;
	for (int i = 1; i <= 11; i++)
	{
		s[i] = v[1] + (i - 1) * k;
		vs[i] = s[i] - v[i];
		ui.tableWidget_2->setItem(i - 1, 1, new QTableWidgetItem(QString::number(s[i])));
		ui.tableWidget_2->setItem(i - 1, 2, new QTableWidgetItem(QString::number(vs[i])));
	}
}

3. 关闭串口

void Sensor_v1::slot7() //关闭串口
{
	CloseHandle(hCom);
	QString labeltext3 = QStringLiteral("串口状态:关闭");
	ui.label_3->setText(labeltext3);
	QString text = QStringLiteral("串口关闭成功!");
	emit sendtext(text); //传出子窗体信号
	newW->show();

	// 打开串口
	hCom = CreateFile(L"\\.\COM5", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hCom == INVALID_HANDLE_VALUE)
	{
		QString text = QStringLiteral("串口打开失败!");
		emit sendtext(text); //传出子窗体信号
		newW->show();
	}
	else
	{
		QString labeltext3 = QStringLiteral("串口状态:打开"), labeltext4 = QStringLiteral("COM5");
		ui.label_3->setText(labeltext3);
		ui.label_4->setText(labeltext4);
		QString text = QStringLiteral("串口打开成功!");
		emit sendtext(text); //传出子窗体信号
		newW->show();
	}

	//设备属性值 获取+修改+设置
	DCB mDCB;
	GetCommState(hCom, &mDCB);
	mDCB.Parity = NOPARITY;
	mDCB.ByteSize = 8;
	mDCB.StopBits = ONESTOPBIT;
	mDCB.BaudRate = CBR_9600;
	SetCommState(hCom, &mDCB);

	//设置串口写和读的缓冲区大小
	SetupComm(&mDCB, 1024, 1024);

	//设置超时时间
	COMMTIMEOUTS TimeOuts;
	//设定读超时
	TimeOuts.ReadIntervalTimeout = MAXDWORD;//读间隔超时
	TimeOuts.ReadTotalTimeoutMultiplier = 0;//读时间系数
	TimeOuts.ReadTotalTimeoutConstant = 0;//读时间常量
	//设定写超时
	TimeOuts.WriteTotalTimeoutMultiplier = 1;//写时间系数
	TimeOuts.WriteTotalTimeoutConstant = 1;//写时间常量
	SetCommTimeouts(hCom, &TimeOuts); //设置超时

	//在发送和接收前,清空读和写的缓冲区域
	PurgeComm(&mDCB, PURGE_TXCLEAR | PURGE_RXCLEAR);
}

总结

本文介绍了使用C++语言实现串口通信的基本步骤。在实际应用中,可以根据不同的需求进行调整和扩展。例如,可以根据实际情况选择不同的串口参数、发送和接收不同的数据格式、以及处理不同的异常情况。

希望本文对您有所帮助。如果您有任何问题,请随时提问。


原文地址: https://www.cveoy.top/t/topic/qiiI 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录