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. 测试步骤
-
硬件连接检查
用万用表检查: - VDD: 3.3V - GND: 0V - SCK: 时钟信号 - CS: 低电平有效 -
软件测试
// 测试代码 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时钟频率,检查接线
浙公网安备 33010602011771号