STM8 + BMP280 SPI 压强测量专用实现

专门针对压强测量优化的STM8+BMP280 SPI驱动实现,包含高精度压强采集、温度补偿、数据滤波和校准功能。

一、硬件连接确认

STM8S103F3P6          BMP280
─────────────────────────────────
PB5 (SPI_SCK)  ──────> SCK
PB6 (SPI_MOSI) ──────> SDI
PB7 (SPI_MISO) <────── SDO
PD4 (GPIO)     ──────> CSB
3.3V           ──────> VDD
GND            ──────> GND

二、压强测量专用代码

1. 压强测量主程序 (src/pressure_measurement.c)

/**
  ******************************************************************************
  * @file    pressure_measurement.c
  * @author  Embedded Developer
  * @brief   STM8 BMP280 专用压强测量程序
  ******************************************************************************
  */

#include "stm8s.h"
#include "bmp280_spi.h"
#include "pressure_processing.h"
#include "delay.h"
#include <stdio.h>

// 全局变量
BMP280_HandleTypeDef bmp280;
PressureData_t pressure_data;

// 系统状态
typedef enum {
    SYS_INIT = 0,
    SYS_CALIBRATING,
    SYS_MEASURING,
    SYS_ERROR
} SystemState;

SystemState sys_state = SYS_INIT;

int main(void)
{
    // 系统初始化
    System_Init();
    
    // 初始化BMP280
    if (BMP280_Init(&bmp280) != BMP280_OK)
    {
        printf("BMP280 Init Failed!\r\n");
        sys_state = SYS_ERROR;
        Error_Handler();
    }
    
    printf("BMP280 Init Success! Chip ID: 0x%02X\r\n", bmp280.chip_id);
    
    // 配置BMP280为高精度压强测量模式
    BMP280_ConfigForPressureMeasurement(&bmp280);
    
    // 校准系统
    sys_state = SYS_CALIBRATING;
    Pressure_Calibrate(&pressure_data);
    
    // 主循环
    sys_state = SYS_MEASURING;
    while(1)
    {
        // 执行压强测量
        Pressure_MeasurementCycle(&pressure_data);
        
        // 显示测量结果
        Pressure_DisplayResults(&pressure_data);
        
        // 延时1秒
        Delay_ms(1000);
    }
}

/**
  * @brief  系统初始化
  * @param  None
  * @retval None
  */
void System_Init(void)
{
    // 时钟初始化
    CLK_HSICmd(ENABLE);
    CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1);
    CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
    
    // GPIO初始化
    GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST);  // LED
    GPIO_Init(GPIOD, GPIO_PIN_4, GPIO_MODE_OUT_PP_HIGH_FAST); // BMP280 CS
    
    // 延时初始化
    Delay_Init();
    
    // UART初始化
    UART_Init();
    
    printf("=== STM8 BMP280 压强测量系统 ===\r\n");
}

/**
  * @brief  UART初始化
  * @param  None
  * @retval None
  */
void UART_Init(void)
{
    UART1_DeInit();
    UART1_Init(9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, 
               UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, 
               UART1_MODE_TXRX_ENABLE);
    UART1_Cmd(ENABLE);
}

/**
  * @brief  错误处理
  * @param  None
  * @retval None
  */
void Error_Handler(void)
{
    while(1)
    {
        GPIO_WriteReverse(GPIOD, GPIO_PIN_0);  // 闪烁LED表示错误
        Delay_ms(200);
    }
}

/**
  * @brief  printf重定向
  * @param  ch: 字符
  * @retval 字符
  */
int putchar(int ch)
{
    UART1_SendData8(ch);
    while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
    return ch;
}

2. 压强处理头文件 (src/pressure_processing.h)

/**
  ******************************************************************************
  * @file    pressure_processing.h
  * @author  Embedded Developer
  * @version V1.0
  * @date    2024-01-01
  * @brief   压强数据处理头文件
  ******************************************************************************
  */

