75 lines
2.4 KiB
C++
75 lines
2.4 KiB
C++
/**
|
||
* @file SensorDriver.h
|
||
* @brief UART 空气质量传感器驱动,解析 TVOC / CH₂O / CO₂ 数据帧。
|
||
*
|
||
* 传感器通信协议:
|
||
* 波特率 9600,8N1
|
||
* 数据帧固定 9 字节:
|
||
* B1(0x2C) B2(0xE4) B3(TVOC高) B4(TVOC低) B5(CH2O高) B6(CH2O低)
|
||
* B7(CO2高) B8(CO2低) B9(校验和)
|
||
*
|
||
* 浓度值(mg/m³) = (高字节 × 256 + 低字节) × 0.001
|
||
* 校验和:uint8(B1 + B2 + ... + B8)
|
||
*
|
||
* 硬件接线:
|
||
* 传感器 B(TXD) → ESP32-C3 GPIO0 (UART1_RX)
|
||
* 传感器 A(RXD) → ESP32-C3 GPIO1 (UART1_TX)
|
||
*/
|
||
#ifndef SENSOR_DRIVER_H
|
||
#define SENSOR_DRIVER_H
|
||
|
||
#include <cmath>
|
||
|
||
/// 传感器一次采集的结果
|
||
struct SensorReading {
|
||
float tvoc; ///< TVOC 浓度 (mg/m³),无效时为 NAN
|
||
float ch2o; ///< 甲醛浓度 (mg/m³),无效时为 NAN
|
||
float co2; ///< CO₂ 浓度 (ppm),无效时为 NAN(注意:单位与 TVOC/CH₂O 不同)
|
||
|
||
/// 检查是否所有字段都无效(读取失败时返回全 NAN)
|
||
bool isValid() const {
|
||
return !std::isnan(tvoc) || !std::isnan(ch2o) || !std::isnan(co2);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* @brief UART 空气质量传感器驱动。
|
||
*
|
||
* 使用 ESP-IDF 的 UART 驱动,在 UART1 上以 9600bps 接收传感器帧数据。
|
||
* 传感器会主动推送数据,调用 read() 时从 UART 缓冲区读取并解析最新一帧。
|
||
*/
|
||
class SensorDriver {
|
||
public:
|
||
SensorDriver();
|
||
~SensorDriver();
|
||
|
||
/// 初始化 UART1 硬件(GPIO0=RX, GPIO1=TX, 9600bps, 8N1)
|
||
void init();
|
||
|
||
/**
|
||
* @brief 从 UART 缓冲区读取并解析一帧传感器数据。
|
||
*
|
||
* 读取时会在缓冲区中搜索帧头 0x2C 0xE4,然后读取完整 9 字节帧,
|
||
* 校验和通过后解析为 SensorReading。
|
||
*
|
||
* @param timeoutMs 等待数据的超时时间(毫秒),默认 3000ms
|
||
* @return SensorReading 结构体,读取失败时所有字段为 NAN
|
||
*/
|
||
SensorReading read(int timeoutMs = 3000);
|
||
|
||
private:
|
||
static constexpr int kFrameSize = 9; ///< 数据帧固定 9 字节
|
||
static constexpr uint8_t kHeaderB1 = 0x2C; ///< 帧头字节 1
|
||
static constexpr uint8_t kHeaderB2 = 0xE4; ///< 帧头字节 2
|
||
|
||
/**
|
||
* @brief 将高低字节换算为浓度值。
|
||
* @param high 高字节
|
||
* @param low 低字节
|
||
* @return 浓度值 (mg/m³)
|
||
*/
|
||
float toConcentration(uint8_t high, uint8_t low) const;
|
||
};
|
||
|
||
#endif // SENSOR_DRIVER_H
|