2026/4/18 11:04:02
网站建设
项目流程
phpcms v9网站地图,海口模板建站平台,网页设计公司婚庆网站模板下载,wordpress重定向传递权重在实际工程中#xff0c;是否使用 Qt 往往并不是技术人员单方面能决定的事情。
常见的限制包括#xff1a;
商业项目对 Qt LGPL / 商业授权 的顾虑项目交付形式不允许引入大型框架甲方或合规部门明确要求 禁止使用 Qt工程本身是纯 C / C 工具链#xff0c;不希望引入额外依赖…在实际工程中是否使用 Qt往往并不是技术人员单方面能决定的事情。常见的限制包括商业项目对Qt LGPL / 商业授权的顾虑项目交付形式不允许引入大型框架甲方或合规部门明确要求禁止使用 Qt工程本身是纯 C / C 工具链不希望引入额外依赖在这种背景下串口通信依然是绕不开的需求。当项目因版权或授权原因不能使用 Qt 时如何在 Windows 平台上用纯 C 实现稳定的串口通信一、为什么不能使用 Qt 会影响串口实现Qt 提供了QSerialPort使用起来非常方便自动管理线程信号槽驱动跨平台但它的前提是项目已经使用 Qt授权模型可接受可以接受引入完整 Qt 运行环境一旦这些前提不成立QSerialPort就不再是可选项。这时唯一可靠的选择就是直接使用 Windows API 提供的串口接口二、Windows 下串口通信的“官方路径”在 Windows 系统中串口本质上是一个设备文件可以像普通文件一样操作。核心 API 包括CreateFile—— 打开串口GetCommState / SetCommState—— 配置串口参数ReadFile / WriteFile—— 数据收发COMMTIMEOUTS—— 读写超时控制这些接口全部属于Windows SDK不涉及任何第三方库或授权问题。三、设计一个可用的纯 C 串口程序在不使用 Qt 的前提下一个实用的串口程序通常需要解决几个问题如何防止程序一启动就退出如何同时进行发送和接收如何在没有控制台窗口的情况下输出调试信息典型做法是使用线程分别处理发送和接收使用WinAPI 事件阻塞主线程使用OutputDebugString输出调试信息四、完整示例纯 C / Windows API 串口通信下面是一份完整、可直接使用的示例代码实现了打开串口定时发送数据接收并打印数据程序长期运行不依赖 Qt示例代码#includewindows.h#includethread#includeatomic#includecstdiostd::atomicboolrunning(true);/*************** 打印工具函数 ***************/voiddebugPrint(constchar*fmt,...){charbuf[512];va_list args;va_start(args,fmt);vsnprintf(buf,sizeof(buf),fmt,args);va_end(args);OutputDebugStringA(buf);}/*************** 串口接收线程 ***************/voidserialReadThread(HANDLE hSerial){charbuffer[256];DWORD bytesRead;while(running){if(ReadFile(hSerial,buffer,sizeof(buffer)-1,bytesRead,NULL)){if(bytesRead0){buffer[bytesRead]\0;debugPrint([RX] %s\n,buffer);}}Sleep(10);}}/*************** 串口发送线程 ***************/voidserialWriteThread(HANDLE hSerial){constchar*msgHello Serial\r\n;DWORD bytesWritten;while(running){BOOL okWriteFile(hSerial,msg,strlen(msg),bytesWritten,NULL);if(okbytesWritten0){debugPrint([TX] %s,msg);}else{debugPrint([TX] 发送失败错误码%lu\n,GetLastError());}Sleep(1000);}}intmain(){// 打开串口HANDLE hSerialCreateFile(L\\\\.\\COM8,// ← 改成你的串口号GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);if(hSerialINVALID_HANDLE_VALUE){debugPrint(串口打开失败错误码%lu\n,GetLastError());return-1;}debugPrint(串口打开成功\n);// 配置串口DCB dcb{0};dcb.DCBlengthsizeof(dcb);GetCommState(hSerial,dcb);dcb.BaudRateCBR_9600;dcb.ByteSize8;dcb.StopBitsONESTOPBIT;dcb.ParityNOPARITY;SetCommState(hSerial,dcb);// 超时COMMTIMEOUTS timeouts{0};timeouts.ReadIntervalTimeout50;timeouts.ReadTotalTimeoutConstant50;timeouts.ReadTotalTimeoutMultiplier10;SetCommTimeouts(hSerial,timeouts);// 启动线程std::threadtRead(serialReadThread,hSerial);std::threadtWrite(serialWriteThread,hSerial);// 主线程永久阻塞HANDLE hEventCreateEvent(NULL,TRUE,FALSE,NULL);WaitForSingleObject(hEvent,INFINITE);runningfalse;tRead.join();tWrite.join();CloseHandle(hSerial);return0;}五、这种方式的优缺点优点不依赖 Qt不涉及授权问题仅使用 Windows 官方 API可用于任何纯 C 工程行为可控、透明缺点代码量明显增加需要手动管理线程和资源不具备跨平台能力六、Qt 仍然有价值但不是唯一解在授权允许、工程条件合适的情况下Qt 的QSerialPort依然是非常优秀的选择代码简洁可维护性高跨平台但当“不能使用 Qt” 成为硬性条件时直接使用 Windows API 并不是退而求其次而是唯一合规且可靠的工程路径。#include QCoreApplication #include QSerialPort #include QSerialPortInfo #include QTimer #include QDebug int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QSerialPort serial; // 1. 串口参数 serial.setPortName(COM8); // 串口号 serial.setBaudRate(QSerialPort::Baud9600); serial.setDataBits(QSerialPort::Data8); serial.setStopBits(QSerialPort::OneStop); serial.setParity(QSerialPort::NoParity); serial.setFlowControl(QSerialPort::NoFlowControl); // 2. 打开串口 if (!serial.open(QIODevice::ReadWrite)) { qDebug() 串口打开失败: serial.errorString(); return -1; } qDebug() 串口打开成功; // 3. 接收数据信号槽 QObject::connect(serial, QSerialPort::readyRead, []() { QByteArray data serial.readAll(); qDebug() [RX] data; }); // 4. 定时发送 QTimer timer; QObject::connect(timer, QTimer::timeout, []() { QByteArray msg Hello Serial; serial.write(msg); qDebug() [TX] msg; }); timer.start(1000); // 1 秒发送一次 return a.exec(); }