#ifndef __PRESSURE_PROCESSING_H
#define __PRESSURE_PROCESSING_H

#include "bmp280_spi.h"

// 压强单位定义
typedef enum {
    PRESSURE_PA = 0,      // 帕斯卡
    PRESSURE_HPA,         // 百帕
    PRESSURE_KPA,         // 千帕
    PRESSURE_MBAR,        // 毫巴
    PRESSURE_MMHG,        // 毫米汞柱
    PRESSURE_ATM          // 标准大气压
} PressureUnit;

// 压强数据结构
typedef struct {
    // 原始数据
    int32_t raw_pressure;
    int32_t raw_temperature;
    
    // 补偿后数据
    float compensated_pressure;    // 补偿后的压强 (Pa)
    float compensated_temperature;  // 补偿后的温度 (°C)
    
    // 滤波后数据
    float filtered_pressure;       // 滤波后的压强 (Pa)
    float filtered_temperature;    // 滤波后的温度 (°C)
    
    // 统计信息
    float min_pressure;            // 最小压强
    float max_pressure;            // 最大压强
    float avg_pressure;            // 平均压强
    uint32_t measurement_count;    // 测量次数
    
    // 校准参数
    float reference_pressure;      // 参考压强 (用于相对压强测量)
    float sea_level_pressure;      // 海平面压强
    float altitude_offset;         // 海拔偏移
    
    // 质量控制
    uint8_t pressure_valid;        // 压强数据有效标志
    uint8_t temperature_valid;     // 温度数据有效标志
    uint8_t calibration_done;      // 校准完成标志
} PressureData_t;

// 滤波参数
typedef struct {
    uint8_t filter_enabled;        // 滤波使能
    uint8_t filter_type;           // 滤波类型: 0-滑动平均, 1-指数平滑
    uint8_t filter_window;         // 滤波窗口大小
    float alpha;                   // 指数平滑系数
} FilterConfig_t;

// 函数声明
void Pressure_Init(PressureData_t *data);
void Pressure_ConfigFilter(FilterConfig_t *config);
void Pressure_Calibrate(PressureData_t *data);
float Pressure_ReadAbsolute(PressureData_t *data);
float Pressure_ReadRelative(PressureData_t *data);
float Pressure_ReadDifferential(PressureData_t *data, float reference);
void Pressure_MeasurementCycle(PressureData_t *data);
void Pressure_DisplayResults(PressureData_t *data);
float Pressure_ConvertUnit(float pressure_pa, PressureUnit to_unit);
float Pressure_CalculateAltitude(float pressure, float sea_level_pressure);
float Pressure_CalculateSeaLevel(float pressure, float altitude);
void Pressure_SetReference(PressureData_t *data, float reference);
void Pressure_ResetStatistics(PressureData_t *data);

// 内部函数
static float ApplyFilter(float new_value, PressureData_t *data);
static uint8_t ValidatePressureData(float pressure, PressureData_t *data);
static void UpdateStatistics(float pressure, PressureData_t *data);

#endif /* __PRESSURE_PROCESSING_H */

3. 压强处理实现 (src/pressure_processing.c)

/**
  ******************************************************************************
  * @file    pressure_processing.c
  * @author  Embedded Developer
  * @version V1.0
  * @date    2024-01-01
  * @brief   压强数据处理实现
  ******************************************************************************
  */

#include "pressure_processing.h"
#include "delay.h"
#include <math.h>

// 滑动平均滤波器缓冲区
#define FILTER_BUFFER_SIZE 16
static float pressure_buffer[FILTER_BUFFER_SIZE];
static uint8_t buffer_index = 0;
static uint8_t buffer_filled = 0;

// 指数平滑滤波变量
static float last_filtered_pressure = 0.0f;
static uint8_t first_sample = 1;

