C++串口通信:打开、读取数据和关闭串口
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 著作权归作者所有。请勿转载和采集!