4. 温度采集模块实现

任务说明

本案例实现BMS(电池管理系统)中的多点温度采集模块,支持最多8个温度传感器通道,完成温度读取、开路/短路故障检测,并对采集到的有效温度执行一致性检查——当最高与最低温度差值超过设定阈值(默认5℃)时,判定为温度不一致并输出告警。

模块设计

温度采集模块由三部分组成:传感器驱动抽象层(模拟NTC热敏电阻经ADC转换后的数字量)、温度计算与滤波(将ADC值转换为摄氏度,并做一阶低通滤波)、一致性检查逻辑(比较各通道有效温度极差)。模块对外提供初始化、单次采集、一致性检查三个接口。

CH0~CH7 ADC 12bit 温度计算 + 滤波 查表 + 一阶低通 开路/短路检测 一致性检查 极差 > 5℃ → 告警 告警 数据流:CHx → ADC → 温度计算/滤波 → 一致性检查 → 告警输出 故障流:开路(ADC≈4095) / 短路(ADC≈0) → 该通道标记无效,不参与一致性比较

代码实现

// temp_module.h
#ifndef TEMP_MODULE_H
#define TEMP_MODULE_H

#include <stdint.h>
#include <stdbool.h>

#define TEMP_MAX_CHANNELS   8
#define TEMP_ADC_FULL_SCALE 4095.0f
#define TEMP_CONSIST_THRESH 5.0f    // 一致性阈值(℃)
#define TEMP_INVALID        (-100.0f) // 无效温度标记

typedef struct {
    float temp_c[TEMP_MAX_CHANNELS];      // 滤波后温度
    bool  fault[TEMP_MAX_CHANNELS];       // true=开路/短路故障
    uint8_t valid_cnt;                    // 有效通道数
    float max_temp;                       // 有效通道最高温
    float min_temp;                       // 有效通道最低温
    bool  inconsistent;                   // 一致性检查结果
} TempModule_t;

void     Temp_Init(TempModule_t *mod);
void     Temp_ProcessChannel(TempModule_t *mod, uint8_t ch, uint16_t adc_raw);
void     Temp_ConsistencyCheck(TempModule_t *mod);

#endif
// temp_module.c
#include "temp_module.h"

#define TEMP_ALPHA 0.2f   // 一阶低通滤波系数

// NTC查表:ADC值 -> 温度(℃),稀疏表+线性插值
static const uint16_t adc_table[] = {400, 800, 1200, 1600, 2000, 2400, 2800, 3200, 3600};
static const float    temp_table[] = {60.0f, 50.0f, 41.0f, 33.0f, 26.0f, 20.0f, 15.0f, 11.0f, 8.0f};
#define TABLE_SIZE (sizeof(adc_table)/sizeof(adc_table[0]))

static float adc_to_temp(uint16_t adc) {
    if (adc <= adc_table[0]) return temp_table[0];
    if (adc >= adc_table[TABLE_SIZE-1]) return temp_table[TABLE_SIZE-1];
    for (uint8_t i = 0; i < TABLE_SIZE-1; i++) {
        if (adc >= adc_table[i] && adc < adc_table[i+1]) {
            float ratio = (float)(adc - adc_table[i]) / (adc_table[i+1] - adc_table[i]);
            return temp_table[i] + ratio * (temp_table[i+1] - temp_table[i]);
        }
    }
    return temp_table[TABLE_SIZE-1];
}

void Temp_Init(TempModule_t *mod) {
    for (uint8_t i = 0; i < TEMP_MAX_CHANNELS; i++) {
        mod->temp_c[i] = 25.0f;   // 默认25℃
        mod->fault[i]  = false;
    }
    mod->valid_cnt    = 0;
    mod->max_temp     = TEMP_INVALID;
    mod->min_temp     = TEMP_INVALID;
    mod->inconsistent = false;
}