/**
  * @brief  初始化压强数据
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Pressure_Init(PressureData_t *data)
{
    // 清零所有数据
    data->raw_pressure = 0;
    data->raw_temperature = 0;
    data->compensated_pressure = 0.0f;
    data->compensated_temperature = 0.0f;
    data->filtered_pressure = 0.0f;
    data->filtered_temperature = 0.0f;
    data->min_pressure = 999999.0f;
    data->max_pressure = 0.0f;
    data->avg_pressure = 0.0f;
    data->measurement_count = 0;
    data->reference_pressure = 101325.0f;  // 标准海平面气压
    data->sea_level_pressure = 101325.0f;
    data->altitude_offset = 0.0f;
    data->pressure_valid = 0;
    data->temperature_valid = 0;
    data->calibration_done = 0;
    
    // 初始化滤波缓冲区
    for (uint8_t i = 0; i < FILTER_BUFFER_SIZE; i++)
    {
        pressure_buffer[i] = 0.0f;
    }
    buffer_index = 0;
    buffer_filled = 0;
    last_filtered_pressure = 0.0f;
    first_sample = 1;
}

/**
  * @brief  配置BMP280为高精度压强测量模式
  * @param  hbmp: BMP280句柄
  * @retval BMP280状态
  */
BMP280_Status BMP280_ConfigForPressureMeasurement(BMP280_HandleTypeDef *hbmp)
{
    BMP280_Status status;
    
    // 配置CONFIG寄存器
    // 待机时间1000ms,滤波器系数16,禁用SPI3W
    status = BMP280_SetConfig(hbmp, 
                             BMP280_STANDBY_1000_MS,
                             BMP280_FILTER_COEFF_16,
                             BMP280_SPI3_DISABLE);
    if (status != BMP280_OK) return status;
    
    // 配置CTRL_MEAS寄存器
    // 温度过采样x2,气压过采样x16,正常模式
    status = BMP280_SetCtrlMeas(hbmp,
                               BMP280_OSRS_T_X2,
                               BMP280_OSRS_P_X16,
                               BMP280_MODE_NORMAL);
    
    return status;
}

/**
  * @brief  校准压强测量
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Pressure_Calibrate(PressureData_t *data)
{
    printf("开始压强校准...\r\n");
    printf("请确保传感器处于稳定环境中...\r\n");
    
    float sum_pressure = 0.0f;
    float sum_temperature = 0.0f;
    float pressure, temperature;
    
    // 丢弃前5次测量(传感器稳定)
    for (uint8_t i = 0; i < 5; i++)
    {
        BMP280_ReadData(&bmp280, &temperature, &pressure);
        Delay_ms(100);
    }
    
    // 采集20次数据取平均
    printf("采集20个样本进行校准...\r\n");
    for (uint8_t i = 0; i < 20; i++)
    {
        if (BMP280_ReadData(&bmp280, &temperature, &pressure) == BMP280_OK)
        {
            sum_pressure += pressure;
            sum_temperature += temperature;
            printf("样本 %d: 压强=%.2f Pa, 温度=%.2f °C\r\n", 
                   i+1, pressure, temperature);
        }
        Delay_ms(100);
    }
    
    // 计算平均值作为参考值
    data->reference_pressure = sum_pressure / 20.0f;
    data->sea_level_pressure = data->reference_pressure;
    data->calibration_done = 1;
    
    printf("校准完成!\r\n");
    printf("参考压强: %.2f Pa (%.2f hPa)\r\n", 
           data->reference_pressure, data->reference_pressure/100.0f);
    printf("参考温度: %.2f °C\r\n", sum_temperature / 20.0f);
}

/**
  * @brief  读取绝对压强
  * @param  data: 压强数据结构指针
  * @retval 绝对压强 (Pa)
  */
