M350b版本
This commit is contained in:
20
othersoft/co2correct/CMakeLists.txt
Normal file
20
othersoft/co2correct/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(CO2Correct VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core SerialPort)
|
||||
|
||||
add_executable(CO2Correct
|
||||
main.cpp
|
||||
calibrator.cpp
|
||||
calibrator.h
|
||||
)
|
||||
|
||||
target_link_libraries(CO2Correct
|
||||
Qt5::Core
|
||||
Qt5::SerialPort
|
||||
)
|
||||
136
othersoft/co2correct/README.md
Normal file
136
othersoft/co2correct/README.md
Normal file
@ -0,0 +1,136 @@
|
||||
# CO2传感器校准工具(控制台版)
|
||||
|
||||
基于Qt SerialPort的控制台程序,用于CO2传感器的自动校准。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 串口通信:支持/dev/ttyWind,波特率9600
|
||||
- 自动校准流程:按照标准流程自动执行校准步骤
|
||||
- 校准完成检测:自动检测校准是否完成(检查返回值的最后几个数字是否小于10)
|
||||
- 命令行参数支持:支持命令行参数配置
|
||||
- 自动模式:连接后立即开始校准
|
||||
|
||||
## 校准流程
|
||||
|
||||
1. **初始化**:发送 `$01,TC0`
|
||||
2. **设置模式**:发送 `$01,KY18`
|
||||
3. **第一次校准**:发送 `$01,AC00240^**`(温度值根据实际环境温度设置)
|
||||
4. **再次设置模式**:发送 `$01,KY18`
|
||||
5. **第二次校准**:发送 `$01,AC00240^**`
|
||||
- 检查返回值的最后几个数字是否都小于10
|
||||
- 如果未完成,重复步骤2-3
|
||||
6. **恢复模式**:
|
||||
- 发送 `$01,KY18`
|
||||
- 发送 `$01,TC00001^**`
|
||||
|
||||
## 编译要求
|
||||
|
||||
- Qt6 (Core, SerialPort)
|
||||
- CMake 3.16或更高版本
|
||||
- C++17编译器
|
||||
|
||||
## 编译步骤
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
或者使用构建脚本:
|
||||
|
||||
```bash
|
||||
./build.sh
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 自动模式(推荐)
|
||||
|
||||
连接串口后立即开始校准:
|
||||
|
||||
```bash
|
||||
./build/CO2Correct -a -p /dev/ttyWind -b 9600 -t 24.0
|
||||
```
|
||||
|
||||
参数说明:
|
||||
- `-a, --auto`: 自动模式,连接后立即开始校准
|
||||
- `-p, --port <port>`: 串口设备路径(默认:/dev/ttyWind)
|
||||
- `-b, --baud <baud>`: 波特率(默认:9600)
|
||||
- `-t, --temperature <temp>`: 校准温度,单位℃(默认:24.0)
|
||||
|
||||
### 交互模式
|
||||
|
||||
```bash
|
||||
./build/CO2Correct -p /dev/ttyWind -b 9600
|
||||
```
|
||||
|
||||
然后输入命令:
|
||||
- `start [温度]` - 开始校准(例如:`start 24.0`)
|
||||
- `stop` - 停止校准
|
||||
- `send <命令>` - 手动发送命令(例如:`send $01,TC0`)
|
||||
- `quit` 或 `exit` - 退出程序
|
||||
|
||||
### 查看帮助
|
||||
|
||||
```bash
|
||||
./build/CO2Correct --help
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 示例1:自动校准(温度24.0℃)
|
||||
|
||||
```bash
|
||||
./build/CO2Correct -a -t 24.0
|
||||
```
|
||||
|
||||
### 示例2:指定串口和波特率
|
||||
|
||||
```bash
|
||||
./build/CO2Correct -a -p /dev/ttyUSB0 -b 9600 -t 25.5
|
||||
```
|
||||
|
||||
### 示例3:在远程设备上运行
|
||||
|
||||
```bash
|
||||
# SSH连接到远程设备
|
||||
ssh root@172.16.0.102
|
||||
|
||||
# 运行校准程序
|
||||
cd /path/to/CO2Correct
|
||||
./build/CO2Correct -a -t 24.0
|
||||
```
|
||||
|
||||
## 输出示例
|
||||
|
||||
```
|
||||
[12:34:56.789] [信息] CO2传感器校准工具已启动
|
||||
[12:34:56.790] [成功] 串口已连接: /dev/ttyWind, 波特率: 9600
|
||||
[12:34:56.791] [信息] 开始校准流程,校准温度: 24.0℃ (编码: 00240)
|
||||
[12:34:56.792] [信息] 发送: $01,TC0
|
||||
[12:34:56.850] [信息] 接收: $WI,TC=0
|
||||
[12:34:56.851] [成功] 步骤1完成: TC0设置成功
|
||||
...
|
||||
[12:35:10.123] [成功] 校准完成!所有值均小于10
|
||||
[12:35:10.125] [成功] 步骤7完成: 恢复模式TC设置成功,校准流程全部完成!
|
||||
|
||||
校准流程全部完成!
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 确保传感器已正确连接并上电
|
||||
- 校准温度值需要根据实际环境温度设置
|
||||
- 如果校准未完成,程序会自动重复步骤2-3,直到所有值都小于10
|
||||
- 校准完成后,传感器会自动恢复到正常模式
|
||||
- 程序会自动检测校准是否完成,无需人工干预
|
||||
|
||||
## 远程设备信息
|
||||
|
||||
- 设备IP:172.16.0.102
|
||||
- 用户名:root
|
||||
- 密码:fa
|
||||
|
||||
(可通过SSH连接后执行程序)
|
||||
29
othersoft/co2correct/build.sh
Executable file
29
othersoft/co2correct/build.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# CO2传感器校准工具构建脚本
|
||||
|
||||
echo "开始构建CO2传感器校准工具..."
|
||||
|
||||
# 创建构建目录
|
||||
if [ ! -d "build" ]; then
|
||||
mkdir build
|
||||
fi
|
||||
|
||||
cd build
|
||||
|
||||
# 运行CMake配置
|
||||
echo "运行CMake配置..."
|
||||
cmake ..
|
||||
|
||||
# 编译
|
||||
echo "开始编译..."
|
||||
make
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "构建成功!"
|
||||
echo "可执行文件位置: $(pwd)/CO2Correct"
|
||||
else
|
||||
echo "构建失败!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
478
othersoft/co2correct/calibrator.cpp
Normal file
478
othersoft/co2correct/calibrator.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
#include "calibrator.h"
|
||||
#include <QDateTime>
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
|
||||
Calibrator::Calibrator(QObject *parent)
|
||||
: QObject(parent)
|
||||
, serialPort(new QSerialPort(this))
|
||||
, calibrationTimer(new QTimer(this))
|
||||
, receiveTimeoutTimer(new QTimer(this))
|
||||
, consoleOutput(new QTextStream(stdout))
|
||||
, currentState(Idle)
|
||||
, retryCount(0)
|
||||
, manualMode(false)
|
||||
{
|
||||
connect(serialPort, &QSerialPort::readyRead, this, &Calibrator::onSerialDataReceived);
|
||||
connect(calibrationTimer, &QTimer::timeout, this, &Calibrator::onCalibrationStepTimeout);
|
||||
connect(receiveTimeoutTimer, &QTimer::timeout, this, &Calibrator::onReceiveTimeout);
|
||||
receiveTimeoutTimer->setSingleShot(true);
|
||||
|
||||
logInfo("CO2传感器校准工具已启动");
|
||||
}
|
||||
|
||||
Calibrator::~Calibrator()
|
||||
{
|
||||
if (serialPort->isOpen()) {
|
||||
serialPort->close();
|
||||
}
|
||||
}
|
||||
|
||||
bool Calibrator::connectSerialPort(const QString &portName, int baudRate)
|
||||
{
|
||||
serialPort->setPortName(portName);
|
||||
serialPort->setBaudRate(baudRate);
|
||||
serialPort->setDataBits(QSerialPort::Data8);
|
||||
serialPort->setParity(QSerialPort::NoParity);
|
||||
serialPort->setStopBits(QSerialPort::OneStop);
|
||||
serialPort->setFlowControl(QSerialPort::NoFlowControl);
|
||||
|
||||
if (serialPort->open(QIODevice::ReadWrite)) {
|
||||
logSuccess(QString("串口已连接: %1, 波特率: %2").arg(portName).arg(baudRate));
|
||||
return true;
|
||||
} else {
|
||||
logError(QString("无法打开串口: %1, 错误: %2").arg(portName).arg(serialPort->errorString()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Calibrator::disconnectSerialPort()
|
||||
{
|
||||
if (serialPort->isOpen()) {
|
||||
serialPort->close();
|
||||
logInfo("串口已断开");
|
||||
}
|
||||
if (currentState != Idle) {
|
||||
stopCalibration();
|
||||
}
|
||||
}
|
||||
|
||||
void Calibrator::startCalibration(double temperature)
|
||||
{
|
||||
if (!serialPort->isOpen()) {
|
||||
logError("请先连接串口!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 将温度转换为5位数字格式,例如24.0 -> 00240
|
||||
temperatureValue = QString("%1").arg(static_cast<int>(temperature * 10), 5, 10, QChar('0'));
|
||||
|
||||
logInfo(QString("开始校准流程,校准温度: %1℃ (编码: %2)").arg(temperature).arg(temperatureValue));
|
||||
currentState = Step1_TC0;
|
||||
retryCount = 0;
|
||||
manualMode = false;
|
||||
nextCalibrationStep();
|
||||
}
|
||||
|
||||
void Calibrator::stopCalibration()
|
||||
{
|
||||
currentState = Idle;
|
||||
retryCount = 0;
|
||||
calibrationTimer->stop();
|
||||
logInfo("校准已停止");
|
||||
}
|
||||
|
||||
void Calibrator::sendManualCommand(const QString &command)
|
||||
{
|
||||
if (!serialPort->isOpen()) {
|
||||
logError("请先连接串口!");
|
||||
return;
|
||||
}
|
||||
manualMode = true;
|
||||
sendCommand(command);
|
||||
}
|
||||
|
||||
void Calibrator::onSerialDataReceived()
|
||||
{
|
||||
// 将接收到的数据追加到缓冲区
|
||||
receiveBuffer.append(serialPort->readAll());
|
||||
|
||||
// 重置超时定时器(每次收到新数据都重置)
|
||||
receiveTimeoutTimer->stop();
|
||||
|
||||
// 查找完整的响应(以换行符结尾)
|
||||
while (true) {
|
||||
int lineEnd = -1;
|
||||
int lineLength = 0;
|
||||
|
||||
// 优先查找 \r\n
|
||||
if (receiveBuffer.contains("\r\n")) {
|
||||
lineEnd = receiveBuffer.indexOf("\r\n");
|
||||
lineLength = 2;
|
||||
} else if (receiveBuffer.contains('\n')) {
|
||||
lineEnd = receiveBuffer.indexOf('\n');
|
||||
lineLength = 1;
|
||||
} else if (receiveBuffer.contains('\r')) {
|
||||
lineEnd = receiveBuffer.indexOf('\r');
|
||||
lineLength = 1;
|
||||
}
|
||||
|
||||
if (lineEnd >= 0) {
|
||||
// 提取一行数据(不包含换行符)
|
||||
QByteArray line = receiveBuffer.left(lineEnd);
|
||||
receiveBuffer.remove(0, lineEnd + lineLength);
|
||||
|
||||
QString response = QString::fromUtf8(line).trimmed();
|
||||
|
||||
if (!response.isEmpty()) {
|
||||
logMessage(QString("接收: %1").arg(response));
|
||||
|
||||
if (manualMode) {
|
||||
manualMode = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
processResponse(response);
|
||||
}
|
||||
} else {
|
||||
// 没有找到完整的行,启动超时定时器
|
||||
// 如果200ms内没有新数据到达,认为当前缓冲区中的数据是完整的响应
|
||||
if (!receiveBuffer.isEmpty()) {
|
||||
receiveTimeoutTimer->start(200); // 200ms超时
|
||||
}
|
||||
// 等待更多数据
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Calibrator::onReceiveTimeout()
|
||||
{
|
||||
// 超时后,处理缓冲区中的数据
|
||||
if (!receiveBuffer.isEmpty()) {
|
||||
QString response = QString::fromUtf8(receiveBuffer).trimmed();
|
||||
receiveBuffer.clear();
|
||||
|
||||
if (!response.isEmpty()) {
|
||||
logMessage(QString("接收(超时): %1").arg(response));
|
||||
|
||||
if (manualMode) {
|
||||
manualMode = false;
|
||||
return;
|
||||
}
|
||||
|
||||
processResponse(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Calibrator::onCalibrationStepTimeout()
|
||||
{
|
||||
logError("等待响应超时,重试当前步骤...");
|
||||
retryCount++;
|
||||
if (retryCount > 3) {
|
||||
logError("重试次数过多,停止校准");
|
||||
stopCalibration();
|
||||
emit calibrationFailed("等待响应超时");
|
||||
return;
|
||||
}
|
||||
nextCalibrationStep();
|
||||
}
|
||||
|
||||
void Calibrator::sendCommand(const QString &command)
|
||||
{
|
||||
if (!serialPort->isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString cmd = command;
|
||||
if (!cmd.endsWith("\r\n") && !cmd.endsWith("\n")) {
|
||||
cmd += "\r\n";
|
||||
}
|
||||
|
||||
QByteArray data = cmd.toUtf8();
|
||||
qint64 bytesWritten = serialPort->write(data);
|
||||
|
||||
if (bytesWritten == -1) {
|
||||
logError(QString("发送失败: %1").arg(serialPort->errorString()));
|
||||
} else {
|
||||
logMessage(QString("发送: %1").arg(command));
|
||||
serialPort->flush();
|
||||
}
|
||||
}
|
||||
int timetry=0;
|
||||
void Calibrator::processResponse(const QString &response)
|
||||
{
|
||||
// 如果正在进行校准流程,处理响应
|
||||
if (currentState != Idle) {
|
||||
// 检查响应是否匹配当前步骤的期望响应
|
||||
bool stepComplete = false;
|
||||
|
||||
switch (currentState) {
|
||||
case Step1_TC0:
|
||||
if (response.contains("$WI,TC=0") || response.contains("TC=0")) {
|
||||
stepComplete = true;
|
||||
logSuccess("步骤1完成: TC0设置成功");
|
||||
}
|
||||
break;
|
||||
|
||||
case Step2_KY18_First:
|
||||
if (response.contains("$WI,KY=18") || response.contains("KY=18")) {
|
||||
stepComplete = true;
|
||||
logSuccess("步骤2完成: KY18设置成功");
|
||||
}
|
||||
break;
|
||||
|
||||
case Step3_AC_First:
|
||||
if (response.contains("$WI,AC=") || response.contains("AC=")) {
|
||||
stepComplete = true;
|
||||
QString acValues = extractACValues(response);
|
||||
logSuccess(QString("步骤3完成: 第一次AC校准,返回值: %1").arg(acValues));
|
||||
}
|
||||
break;
|
||||
|
||||
case Step4_KY18_Second:
|
||||
if (response.contains("$WI,KY=18") || response.contains("KY=18")) {
|
||||
stepComplete = true;
|
||||
logSuccess("步骤4完成: 第二次KY18设置成功");
|
||||
}
|
||||
break;
|
||||
|
||||
case Step5_AC_Second:
|
||||
if (response.contains("$WI,AC=") || response.contains("AC=")) {
|
||||
QString acValues = extractACValues(response);
|
||||
logInfo(QString("步骤5: 第二次AC校准,返回值: %1").arg(acValues));
|
||||
|
||||
if (checkCalibrationComplete(response)) {
|
||||
stepComplete = true;
|
||||
logSuccess("校准完成!所有值均小于10");
|
||||
} else {
|
||||
if (timetry>1) {
|
||||
stepComplete = true;
|
||||
logInfo("次数满了");
|
||||
break;
|
||||
}
|
||||
timetry++;
|
||||
|
||||
logInfo("校准未完成,需要重复步骤2-3,等待5秒后重试...");
|
||||
// 重新开始步骤2
|
||||
currentState = Step2_KY18_First;
|
||||
retryCount = 0;
|
||||
calibrationTimer->stop();
|
||||
QTimer::singleShot(5000, this, &Calibrator::nextCalibrationStep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Step6_Restore_KY18:
|
||||
if (response.contains("$WI,KY=18") || response.contains("KY=18")) {
|
||||
stepComplete = true;
|
||||
logSuccess("步骤6完成: 恢复模式KY18设置成功");
|
||||
}
|
||||
break;
|
||||
|
||||
case Step7_Restore_TC:
|
||||
if (response.contains("$WI,TC=00001") || response.contains("TC=00001")) {
|
||||
stepComplete = true;
|
||||
logSuccess("步骤7完成: 恢复模式TC设置成功,校准流程全部完成!");
|
||||
stopCalibration();
|
||||
emit calibrationCompleted();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (stepComplete) {
|
||||
calibrationTimer->stop();
|
||||
retryCount = 0;
|
||||
|
||||
// 更新到下一步状态
|
||||
switch (currentState) {
|
||||
case Step1_TC0:
|
||||
currentState = Step2_KY18_First;
|
||||
break;
|
||||
case Step2_KY18_First:
|
||||
currentState = Step3_AC_First;
|
||||
break;
|
||||
case Step3_AC_First:
|
||||
currentState = Step4_KY18_Second;
|
||||
break;
|
||||
case Step4_KY18_Second:
|
||||
currentState = Step5_AC_Second;
|
||||
break;
|
||||
case Step5_AC_Second:
|
||||
currentState = Step6_Restore_KY18;
|
||||
break;
|
||||
case Step6_Restore_KY18:
|
||||
currentState = Step7_Restore_TC;
|
||||
break;
|
||||
case Step7_Restore_TC:
|
||||
// 已完成,不需要更新状态
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QTimer::singleShot(500, this, &Calibrator::nextCalibrationStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Calibrator::nextCalibrationStep()
|
||||
{
|
||||
if (currentState == Idle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置超时定时器
|
||||
calibrationTimer->stop();
|
||||
calibrationTimer->setSingleShot(true);
|
||||
calibrationTimer->start(5000); // 5秒超时
|
||||
|
||||
switch (currentState) {
|
||||
case Step1_TC0:
|
||||
sendCommand("$01,TC0");
|
||||
break;
|
||||
|
||||
case Step2_KY18_First:
|
||||
sendCommand("$01,KY18");
|
||||
break;
|
||||
|
||||
case Step3_AC_First:
|
||||
{
|
||||
QString acCommand = QString("$01,AC%1^**").arg(temperatureValue);
|
||||
sendCommand(acCommand);
|
||||
}
|
||||
break;
|
||||
|
||||
case Step4_KY18_Second:
|
||||
sendCommand("$01,KY18");
|
||||
break;
|
||||
|
||||
case Step5_AC_Second:
|
||||
{
|
||||
QString acCommand = QString("$01,AC%1^**").arg(temperatureValue);
|
||||
sendCommand(acCommand);
|
||||
}
|
||||
break;
|
||||
|
||||
case Step6_Restore_KY18:
|
||||
sendCommand("$01,KY18");
|
||||
break;
|
||||
|
||||
case Step7_Restore_TC:
|
||||
sendCommand("$01,TC00001^**");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Calibrator::checkCalibrationComplete(const QString &response)
|
||||
{
|
||||
QString acValues = extractACValues(response);
|
||||
return allValuesLessThan10(acValues);
|
||||
}
|
||||
|
||||
QString Calibrator::extractACValues(const QString &response)
|
||||
{
|
||||
// 提取AC=后面的所有值
|
||||
// 格式: $WI,AC=01854,01853,01853,00927,00010,00010,00025,00025,00014,00013
|
||||
QRegularExpression re(R"(\$WI,AC=(.+))");
|
||||
QRegularExpressionMatch match = re.match(response);
|
||||
|
||||
if (!match.hasMatch()) {
|
||||
// 尝试另一种格式
|
||||
re.setPattern(R"(AC=(.+))");
|
||||
match = re.match(response);
|
||||
}
|
||||
|
||||
if (match.hasMatch()) {
|
||||
return match.captured(1);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Calibrator::allValuesLessThan10(const QString &acValues)
|
||||
{
|
||||
if (acValues.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 分割所有值
|
||||
QStringList values = acValues.split(',');
|
||||
|
||||
if (values.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查从第5个值(包含)到最后一个值
|
||||
// 示例: 01094,01094,01091,01094,000474 -> 检查第5个值(000474)
|
||||
// 如果有更多值,检查从第5个到最后一个
|
||||
int startIndex = 4; // 第5个值(索引从0开始,所以是4)
|
||||
|
||||
if (startIndex >= values.size()) {
|
||||
logError(QString("值数量不足5个,无法检查"));
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList checkedValues;
|
||||
for (int i = startIndex; i < values.size(); i++) {
|
||||
QString valueStr = values[i].trimmed();
|
||||
bool ok;
|
||||
int value = valueStr.toInt(&ok);
|
||||
if (!ok) {
|
||||
logError(QString("无法解析值: %1").arg(valueStr));
|
||||
return false;
|
||||
}
|
||||
checkedValues << valueStr;
|
||||
if (value >= 10) {
|
||||
logInfo(QString("检查值: %1 (第%2到最后一个值: %3),值 %4 >= 10,校准未完成")
|
||||
.arg(valueStr)
|
||||
.arg(startIndex + 1)
|
||||
.arg(checkedValues.join(","))
|
||||
.arg(value));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
logSuccess(QString("第%1到最后一个值均小于10 (值: %2),校准完成")
|
||||
.arg(startIndex + 1)
|
||||
.arg(checkedValues.join(",")));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Calibrator::logMessage(const QString &message)
|
||||
{
|
||||
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
|
||||
*consoleOutput << QString("[%1] %2\n").arg(timestamp).arg(message);
|
||||
consoleOutput->flush();
|
||||
}
|
||||
|
||||
void Calibrator::logError(const QString &message)
|
||||
{
|
||||
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
|
||||
*consoleOutput << QString("[%1] [错误] %2\n").arg(timestamp).arg(message);
|
||||
consoleOutput->flush();
|
||||
}
|
||||
|
||||
void Calibrator::logSuccess(const QString &message)
|
||||
{
|
||||
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
|
||||
*consoleOutput << QString("[%1] [成功] %2\n").arg(timestamp).arg(message);
|
||||
consoleOutput->flush();
|
||||
}
|
||||
|
||||
void Calibrator::logInfo(const QString &message)
|
||||
{
|
||||
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
|
||||
*consoleOutput << ("[%1] [信息] %2\n").arg(timestamp).arg(message);
|
||||
consoleOutput->flush();
|
||||
}
|
||||
|
||||
71
othersoft/co2correct/calibrator.h
Normal file
71
othersoft/co2correct/calibrator.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef CALIBRATOR_H
|
||||
#define CALIBRATOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSerialPort>
|
||||
#include <QTimer>
|
||||
#include <QTextStream>
|
||||
#include <QCoreApplication>
|
||||
|
||||
class Calibrator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Calibrator(QObject *parent = nullptr);
|
||||
~Calibrator();
|
||||
|
||||
bool connectSerialPort(const QString &portName, int baudRate = 9600);
|
||||
void disconnectSerialPort();
|
||||
void startCalibration(double temperature);
|
||||
void stopCalibration();
|
||||
void sendManualCommand(const QString &command);
|
||||
bool isConnected() const { return serialPort && serialPort->isOpen(); }
|
||||
|
||||
signals:
|
||||
void calibrationCompleted();
|
||||
void calibrationFailed(const QString &error);
|
||||
|
||||
private slots:
|
||||
void onSerialDataReceived();
|
||||
void onCalibrationStepTimeout();
|
||||
void onReceiveTimeout(); // 接收数据超时处理
|
||||
|
||||
private:
|
||||
QSerialPort *serialPort;
|
||||
QTimer *calibrationTimer;
|
||||
QTimer *receiveTimeoutTimer; // 接收数据超时定时器
|
||||
QTextStream *consoleOutput;
|
||||
QByteArray receiveBuffer; // 接收数据缓冲区
|
||||
|
||||
// 校准状态
|
||||
enum CalibrationState {
|
||||
Idle,
|
||||
Step1_TC0, // 发送TC0
|
||||
Step2_KY18_First, // 第一次发送KY18
|
||||
Step3_AC_First, // 第一次发送AC命令
|
||||
Step4_KY18_Second, // 第二次发送KY18
|
||||
Step5_AC_Second, // 第二次发送AC命令,检查校准结果
|
||||
Step6_Restore_KY18, // 恢复模式:发送KY18
|
||||
Step7_Restore_TC // 恢复模式:发送TC00001
|
||||
};
|
||||
|
||||
CalibrationState currentState;
|
||||
QString temperatureValue; // 校准温度值(如00240表示24.0℃)
|
||||
int retryCount;
|
||||
bool manualMode; // 手动模式标志
|
||||
|
||||
void sendCommand(const QString &command);
|
||||
void processResponse(const QString &response);
|
||||
void nextCalibrationStep();
|
||||
bool checkCalibrationComplete(const QString &response);
|
||||
QString extractACValues(const QString &response);
|
||||
bool allValuesLessThan10(const QString &acValues);
|
||||
void logMessage(const QString &message);
|
||||
void logError(const QString &message);
|
||||
void logSuccess(const QString &message);
|
||||
void logInfo(const QString &message);
|
||||
};
|
||||
|
||||
#endif // CALIBRATOR_H
|
||||
|
||||
99
othersoft/co2correct/main.cpp
Normal file
99
othersoft/co2correct/main.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "calibrator.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QTextStream>
|
||||
#include <QCommandLineParser>
|
||||
#include <QTimer>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
QCoreApplication::setApplicationName("CO2Correct");
|
||||
QCoreApplication::setApplicationVersion("1.0.0");
|
||||
|
||||
QTextStream cout(stdout);
|
||||
QTextStream cin(stdin);
|
||||
|
||||
// 命令行参数解析
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("CO2传感器校准工具");
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
QCommandLineOption portOption(QStringList() << "p" << "port",
|
||||
"串口设备路径", "port", "/dev/ttyWind");
|
||||
parser.addOption(portOption);
|
||||
|
||||
QCommandLineOption baudOption(QStringList() << "b" << "baud",
|
||||
"波特率", "baud", "9600");
|
||||
parser.addOption(baudOption);
|
||||
|
||||
QCommandLineOption tempOption(QStringList() << "t" << "temperature",
|
||||
"校准温度(℃)", "temperature", "24.0");
|
||||
parser.addOption(tempOption);
|
||||
|
||||
QCommandLineOption autoOption(QStringList() << "a" << "auto",
|
||||
"自动模式:连接后立即开始校准");
|
||||
parser.addOption(autoOption);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
QString portName = parser.value(portOption);
|
||||
int baudRate = parser.value(baudOption).toInt();
|
||||
double temperature = parser.value(tempOption).toDouble();
|
||||
bool autoMode = parser.isSet(autoOption);
|
||||
|
||||
Calibrator calibrator;
|
||||
|
||||
// 连接信号
|
||||
QObject::connect(&calibrator, &Calibrator::calibrationCompleted, [&]() {
|
||||
cout << "\n Mission Complete!\n";
|
||||
QTimer::singleShot(1000, &app, &QCoreApplication::quit);
|
||||
});
|
||||
|
||||
QObject::connect(&calibrator, &Calibrator::calibrationFailed, [&](const QString &error) {
|
||||
cout << "\n校准失败: " << error << "\n";
|
||||
QTimer::singleShot(1000, &app, &QCoreApplication::quit);
|
||||
});
|
||||
|
||||
// 连接串口
|
||||
cout << QString("正在连接串口: %1, 波特率: %2...\n").arg(portName).arg(baudRate);
|
||||
if (!calibrator.connectSerialPort(portName, baudRate)) {
|
||||
cout << "串口连接失败,程序退出\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (autoMode) {
|
||||
// 自动模式:立即开始校准
|
||||
cout << QString("自动模式:开始校准,温度: %1℃\n").arg(temperature)<<flush;
|
||||
calibrator.startCalibration(temperature);
|
||||
} else {
|
||||
// 交互模式
|
||||
cout << "\n=== CO2传感器校准工具 ===\n";
|
||||
cout << "串口: " << portName << ", 波特率: " << baudRate << "\n";
|
||||
cout << "\n命令:\n";
|
||||
cout << " start [温度] - 开始校准(默认温度24.0℃)\n";
|
||||
cout << " stop - 停止校准\n";
|
||||
cout << " send <命令> - 手动发送命令\n";
|
||||
cout << " quit/exit - 退出程序\n";
|
||||
cout << "\n提示: 使用 -a 参数可自动模式(连接后立即开始校准)\n";
|
||||
cout << "示例: " << app.applicationName() << " -a -t 24.0\n\n";
|
||||
|
||||
// 在单独的线程中处理输入,或者使用QSocketNotifier
|
||||
// 这里使用简单的提示,建议使用自动模式
|
||||
cout << "注意: 交互模式需要手动输入命令。\n";
|
||||
cout << "建议使用自动模式: " << app.applicationName() << " -a -t " << temperature << "\n";
|
||||
cout << "或者直接开始校准,输入: start " << temperature << "\n\n";
|
||||
|
||||
// 使用QSocketNotifier来非阻塞读取stdin
|
||||
// 简化处理:直接提示用户使用自动模式
|
||||
cout << "等待5秒后自动开始校准(温度: " << temperature << "℃)...\n";
|
||||
cout << "按Ctrl+C可取消\n";
|
||||
|
||||
QTimer::singleShot(5000, [&]() {
|
||||
cout << "\n自动开始校准...\n";
|
||||
calibrator.startCalibration(temperature);
|
||||
});
|
||||
}
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
Reference in New Issue
Block a user