void Temp_ProcessChannel(TempModule_t *mod, uint8_t ch, uint16_t adc_raw) {
    if (ch >= TEMP_MAX_CHANNELS) return;

    // 故障检测:开路≈4095,短路≈0(含2%裕量)
    if (adc_raw >= 4015 || adc_raw <= 80) {
        mod->fault[ch] = true;
        mod->temp_c[ch] = TEMP_INVALID;
        return;
    }
    mod->fault[ch] = false;

    // 查表得到瞬时温度,再做一阶低通滤波
    float instant = adc_to_temp(adc_raw);
    mod->temp_c[ch] = mod->temp_c[ch] + TEMP_ALPHA * (instant - mod->temp_c[ch]);
}

void Temp_ConsistencyCheck(TempModule_t *mod) {
    mod->valid_cnt = 0;
    mod->max_temp  = TEMP_INVALID;
    mod->min_temp  = TEMP_INVALID;

    for (uint8_t i = 0; i < TEMP_MAX_CHANNELS; i++) {
        if (mod->fault[i]) continue;   // 故障通道不参与
        if (mod->valid_cnt == 0) {
            mod->max_temp = mod->min_temp = mod->temp_c[i];
        } else {
            if (mod->temp_c[i] > mod->max_temp) mod->max_temp = mod->temp_c[i];
            if (mod->temp_c[i] < mod->min_temp) mod->min_temp = mod->temp_c[i];
        }
        mod->valid_cnt++;
    }

    // 有效通道数≥2才做一致性判定
    if (mod->valid_cnt >= 2) {
        mod->inconsistent = ((mod->max_temp - mod->min_temp) > TEMP_CONSIST_THRESH);
    } else {
        mod->inconsistent = false;   // 有效通道不足,不告警
    }
}
// main.c 示例调用
#include <stdio.h>
#include "temp_module.h"

int main(void) {
    TempModule_t bms_temp;
    Temp_Init(&bms_temp);

    // 模拟一轮采集:8个通道的ADC原始值
    uint16_t adc_samples[TEMP_MAX_CHANNELS] = {
        1800,  // 约29℃
        1850,  // 约28℃
        4090,  // 开路故障
        1750,  // 约30℃
        1900,  // 约27℃
        50,    // 短路故障
        1820,  // 约29℃
        3000   // 约13℃(明显偏低)
    };

    for (uint8_t ch = 0; ch < TEMP_MAX_CHANNELS; ch++) {
        Temp_ProcessChannel(&bms_temp, ch, adc_samples[ch]);
    }
    Temp_ConsistencyCheck(&bms_temp);

    // 打印结果
    printf("有效通道数: %u\n", bms_temp.valid_cnt);
    for (uint8_t i = 0; i < TEMP_MAX_CHANNELS; i++) {
        if (bms_temp.fault[i])
            printf("CH%u: 故障\n", i);
        else
            printf("CH%u: %.1f℃\n", i, bms_temp.temp_c[i]);
    }
    if (bms_temp.valid_cnt >= 2) {
        printf("最高温: %.1f℃, 最低温: %.1f℃, 极差: %.1f℃\n",
               bms_temp.max_temp, bms_temp.min_temp,
               bms_temp.max_temp - bms_temp.min_temp);
    }
    printf("一致性检查: %s\n", bms_temp.inconsistent ? "不一致(告警)" : "一致");

    return 0;
}

编译与运行

# 将上述三个文件置于同一目录,执行:
gcc -Wall -std=c99 main.c temp_module.c -o temp_module
./temp_module

验证方法与判定标准

运行程序后,观察输出:

  • CH2(ADC=4090)与CH5(ADC=50)应显示“故障”,不参与温度统计;
  • 有效通道数为6,最高温约30℃(CH3),最低温约13℃(CH7),极差约17℃,超过5℃阈值;
  • 最终输出“一致性检查: 不一致(告警)”。

若将CH7的ADC值改为1800(约29℃),重新编译运行,则极差约3℃,应输出“一致性检查: 一致”。

判定标准:程序能正确识别开路/短路故障,有效通道统计准确,一致性判定结果与上述预期一致,即视为通过。