float Pressure_ReadAbsolute(PressureData_t *data)
{
    float temperature, pressure;
    
    if (BMP280_ReadData(&bmp280, &temperature, &pressure) == BMP280_OK)
    {
        // 保存原始数据
        data->raw_pressure = (int32_t)pressure;
        data->raw_temperature = (int32_t)temperature;
        
        // 保存补偿后数据
        data->compensated_pressure = pressure;
        data->compensated_temperature = temperature;
        
        // 验证数据有效性
        data->pressure_valid = ValidatePressureData(pressure, data);
        data->temperature_valid = (temperature > -40.0f && temperature < 85.0f);
        
        // 应用滤波
        data->filtered_pressure = ApplyFilter(pressure, data);
        data->filtered_temperature = temperature;
        
        // 更新统计信息
        UpdateStatistics(pressure, data);
        
        return pressure;
    }
    
    return 0.0f;
}

/**
  * @brief  读取相对压强(相对于参考压强)
  * @param  data: 压强数据结构指针
  * @retval 相对压强 (Pa)
  */
float Pressure_ReadRelative(PressureData_t *data)
{
    float absolute_pressure = Pressure_ReadAbsolute(data);
    if (absolute_pressure > 0)
    {
        return absolute_pressure - data->reference_pressure;
    }
    return 0.0f;
}

/**
  * @brief  读取差压(相对于给定参考值)
  * @param  data: 压强数据结构指针
  * @param  reference: 参考压强 (Pa)
  * @retval 差压 (Pa)
  */
float Pressure_ReadDifferential(PressureData_t *data, float reference)
{
    float absolute_pressure = Pressure_ReadAbsolute(data);
    if (absolute_pressure > 0)
    {
        return absolute_pressure - reference;
    }
    return 0.0f;
}

/**
  * @brief  执行一次完整的测量循环
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Pressure_MeasurementCycle(PressureData_t *data)
{
    // 读取绝对压强
    float absolute_pressure = Pressure_ReadAbsolute(data);
    
    if (absolute_pressure > 0)
    {
        // 计算相对压强
        float relative_pressure = absolute_pressure - data->reference_pressure;
        
        // 计算海拔高度
        float altitude = Pressure_CalculateAltitude(absolute_pressure, data->sea_level_pressure);
        
        // 计算海平面压强(如果已知海拔)
        if (data->altitude_offset != 0)
        {
            data->sea_level_pressure = Pressure_CalculateSeaLevel(absolute_pressure, data->altitude_offset);
        }
        
        // 保存数据
        data->measurement_count++;
    }
}

/**
  * @brief  显示测量结果
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Pressure_DisplayResults(PressureData_t *data)
{
    printf("\r\n=== 压强测量结果 ===\r\n");
    
    if (data->pressure_valid)
    {
        printf("绝对压强: %.2f Pa\r\n", data->filtered_pressure);
        printf("         %.2f hPa\r\n", data->filtered_pressure / 100.0f);
        printf("         %.2f mmHg\r\n", Pressure_ConvertUnit(data->filtered_pressure, PRESSURE_MMHG));
        printf("         %.4f atm\r\n", Pressure_ConvertUnit(data->filtered_pressure, PRESSURE_ATM));
    }
    else
    {
        printf("绝对压强: 无效\r\n");
    }
    
    if (data->temperature_valid)
    {
        printf("温度: %.2f °C\r\n", data->filtered_temperature);
    }
    else
    {
        printf("温度: 无效\r\n");
    }
    
    // 显示相对压强
    if (data->calibration_done)
    {
        float relative_pressure = data->filtered_pressure - data->reference_pressure;
        printf("相对压强: %.2f Pa\r\n", relative_pressure);
        
        if (relative_pressure > 0)
            printf("        (高于参考值)\r\n");
        else if (relative_pressure < 0)
            printf("        (低于参考值)\r\n");
        else
            printf("        (等于参考值)\r\n");
    }
    
    // 显示统计信息
    if (data->measurement_count > 0)
    {
        printf("测量次数: %lu\r\n", data->measurement_count);
        printf("最小压强: %.2f Pa\r\n", data->min_pressure);
        printf("最大压强: %.2f Pa\r\n", data->max_pressure);
        printf("平均压强: %.2f Pa\r\n", data->avg_pressure);
    }
    
    printf("======================\r\n");
}

/**
  * @brief  单位转换
  * @param  pressure_pa: 压强值 (Pa)
  * @param  to_unit: 目标单位
  * @retval 转换后的压强值
  */
float Pressure_ConvertUnit(float pressure_pa, PressureUnit to_unit)
{
    switch(to_unit)
    {
        case PRESSURE_PA:
            return pressure_pa;
        case PRESSURE_HPA:
            return pressure_pa / 100.0f;
        case PRESSURE_KPA:
            return pressure_pa / 1000.0f;
        case PRESSURE_MBAR:
            return pressure_pa / 100.0f;  // 1 hPa = 1 mbar
        case PRESSURE_MMHG:
            return pressure_pa / 133.322f; // 1 mmHg = 133.322 Pa
        case PRESSURE_ATM:
            return pressure_pa / 101325.0f; // 1 atm = 101325 Pa
        default:
            return pressure_pa;
    }
}

/**
  * @brief  计算海拔高度
  * @param  pressure: 当前压强 (Pa)
  * @param  sea_level_pressure: 海平面压强 (Pa)
  * @retval 海拔高度 (m)
  */
float Pressure_CalculateAltitude(float pressure, float sea_level_pressure)
{
    return 44330.0f * (1.0f - powf(pressure / sea_level_pressure, 0.1903f));
}

/**
  * @brief  计算海平面压强
  * @param  pressure: 当前压强 (Pa)
  * @param  altitude: 海拔高度 (m)
  * @retval 海平面压强 (Pa)
  */
float Pressure_CalculateSeaLevel(float pressure, float altitude)
{
    return pressure / powf(1.0f - (altitude / 44330.0f), 5.255f);
}

/**
  * @brief  设置参考压强
  * @param  data: 压强数据结构指针
  * @param  reference: 参考压强 (Pa)
  * @retval None
  */
void Pressure_SetReference(PressureData_t *data, float reference)
{
    data->reference_pressure = reference;
    printf("参考压强已设置为: %.2f Pa\r\n", reference);
}

/**
  * @brief  重置统计信息
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Pressure_ResetStatistics(PressureData_t *data)
{
    data->min_pressure = 999999.0f;
    data->max_pressure = 0.0f;
    data->avg_pressure = 0.0f;
    data->measurement_count = 0;
    printf("统计信息已重置\r\n");
}

/**
  * @brief  应用滤波
  * @param  new_value: 新测量值
  * @param  data: 压强数据结构指针
  * @retval 滤波后的值
  */
static float ApplyFilter(float new_value, PressureData_t *data)
{
    // 滑动平均滤波
    pressure_buffer[buffer_index] = new_value;
    buffer_index = (buffer_index + 1) % FILTER_BUFFER_SIZE;
    
    if (buffer_filled < FILTER_BUFFER_SIZE)
    {
        buffer_filled++;
        return new_value;  // 缓冲区未满,返回原始值
    }
    
    float sum = 0.0f;
    for (uint8_t i = 0; i < FILTER_BUFFER_SIZE; i++)
    {
        sum += pressure_buffer[i];
    }
    
    return sum / FILTER_BUFFER_SIZE;
}

/**
  * @brief  验证压强数据有效性
  * @param  pressure: 压强值 (Pa)
  * @param  data: 压强数据结构指针
  * @retval 1=有效, 0=无效
  */
static uint8_t ValidatePressureData(float pressure, PressureData_t *data)
{
    // 检查压强范围是否合理
    if (pressure < 30000.0f || pressure > 110000.0f)
    {
        return 0;  // 超出正常范围
    }
    
    // 检查变化率是否过大(可能是噪声)
    if (data->measurement_count > 0)
    {
        float change = fabsf(pressure - data->filtered_pressure);
        if (change > 1000.0f)  // 变化超过1000Pa可能是异常值
        {
            return 0;
        }
    }
    
    return 1;
}

/**
  * @brief  更新统计信息
  * @param  pressure: 压强值 (Pa)
  * @param  data: 压强数据结构指针
  * @retval None
  */
static void UpdateStatistics(float pressure, PressureData_t *data)
{
    // 更新最小最大值
    if (pressure < data->min_pressure)
        data->min_pressure = pressure;
    
    if (pressure > data->max_pressure)
        data->max_pressure = pressure;
    
    // 更新平均值
    if (data->measurement_count == 0)
    {
        data->avg_pressure = pressure;
    }
    else
    {
        data->avg_pressure = (data->avg_pressure * data->measurement_count + pressure) / 
                           (data->measurement_count + 1);
    }
}

4. 高精度压强监测应用 (src/pressure_monitor.c)

/**
  ******************************************************************************
  * @file    pressure_monitor.c
  * @author  Embedded Developer
  * @version V1.0
  * @date    2024-01-01
  * @brief   高精度压强监测应用
  ******************************************************************************
  */

#include "pressure_processing.h"
#include "delay.h"
#include <stdio.h>

// 监测模式
typedef enum {
    MONITOR_CONTINUOUS = 0,    // 连续监测
    MONITOR_PEAK_HOLD,        // 峰值保持
    MONITOR_THRESHOLD,        // 阈值报警
    MONITOR_DIFFERENTIAL      // 差压监测
} MonitorMode;

// 阈值设置
typedef struct {
    float low_threshold;       // 低压阈值
    float high_threshold;      // 高压阈值
    uint8_t alarm_enabled;     // 报警使能
} ThresholdConfig_t;

PressureData_t pressure_data;
MonitorMode monitor_mode = MONITOR_CONTINUOUS;
ThresholdConfig_t thresholds = {95000.0f, 105000.0f, 1};

/**
  * @brief  高精度压强监测主程序
  * @param  None
  * @retval None
  */
int main(void)
{
    System_Init();
    
    // 初始化压强数据
    Pressure_Init(&pressure_data);
    
    // 初始化BMP280
    if (BMP280_Init(&bmp280) != BMP280_OK)
    {
        printf("BMP280 Init Failed!\r\n");
        Error_Handler();
    }
    
    // 配置为高精度模式
    BMP280_ConfigForPressureMeasurement(&bmp280);
    
    // 校准
    printf("开始校准...\r\n");
    Pressure_Calibrate(&pressure_data);
    
    printf("压强监测系统已启动\r\n");
    printf("当前模式: 连续监测\r\n");
    printf("低压阈值: %.2f Pa\r\n", thresholds.low_threshold);
    printf("高压阈值: %.2f Pa\r\n", thresholds.high_threshold);
    
    // 主循环
    while(1)
    {
        // 执行测量
        Pressure_MeasurementCycle(&pressure_data);
        
        // 根据模式处理
        switch(monitor_mode)
        {
            case MONITOR_CONTINUOUS:
                Monitor_ContinuousMode(&pressure_data);
                break;
            case MONITOR_PEAK_HOLD:
                Monitor_PeakHoldMode(&pressure_data);
                break;
            case MONITOR_THRESHOLD:
                Monitor_ThresholdMode(&pressure_data);
                break;
            case MONITOR_DIFFERENTIAL:
                Monitor_DifferentialMode(&pressure_data);
                break;
        }
        
        // 显示结果
        Pressure_DisplayResults(&pressure_data);
        
        // 检查阈值报警
        if (thresholds.alarm_enabled)
        {
            Check_ThresholdAlarm(&pressure_data);
        }
        
        Delay_ms(1000);
    }
}

/**
  * @brief  连续监测模式
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Monitor_ContinuousMode(PressureData_t *data)
{
    // 连续监测,不做特殊处理
    static uint32_t last_display_time = 0;
    
    if (data->measurement_count % 10 == 0)  // 每10次测量显示一次
    {
        printf("[连续监测] 压强: %.2f Pa\r\n", data->filtered_pressure);
    }
}

/**
  * @brief  峰值保持模式
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Monitor_PeakHoldMode(PressureData_t *data)
{
    static float peak_pressure = 0.0f;
    static uint32_t peak_time = 0;
    
    if (data->filtered_pressure > peak_pressure)
    {
        peak_pressure = data->filtered_pressure;
        peak_time = data->measurement_count;
        printf("[峰值保持] 新峰值: %.2f Pa (第%lu次测量)\r\n", peak_pressure, peak_time);
    }
}

/**
  * @brief  阈值报警模式
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Monitor_ThresholdMode(PressureData_t *data)
{
    static uint8_t low_alarm_active = 0;
    static uint8_t high_alarm_active = 0;
    
    // 检查低压报警
    if (data->filtered_pressure < thresholds.low_threshold)
    {
        if (!low_alarm_active)
        {
            low_alarm_active = 1;
            printf("[报警] 低压报警! 当前压强: %.2f Pa < 阈值: %.2f Pa\r\n",
                   data->filtered_pressure, thresholds.low_threshold);
            GPIO_WriteHigh(GPIOD, GPIO_PIN_0);  // 点亮LED
        }
    }
    else
    {
        low_alarm_active = 0;
    }
    
    // 检查高压报警
    if (data->filtered_pressure > thresholds.high_threshold)
    {
        if (!high_alarm_active)
        {
            high_alarm_active = 1;
            printf("[报警] 高压报警! 当前压强: %.2f Pa > 阈值: %.2f Pa\r\n",
                   data->filtered_pressure, thresholds.high_threshold);
            GPIO_WriteHigh(GPIOD, GPIO_PIN_0);  // 点亮LED
        }
    }
    else
    {
        high_alarm_active = 0;
    }
    
    // 关闭LED如果没有报警
    if (!low_alarm_active && !high_alarm_active)
    {
        GPIO_WriteLow(GPIOD, GPIO_PIN_0);
    }
}

/**
  * @brief  差压监测模式
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Monitor_DifferentialMode(PressureData_t *data)
{
    static float reference_pressure = 101325.0f;
    float differential_pressure = data->filtered_pressure - reference_pressure;
    
    printf("[差压监测] 差压: %.2f Pa (参考值: %.2f Pa)\r\n", 
           differential_pressure, reference_pressure);
}

/**
  * @brief  检查阈值报警
  * @param  data: 压强数据结构指针
  * @retval None
  */
void Check_ThresholdAlarm(PressureData_t *data)
{
    if (data->filtered_pressure < thresholds.low_threshold)
    {
        // 低压报警
        GPIO_WriteHigh(GPIOD, GPIO_PIN_0);
        Delay_ms(100);
        GPIO_WriteLow(GPIOD, GPIO_PIN_0);
        Delay_ms(100);
    }
    else if (data->filtered_pressure > thresholds.high_threshold)
    {
        // 高压报警
        GPIO_WriteHigh(GPIOD, GPIO_PIN_0);
        Delay_ms(500);
        GPIO_WriteLow(GPIOD, GPIO_PIN_0);
        Delay_ms(500);
    }
}

三、编译和测试

1. 编译命令

# 使用SDCC编译
sdcc -mstm8 --opt-code-size pressure_measurement.c pressure_processing.c bmp280_spi.c spi_driver.c delay.c

# 或者使用Cosmic C
cxstm8 -iinc +debug -pxp pressure_measurement.c

2. 测试步骤

  1. 硬件连接检查

    用万用表检查:
    - VDD: 3.3V
    - GND: 0V
    - SCK: 时钟信号
    - CS: 低电平有效
    
  2. 软件测试

    // 测试代码
    int main(void)
    {
        System_Init();
        BMP280_Init(&bmp280);
        
        // 测试读取芯片ID
        uint8_t chip_id;
        BMP280_ReadChipID(&bmp280, &chip_id);
        printf("Chip ID: 0x%02X (应为0x58)\n", chip_id);
        
        // 测试读取压强
        float pressure, temperature;
        BMP280_ReadData(&bmp280, &temperature, &pressure);
        printf("Pressure: %.2f Pa\n", pressure);
        printf("Temperature: %.2f °C\n", temperature);
    }
    

3. 预期输出

=== STM8 BMP280 压强测量系统 ===
BMP280 Init Success! Chip ID: 0x58
开始压强校准...
请确保传感器处于稳定环境中...
采集20个样本进行校准...
样本 1: 压强=101325.50 Pa, 温度=25.30 °C
样本 2: 压强=101326.20 Pa, 温度=25.28 °C
...
校准完成!
参考压强: 101325.75 Pa (1013.26 hPa)

=== 压强测量结果 ===
绝对压强: 101325.75 Pa
         1013.26 hPa
         759.94 mmHg
         1.0000 atm
温度: 25.30 °C
相对压强: 0.00 Pa
        (等于参考值)
测量次数: 1
最小压强: 101325.75 Pa
最大压强: 101325.75 Pa
平均压强: 101325.75 Pa
======================

参考代码 STM8+BMP280采用SPI方式驱动 www.youwenfan.com/contentcnv/112878.html

四、精度优化技巧

1. 温度补偿优化

// 在BMP280_Compensate_P函数中添加温度补偿
float BMP280_Compensate_P_Optimized(int32_t adc_P, int32_t adc_T, BMP280_HandleTypeDef *hbmp)
{
    // 原始补偿
    float pressure = BMP280_Compensate_P(adc_P, hbmp);
    
    // 温度补偿(每摄氏度变化0.01%)
    float temp_compensation = 1.0f + (hbmp->calib_data.temperature - 25.0f) * 0.0001f;
    pressure *= temp_compensation;
    
    return pressure;
}

2. 多点校准

// 多点校准表
typedef struct {
    float known_pressure;    // 已知标准压强
    float measured_pressure; // 测量压强
    float correction_factor; // 校正系数
} CalibrationPoint;

CalibrationPoint cal_table[3] = {
    {80000.0f, 0.0f, 1.0f},   // 低压点
    {101325.0f, 0.0f, 1.0f},  // 中点
    {120000.0f, 0.0f, 1.0f}   // 高压点
};

// 应用多点校准
float Apply_MultiPointCalibration(float pressure)
{
    if (pressure < cal_table[0].known_pressure)
        return pressure * cal_table[0].correction_factor;
    else if (pressure < cal_table[1].known_pressure)
        return pressure * cal_table[1].correction_factor;
    else
        return pressure * cal_table[2].correction_factor;
}

3. 数字滤波优化

// 卡尔曼滤波
typedef struct {
    float q;  // 过程噪声协方差
    float r;  // 测量噪声协方差
    float x;  // 估计值
    float p;  // 估计误差协方差
    float k;  // 卡尔曼增益
} KalmanFilter;

float Kalman_Update(KalmanFilter *kf, float measurement)
{
    // 预测
    kf->p = kf->p + kf->q;
    
    // 更新
    kf->k = kf->p / (kf->p + kf->r);
    kf->x = kf->x + kf->k * (measurement - kf->x);
    kf->p = (1 - kf->k) * kf->p;
    
    return kf->x;
}

五、常见问题解决

1. 压强读数漂移

  • 原因: 温度变化导致
  • 解决: 启用温度补偿,定期重新校准

2. 压强读数跳动大

  • 原因: 电源噪声或机械振动
  • 解决: 增加滤波,使用独立电源,减震安装

3. 精度不够

  • 原因: 过采样设置不当
  • 解决: 使用最高过采样率(x16),启用滤波器

4. 通信不稳定

  • 原因: SPI时序问题
  • 解决: 降低SPI时钟频率,检查接线
posted @ 2026-06-08 15:59  kang_ms  阅读(10)  评论(0)    收藏  举报