大家好,我是專注分享職業(yè)規(guī)劃/技術(shù)科普/智能生活有關(guān)原創(chuàng)文章的allen康哥。嵌入式開發(fā)其實(shí)某種意義上來說就是傳感器的使用,所以今天就總結(jié)分享7種常用的傳感器應(yīng)用場景以及單片機(jī)例程,僅供參看。
1.溫濕度傳感器 DHT11
應(yīng)用場景
智能家居:溫濕度聯(lián)動空調(diào)/加濕器(如米家溫濕度計(jì))
農(nóng)業(yè)大棚:環(huán)境監(jiān)控系統(tǒng)(閾值觸發(fā)通風(fēng)/噴淋)
冷鏈運(yùn)輸:藥品/食品運(yùn)輸箱溫濕度記錄
STM32例程
#include?"main.h"
#include?<stdio.h>
#define?DHT11_PORT GPIOA
#define?DHT11_PIN ?GPIO_PIN_0
TIM_HandleTypeDef htim2; ?// 需要配置一個(gè)基本定時(shí)器
// 微秒延時(shí)函數(shù)(需要配置一個(gè)基本定時(shí)器,比如TIM2)
void?Delay_us(uint16_t?us)
{
? ? __HAL_TIM_SET_COUNTER(&htim2,?0);
? ? HAL_TIM_Base_Start(&htim2);
? ??while(__HAL_TIM_GET_COUNTER(&htim2) < us);
? ? HAL_TIM_Base_Stop(&htim2);
}
// 初始化DHT11
void?DHT11_Init(void)
{
? ? GPIO_InitTypeDef GPIO_InitStruct = {0};
? ? GPIO_InitStruct.Pin = DHT11_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
? ? GPIO_InitStruct.Pull = GPIO_NOPULL;
? ? GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
? ? HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
? ? HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);?// 拉高總線
}
// 讀取DHT11數(shù)據(jù)
uint8_t?DHT11_Read(float?*temp,?float?*humi)
{
? ??uint8_t?data[5] = {0};
? ??uint8_t?retry =?0;
? ??
? ??// 發(fā)送開始信號
? ? HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
? ? HAL_Delay(18); ?// 拉低至少18ms
? ? HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
? ??
? ??// 切換為輸入模式
? ? GPIO_InitTypeDef GPIO_InitStruct = {0};
? ? GPIO_InitStruct.Pin = DHT11_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
? ? GPIO_InitStruct.Pull = GPIO_PULLUP;
? ? HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
? ??
? ??// 等待DHT11響應(yīng)
? ? Delay_us(40); ?// 等待20-40us
? ??if(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET)
? ? {
? ? ? ??// 等待80us低電平
? ? ? ??while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET && retry <?100)
? ? ? ? {
? ? ? ? ? ? retry++;
? ? ? ? ? ? Delay_us(1);
? ? ? ? }
? ? ? ? retry =?0;
? ? ? ??// 等待80us高電平
? ? ? ??while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET && retry <?100)
? ? ? ? {
? ? ? ? ? ? retry++;
? ? ? ? ? ? Delay_us(1);
? ? ? ? }
? ? ? ??
? ? ? ??// 開始接收數(shù)據(jù)
? ? ? ??for(uint8_t?i=0; i<40; i++)
? ? ? ? {
? ? ? ? ? ? retry =?0;
? ? ? ? ? ??while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET && retry <?100)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? retry++;
? ? ? ? ? ? ? ? Delay_us(1);
? ? ? ? ? ? }
? ? ? ? ? ??
? ? ? ? ? ??uint32_t?time =?0;
? ? ? ? ? ? retry =?0;
? ? ? ? ? ??while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET && retry <?100)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? retry++;
? ? ? ? ? ? ? ? Delay_us(1);
? ? ? ? ? ? ? ? time++;
? ? ? ? ? ? }
? ? ? ? ? ??
? ? ? ? ? ? data[i/8] <<=?1;
? ? ? ? ? ??if(time >?30)?// 高電平持續(xù)時(shí)間大于30us表示'1'
? ? ? ? ? ? {
? ? ? ? ? ? ? ? data[i/8] |=?1;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ??
? ? ? ??// 校驗(yàn)數(shù)據(jù)
? ? ? ??if(data[4] == (data[0] + data[1] + data[2] + data[3]))
? ? ? ? {
? ? ? ? ? ? *humi = data[0] + data[1] *?0.1;
? ? ? ? ? ? *temp = data[2] + data[3] *?0.1;
? ? ? ? ? ??return0;?// 成功
? ? ? ? }
? ? }
? ??return1;?// 失敗
}
// 主函數(shù)示例
int?main(void)
{
? ? HAL_Init();
? ? SystemClock_Config();
? ? MX_TIM2_Init();?// 初始化定時(shí)器
? ? DHT11_Init();
? ??
? ??float?temperature, humidity;
? ??
? ??while(1)
? ? {
? ? ? ??if(DHT11_Read(&temperature, &humidity) ==?0)
? ? ? ? {
? ? ? ? ? ??printf("Temperature: %.1f Crn", temperature);
? ? ? ? ? ??printf("Humidity: %.1f %%rn", humidity);
? ? ? ? }
? ? ? ??else
? ? ? ? {
? ? ? ? ? ??printf("Sensor read failed!rn");
? ? ? ? }
? ? ? ? HAL_Delay(2000);?// 2秒讀取一次
? ? }
}
2.溫度傳感器 DS18B20
應(yīng)用場景
工業(yè)設(shè)備:電機(jī)/變壓器溫度監(jiān)控
醫(yī)療設(shè)備:血液存儲箱溫度監(jiān)測
STM32例程(單總線協(xié)議)
#include?"main.h"
#include?<stdio.h>
#define?DS18B20_PORT GPIOA
#define?DS18B20_PIN ?GPIO_PIN_0
TIM_HandleTypeDef htim2; ?// 用于微秒延時(shí)的基礎(chǔ)定時(shí)器
/* 微秒延時(shí)函數(shù)(需要配置定時(shí)器,例如TIM2) */
void?Delay_us(uint16_t?us)
{
? ? __HAL_TIM_SET_COUNTER(&htim2,?0);
? ? HAL_TIM_Base_Start(&htim2);
? ??while(__HAL_TIM_GET_COUNTER(&htim2) < us);
? ? HAL_TIM_Base_Stop(&htim2);
}
/* 單總線初始化 */
uint8_t?DS18B20_Reset(void)
{
? ??uint8_t?status =?0;
? ??
? ??// 配置為輸出模式
? ? GPIO_InitTypeDef GPIO_InitStruct = {0};
? ? GPIO_InitStruct.Pin = DS18B20_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
? ? GPIO_InitStruct.Pull = GPIO_NOPULL;
? ? GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
? ? HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
? ??
? ??// 拉低總線480us
? ? HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
? ? Delay_us(480);
? ??
? ??// 釋放總線,切換為輸入模式
? ? HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
? ? GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
? ? GPIO_InitStruct.Pull = GPIO_PULLUP;
? ? HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
? ??
? ??// 檢測存在脈沖(60-240us低電平)
? ? Delay_us(60);
? ??if(!HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN)) status =?1;
? ? Delay_us(240);
? ??
? ??return?status;?// 返回1表示檢測到設(shè)備
}
/* 寫入1位數(shù)據(jù) */
void?DS18B20_WriteBit(uint8_t?bit)
{
? ? GPIO_InitTypeDef GPIO_InitStruct = {0};
? ? GPIO_InitStruct.Pin = DS18B20_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
? ? GPIO_InitStruct.Pull = GPIO_NOPULL;
? ? HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
? ??
? ? HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
? ??if(bit) {
? ? ? ? Delay_us(5); ??// 1-15us低電平表示寫1
? ? ? ? HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
? ? ? ? Delay_us(60);
? ? }?else?{
? ? ? ? Delay_us(60); ?// 60us低電平表示寫0
? ? ? ? HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
? ? ? ? Delay_us(5);
? ? }
}
/* 寫入1字節(jié)數(shù)據(jù) */
void?DS18B20_WriteByte(uint8_t?data)
{
? ??for(uint8_t?i=0; i<8; i++){
? ? ? ? DS18B20_WriteBit(data &?0x01);
? ? ? ? data >>=?1;
? ? }
}
/* 讀取1位數(shù)據(jù) */
uint8_t?DS18B20_ReadBit(void)
{
? ??uint8_t?bit =?0;
? ??
? ??// 配置為輸出模式
? ? GPIO_InitTypeDef GPIO_InitStruct = {0};
? ? GPIO_InitStruct.Pin = DS18B20_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
? ? GPIO_InitStruct.Pull = GPIO_NOPULL;
? ? HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
? ??
? ??// 產(chǎn)生讀時(shí)隙
? ? HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
? ? Delay_us(2);
? ? HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
? ??
? ??// 切換為輸入模式
? ? GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
? ? GPIO_InitStruct.Pull = GPIO_PULLUP;
? ? HAL_GPIO_Init(DS18B20_PORT, &GPIO_InitStruct);
? ??
? ? Delay_us(10);
? ? bit = HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN);
? ? Delay_us(50);
? ??
? ??return?bit;
}
/* 讀取1字節(jié)數(shù)據(jù) */
uint8_t?DS18B20_ReadByte(void)
{
? ??uint8_t?data =?0;
? ??for(uint8_t?i=0; i<8; i++){
? ? ? ? data >>=?1;
? ? ? ??if(DS18B20_ReadBit()) data |=?0x80;
? ? }
? ??return?data;
}
/* 讀取溫度值 */
float?DS18B20_ReadTemp(void)
{
? ??if(DS18B20_Reset() ==?0)?return-999;?// 設(shè)備未響應(yīng)
? ??
? ? DS18B20_WriteByte(0xCC); ?// 跳過ROM指令
? ? DS18B20_WriteByte(0x44); ?// 啟動溫度轉(zhuǎn)換
? ? Delay_us(800000); ? ? ? ??// 等待轉(zhuǎn)換完成(最大750ms)
? ??
? ??if(DS18B20_Reset() ==?0)?return-999;
? ??
? ? DS18B20_WriteByte(0xCC); ?// 跳過ROM指令
? ? DS18B20_WriteByte(0xBE); ?// 讀取暫存器
? ??
? ??uint8_t?temp_l = DS18B20_ReadByte();
? ??uint8_t?temp_h = DS18B20_ReadByte();
? ??
? ??int16_t?temp = (temp_h <<?8) | temp_l;
? ??return?temp *?0.0625; ? ??// 12位精度時(shí)的分辨率
}
/* 主函數(shù)示例 */
int?main(void)
{
? ? HAL_Init();
? ? SystemClock_Config();
? ? MX_TIM2_Init(); ?// 初始化定時(shí)器
? ??
? ??while(1)
? ? {
? ? ? ??float?temperature = DS18B20_ReadTemp();
? ? ? ??if(temperature !=?-999) {
? ? ? ? ? ??printf("Temperature: %.3f Crn", temperature);
? ? ? ? }?else?{
? ? ? ? ? ??printf("Sensor Error!rn");
? ? ? ? }
? ? ? ? HAL_Delay(1000); ?// 1秒讀取一次
? ? }
}
3.加速度傳感器 MPU6050
應(yīng)用場景
可穿戴設(shè)備:智能手環(huán)步數(shù)檢測(如小米手環(huán))
無人機(jī)飛控:姿態(tài)解算(大疆飛控IMU模塊)
工業(yè)機(jī)器人:振動監(jiān)測(庫卡機(jī)械臂)
#include?"main.h"
#include?<stdio.h>
#include?<math.h>
#define?MPU6050_ADDR 0xD0 ?// I2C地址(AD0接地時(shí)為0x68,左移1位后為0xD0)
#define?SMPLRT_DIV 0x19 ? ?// 采樣率分頻
#define?CONFIG 0x1A ? ? ? ?// 配置寄存器
#define?GYRO_CONFIG 0x1B ??// 陀螺儀配置
#define?ACCEL_CONFIG 0x1C ?// 加速度計(jì)配置
#define?PWR_MGMT_1 0x6B ? ?// 電源管理1
#define?WHO_AM_I 0x75 ? ? ?// 設(shè)備ID寄存器
I2C_HandleTypeDef hi2c1; ?// 需要配置I2C外設(shè)
// 校準(zhǔn)參數(shù)結(jié)構(gòu)體
typedefstruct?{
? ??int16_t?x_offset;
? ??int16_t?y_offset;
? ??int16_t?z_offset;
} MPU6050_Calib;
// 原始數(shù)據(jù)結(jié)構(gòu)體
typedefstruct?{
? ??int16_t?accel_x;
? ??int16_t?accel_y;
? ??int16_t?accel_z;
? ??int16_t?temp;
? ??int16_t?gyro_x;
? ??int16_t?gyro_y;
? ??int16_t?gyro_z;
} MPU6050_RawData;
// 初始化MPU6050
uint8_t?MPU6050_Init(void)
{
? ??uint8_t?check;
? ? HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, WHO_AM_I,?1, &check,?1,?100);
? ??if(check !=?0x68)?return1;?// 檢測設(shè)備ID
? ??
? ??// 喚醒設(shè)備,選擇時(shí)鐘源
? ??uint8_t?data =?0x00;
? ? HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, PWR_MGMT_1,?1, &data,?1,?100);
? ??
? ??// 設(shè)置采樣率分頻(1kHz/(1+SMPLRT_DIV))
? ? data =?0x07;?// 125Hz
? ? HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, SMPLRT_DIV,?1, &data,?1,?100);
? ??
? ??// 設(shè)置低通濾波器帶寬
? ? data =?0x06;?// 5Hz
? ? HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, CONFIG,?1, &data,?1,?100);
? ??
? ??// 設(shè)置加速度計(jì)量程 ±4g
? ? data =?0x08;?// ±4g (8192 LSB/g)
? ? HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, ACCEL_CONFIG,?1, &data,?1,?100);
? ??
? ??// 設(shè)置陀螺儀量程 ±500°/s
? ? data =?0x08;?// ±500°/s (65.5 LSB/°/s)
? ? HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, GYRO_CONFIG,?1, &data,?1,?100);
? ??
? ??return0;
}
// 讀取原始數(shù)據(jù)
void?MPU6050_ReadRaw(MPU6050_RawData *data)
{
? ??uint8_t?buffer[14];
? ? HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR,?0x3B,?1, buffer,?14,?100);
? ??
? ? data->accel_x = (buffer[0] <<8) | buffer[1];
? ? data->accel_y = (buffer[2] <<8) | buffer[3];
? ? data->accel_z = (buffer[4] <<8) | buffer[5];
? ? data->temp = (buffer[6] <<8) | buffer[7];
? ? data->gyro_x = (buffer[8] <<8) | buffer[9];
? ? data->gyro_y = (buffer[10]<<8) | buffer[11];
? ? data->gyro_z = (buffer[12]<<8) | buffer[12];
}
// 自動校準(zhǔn)(傳感器需保持水平靜止)
void?MPU6050_Calibrate(MPU6050_Calib *calib,?uint32_t?sample_num)
{
? ??int32_t?sum_gx =?0, sum_gy =?0, sum_gz =?0;
? ??
? ??for(uint32_t?i=0; i<sample_num; i++){
? ? ? ? MPU6050_RawData data;
? ? ? ? MPU6050_ReadRaw(&data);
? ? ? ? sum_gx += data.gyro_x;
? ? ? ? sum_gy += data.gyro_y;
? ? ? ? sum_gz += data.gyro_z;
? ? ? ? HAL_Delay(10);
? ? }
? ??
? ? calib->x_offset = sum_gx / sample_num;
? ? calib->y_offset = sum_gy / sample_num;
? ? calib->z_offset = sum_gz / sample_num;
}
// 姿態(tài)解算(互補(bǔ)濾波)
void?MPU6050_GetAngle(float?*pitch,?float?*roll, MPU6050_RawData *raw,?float?dt)
{
? ??staticfloat?angle_pitch =?0, angle_roll =?0;
? ??staticfloat?gyro_x_bias =?0, gyro_y_bias =?0;
? ??
? ??// 加速度計(jì)角度計(jì)算
? ??float?accel_pitch =?atan2(raw->accel_y,?sqrt(raw->accel_x*raw->accel_x + raw->accel_z*raw->accel_z)) *?180/M_PI;
? ??float?accel_roll =?atan2(-raw->accel_x,?sqrt(raw->accel_y*raw->accel_y + raw->accel_z*raw->accel_z)) *?180/M_PI;
? ??
? ??// 陀螺儀角速度(考慮校準(zhǔn)偏移)
? ??float?gyro_x = (raw->gyro_x - gyro_x_bias) /?65.5;?// ±500dps時(shí)靈敏度65.5 LSB/°/s
? ??float?gyro_y = (raw->gyro_y - gyro_y_bias) /?65.5;
? ??
? ??// 互補(bǔ)濾波(系數(shù)0.96)
? ? angle_pitch =?0.96*(angle_pitch + gyro_x*dt) +?0.04*accel_pitch;
? ? angle_roll =?0.96*(angle_roll + gyro_y*dt) +?0.04*accel_roll;
? ??
? ? *pitch = angle_pitch;
? ? *roll = angle_roll;
}
// 主函數(shù)示例
int?main(void)
{
? ? HAL_Init();
? ? SystemClock_Config();
? ? MX_I2C1_Init();?// 初始化I2C
? ??
? ??if(MPU6050_Init()) {
? ? ? ??printf("MPU6050 Init Failed!rn");
? ? ? ??while(1);
? ? }
? ??
? ? MPU6050_Calib calib;
? ? MPU6050_Calibrate(&calib,?200);?// 采集200個(gè)樣本校準(zhǔn)
? ??
? ? MPU6050_RawData raw;
? ??float?pitch, roll;
? ??uint32_t?last_tick = HAL_GetTick();
? ??
? ??while(1) {
? ? ? ??// 讀取原始數(shù)據(jù)并應(yīng)用校準(zhǔn)
? ? ? ? MPU6050_ReadRaw(&raw);
? ? ? ? raw.gyro_x -= calib.x_offset;
? ? ? ? raw.gyro_y -= calib.y_offset;
? ? ? ? raw.gyro_z -= calib.z_offset;
? ? ? ??
? ? ? ??// 計(jì)算時(shí)間差(單位:秒)
? ? ? ??uint32_t?current_tick = HAL_GetTick();
? ? ? ??float?dt = (current_tick - last_tick) *?0.001f;
? ? ? ? last_tick = current_tick;
? ? ? ??
? ? ? ??// 姿態(tài)解算
? ? ? ? MPU6050_GetAngle(&pitch, &roll, &raw, dt);
? ? ? ??
? ? ? ??// 輸出結(jié)果
? ? ? ??printf("Pitch: %.2f° ?Roll: %.2f°rn", pitch, roll);
? ? ? ? HAL_Delay(50);?// 控制輸出頻率
? ? }
}
4.壓力傳感器 BMP280
應(yīng)用場景
氣象設(shè)備:便攜式氣壓計(jì)(如Garmin手持GPS)
無人機(jī):高度計(jì)(大疆Phantom系列)
STM32例程
#include?"main.h"
#include?<stdio.h>
#include?<math.h>
#define?BMP280_I2C_ADDR 0x76?// 0x77 if SDO high
#define?BMP280_CALIB_SIZE 24
I2C_HandleTypeDef hi2c1; ?// 需要配置I2C外設(shè)
// 校準(zhǔn)參數(shù)結(jié)構(gòu)體
typedefstruct?{
? ??uint16_t?dig_T1;
? ??int16_t? dig_T2;
? ??int16_t? dig_T3;
? ??uint16_t?dig_P1;
? ??int16_t? dig_P2;
? ??int16_t? dig_P3;
? ??int16_t? dig_P4;
? ??int16_t? dig_P5;
? ??int16_t? dig_P6;
? ??int16_t? dig_P7;
? ??int16_t? dig_P8;
? ??int16_t? dig_P9;
} BMP280_Calib;
// 傳感器配置結(jié)構(gòu)體
typedefstruct?{
? ??uint8_t?ctrl_meas;
? ??uint8_t?config;
} BMP280_Config;
// 初始化BMP280
uint8_t?BMP280_Init(BMP280_Calib *calib, BMP280_Config *conf)
{
? ??// 檢測設(shè)備ID
? ??uint8_t?id;
? ? HAL_I2C_Mem_Read(&hi2c1, BMP280_I2C_ADDR,?0xD0,?1, &id,?1,?100);
? ??if(id !=?0x58)?return1;
? ??// 讀取校準(zhǔn)參數(shù)
? ??uint8_t?calib_data[BMP280_CALIB_SIZE];
? ? HAL_I2C_Mem_Read(&hi2c1, BMP280_I2C_ADDR,?0x88,?1, calib_data, BMP280_CALIB_SIZE,?100);
? ??
? ? calib->dig_T1 = (calib_data[1] <<8) | calib_data[0];
? ? calib->dig_T2 = (calib_data[3] <<8) | calib_data[2];
? ? calib->dig_T3 = (calib_data[5] <<8) | calib_data[4];
? ? calib->dig_P1 = (calib_data[7] <<8) | calib_data[6];
? ? calib->dig_P2 = (calib_data[9] <<8) | calib_data[8];
? ? calib->dig_P3 = (calib_data[11]<<8) | calib_data[10];
? ? calib->dig_P4 = (calib_data[13]<<8) | calib_data[12];
? ? calib->dig_P5 = (calib_data[15]<<8) | calib_data[14];
? ? calib->dig_P6 = (calib_data[17]<<8) | calib_data[16];
? ? calib->dig_P7 = (calib_data[19]<<8) | calib_data[18];
? ? calib->dig_P8 = (calib_data[21]<<8) | calib_data[20];
? ? calib->dig_P9 = (calib_data[23]<<8) | calib_data[22];
? ??// 寫入配置寄存器
? ? HAL_I2C_Mem_Write(&hi2c1, BMP280_I2C_ADDR,?0xF4,?1, &conf->ctrl_meas,?1,?100);
? ? HAL_I2C_Mem_Write(&hi2c1, BMP280_I2C_ADDR,?0xF5,?1, &conf->config,?1,?100);
? ??
? ??return0;
}
// 讀取原始數(shù)據(jù)
void?BMP280_ReadRaw(int32_t?*temp_raw,?int32_t?*press_raw)
{
? ??uint8_t?data[6];
? ? HAL_I2C_Mem_Read(&hi2c1, BMP280_I2C_ADDR,?0xF7,?1, data,?6,?100);
? ??
? ? *press_raw = (int32_t)((data[0] <<12) | (data[1] <<4) | (data[2] >>4));
? ? *temp_raw ?= (int32_t)((data[3] <<12) | (data[4] <<4) | (data[5] >>4));
}
// 溫度補(bǔ)償計(jì)算
float?BMP280_CompensateTemp(int32_t?temp_raw, BMP280_Calib *calib)
{
? ??int32_t?var1, var2, T;
? ??
? ? var1 = ((((temp_raw >>3) - ((int32_t)calib->dig_T1 <<1))) *?
? ? ? ? ? ? ((int32_t)calib->dig_T2)) >>11;
? ??
? ? var2 = (((((temp_raw >>4) - ((int32_t)calib->dig_T1)) *?
? ? ? ? ? ? ((temp_raw >>4) - ((int32_t)calib->dig_T1))) >>12) *?
? ? ? ? ? ? ((int32_t)calib->dig_T3)) >>14;
? ? T = var1 + var2;
? ??return?(T *?5?+?128) /?256.0f?/?100.0f;?// 返回?cái)z氏度
}
// 壓力補(bǔ)償計(jì)算
float?BMP280_CompensatePress(int32_t?press_raw, BMP280_Calib *calib,?float?t_fine)
{
? ??int64_t?var1, var2, p;
? ??
? ? var1 = ((int64_t)t_fine) -?128000;
? ? var2 = var1 * var1 * (int64_t)calib->dig_P6;
? ? var2 = var2 + ((var1 * (int64_t)calib->dig_P5) <<17);
? ? var2 = var2 + (((int64_t)calib->dig_P4) <<35);
? ? var1 = ((var1 * var1 * (int64_t)calib->dig_P3) >>8) +?
? ? ? ? ? ?((var1 * (int64_t)calib->dig_P2) <<12);
? ? var1 = (((((int64_t)1) <<47) + var1)) * ((int64_t)calib->dig_P1) >>33;
? ??if(var1 ==?0)?return0;
? ??
? ? p =?1048576?- press_raw;
? ? p = (((p <<31) - var2) *?3125) / var1;
? ? var1 = (((int64_t)calib->dig_P9) * (p >>13) * (p >>13)) >>25;
? ? var2 = (((int64_t)calib->dig_P8) * p) >>19;
? ??
? ? p = ((p + var1 + var2) >>8) + (((int64_t)calib->dig_P7) <<4);
? ??return?(float)p /?256.0f;?// 返回Pa
}
// 計(jì)算海拔高度(國際標(biāo)準(zhǔn)大氣模型)
float?BMP280_CalcAltitude(float?pressure,?float?sea_level_hpa=1013.25f)
{
? ??return44330.0f?* (1.0f?- powf(pressure /?100.0f?/ sea_level_hpa,?0.1903f));
}
int?main(void)
{
? ? HAL_Init();
? ? SystemClock_Config();
? ? MX_I2C1_Init();
? ??// 配置參數(shù):溫度x2采樣,壓力x16采樣,正常模式,濾波器系數(shù)16
? ? BMP280_Config conf = {
? ? ? ? .ctrl_meas =?0b01010111,?// osrs_t=x2, osrs_p=x16, mode=normal
? ? ? ? .config ? ?=?0b00010100// t_sb=0.5ms, filter=16, spi3w_en=0
? ? };
? ? BMP280_Calib calib;
? ??if(BMP280_Init(&calib, &conf)) {
? ? ? ??printf("BMP280 Init Failed!rn");
? ? ? ??while(1);
? ? }
? ??int32_t?temp_raw, press_raw;
? ??float?temperature, pressure, altitude;
? ??while(1) {
? ? ? ? BMP280_ReadRaw(&temp_raw, &press_raw);
? ? ? ??
? ? ? ? temperature = BMP280_CompensateTemp(temp_raw, &calib);
? ? ? ??float?t_fine = temperature *?100.0f;?// 用于壓力補(bǔ)償
? ? ? ? pressure = BMP280_CompensatePress(press_raw, &calib, t_fine);
? ? ? ? altitude = BMP280_CalcAltitude(pressure);
? ? ? ??
? ? ? ??printf("Temp: %.2f C ?Pressure: %.2f Pa ?Alt: %.2f mrn",?
? ? ? ? ? ? ? temperature, pressure, altitude);
? ? ? ??
? ? ? ? HAL_Delay(1000);
? ? }
}
5.紅外測距 GP2Y0A21
應(yīng)用場景
服務(wù)機(jī)器人:自動避障(如掃地機(jī)器人)
工業(yè)自動化:傳送帶物體位置檢測
智能馬桶:人體接近感應(yīng)
STM32例程
#include?"main.h"
#include?<stdio.h>
#include?<math.h>
#define?IR_ADC hadc1 ? ? ? ? ?// 使用的ADC實(shí)例
#define?SAMPLE_TIMES 5 ? ? ? ?// 采樣次數(shù)(用于移動平均)
#define?VALID_MIN_DISTANCE 10?// 有效測量范圍10cm
#define?VALID_MAX_DISTANCE 80?// 有效測量范圍80cm
// ADC初始化(需在CubeMX中配置)
void?MX_ADC1_Init(void);
// 非線性校準(zhǔn)結(jié)構(gòu)體
typedefstruct?{
? ??float?adc_min; ? ?// 對應(yīng)80cm的ADC值
? ??float?adc_max; ? ?// 對應(yīng)10cm的ADC值
? ??float?voltage_ref;// 參考電壓(3.3V或5V)
} IR_Calibration;
// 獲取ADC原始值(12位分辨率)
uint32_t?IR_GetRawADC(void)
{
? ??uint32_t?raw =?0;
? ? HAL_ADC_Start(&IR_ADC);
? ??for(int?i=0; i<SAMPLE_TIMES; i++){
? ? ? ? HAL_ADC_PollForConversion(&IR_ADC,?10);
? ? ? ? raw += HAL_ADC_GetValue(&IR_ADC);
? ? ? ? HAL_Delay(2);
? ? }
? ? HAL_ADC_Stop(&IR_ADC);
? ??return?raw / SAMPLE_TIMES;?// 返回平均值
}
// 查表法計(jì)算距離(基于典型特性曲線)
float?IR_CalcDistance_LUT(uint32_t?adc_val, IR_Calibration *cal)
{
? ??// 典型電壓-距離對應(yīng)表(需根據(jù)實(shí)測數(shù)據(jù)校準(zhǔn))
? ??constfloat?distance_table[] = {80.0,?70.0,?60.0,?50.0,?40.0,?30.0,?20.0,?10.0};
? ??constuint16_t?adc_table[] = {620, ?720, ?860,?1050,?1350,?1850,?2750,?3850};?// 3.3V參考電壓時(shí)的典型值
? ??
? ??if(adc_val <= adc_table[7])?return?VALID_MIN_DISTANCE;
? ??if(adc_val >= adc_table[0])?return?VALID_MAX_DISTANCE;
? ??
? ??// 線性插值
? ??for(int?i=0; i<7; i++){
? ? ? ??if(adc_val >= adc_table[i+1] && adc_val <= adc_table[i]){
? ? ? ? ? ??float?ratio = (float)(adc_val - adc_table[i+1]) / (adc_table[i] - adc_table[i+1]);
? ? ? ? ? ??return?distance_table[i+1] + ratio*(distance_table[i] - distance_table[i+1]);
? ? ? ? }
? ? }
? ??return0;
}
// 公式法計(jì)算距離(近似公式V = 1/(a*d + b))
float?IR_CalcDistance_Formula(uint32_t?adc_val, IR_Calibration *cal)
{
? ??float?voltage = (adc_val /?4095.0f) * cal->voltage_ref;
? ??if(voltage <?0.4f)?return?VALID_MAX_DISTANCE;
? ??if(voltage >?3.0f)?return?VALID_MIN_DISTANCE;
? ??
? ??// 經(jīng)驗(yàn)公式:1/d = (V - 0.35)/0.3 (單位:cm)
? ??float?distance =?1.0?/ ((voltage -?0.35f)/0.3f);
? ??return?fmaxf(fminf(distance, VALID_MAX_DISTANCE), VALID_MIN_DISTANCE);
}
// 自動校準(zhǔn)函數(shù)(需在已知距離下校準(zhǔn))
void?IR_AutoCalibrate(IR_Calibration *cal,?float?known_distance)
{
? ??uint32_t?adc_val = IR_GetRawADC();
? ??if(known_distance ==?10.0f) cal->adc_min = adc_val;
? ??if(known_distance ==?80.0f) cal->adc_max = adc_val;
}
int?main(void)
{
? ? HAL_Init();
? ? SystemClock_Config();
? ? MX_ADC1_Init();
? ??
? ??// 初始化校準(zhǔn)參數(shù)(需根據(jù)實(shí)際測量校準(zhǔn))
? ? IR_Calibration calib = {
? ? ? ? .adc_min =?3850, ? ?// 10cm時(shí)的ADC值
? ? ? ? .adc_max =?620, ? ??// 80cm時(shí)的ADC值
? ? ? ? .voltage_ref =?3.3f// 參考電壓
? ? };
? ??
? ??while(1)
? ? {
? ? ? ??uint32_t?raw_adc = IR_GetRawADC();
? ? ? ??
? ? ? ??// 兩種計(jì)算方法
? ? ? ??float?distance_lut = IR_CalcDistance_LUT(raw_adc, &calib);
? ? ? ??float?distance_formula = IR_CalcDistance_Formula(raw_adc, &calib);
? ? ? ??
? ? ? ??// 輸出結(jié)果
? ? ? ??printf("ADC: %4lu ?LUT: %.1fcm ?Formula: %.1fcmrn",?
? ? ? ? ? ? ? raw_adc, distance_lut, distance_formula);
? ? ? ??
? ? ? ? HAL_Delay(200);?// 控制采樣頻率
? ? }
}
6.超聲波測距 HC-SR04
應(yīng)用場景
智能停車場:車位檢測系統(tǒng)
液位監(jiān)測:儲油罐液位測量
安防系統(tǒng):入侵檢測報(bào)警
STM32例程
#include?"main.h"
#include?<stdio.h>
#include?<math.h>
// 硬件引腳定義
#define?TRIG_GPIO_PORT ?GPIOA
#define?TRIG_GPIO_PIN ? GPIO_PIN_1
#define?ECHO_GPIO_PORT ?GPIOA
#define?ECHO_GPIO_PIN ? GPIO_PIN_0
// 定時(shí)器配置(用于測量高電平時(shí)間)
TIM_HandleTypeDef htim2;
// 測量參數(shù)
#define?SOUND_SPEED_25C 34300.0f ?// 25℃時(shí)聲速(cm/s)
#define?MAX_DISTANCE_CM ?400 ? ? ??// 最大有效距離
#define?MIN_DISTANCE_CM ?2 ? ? ? ??// 最小有效距離
#define?TIMEOUT_US ? ? ? 60000 ? ??// 超時(shí)時(shí)間(對應(yīng)400cm)
// 濾波器配置
#define?MEDIAN_FILTER_SIZE 5 ? ? ??// 中值濾波窗口大小
#define?MOVING_AVERAGE_SIZE 3 ? ? ?// 移動平均窗口大小
typedefstruct?{
? ??float?temperature; ? ?// 環(huán)境溫度(用于聲速補(bǔ)償)
? ??float?distance_cm; ? ?// 最終輸出距離
? ??uint32_t?timeout; ? ??// 超時(shí)計(jì)數(shù)器
} Ultrasonic_State;
// 微秒延時(shí)函數(shù)
void?Delay_us(uint16_t?us)
{
? ? __HAL_TIM_SET_COUNTER(&htim2,?0);
? ? HAL_TIM_Base_Start(&htim2);
? ??while(__HAL_TIM_GET_COUNTER(&htim2) < us);
? ? HAL_TIM_Base_Stop(&htim2);
}
// 超聲波模塊初始化
void?Ultrasonic_Init(void)
{
? ? GPIO_InitTypeDef GPIO_InitStruct = {0};
? ??
? ??// 配置TRIG引腳為輸出
? ? GPIO_InitStruct.Pin = TRIG_GPIO_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
? ? GPIO_InitStruct.Pull = GPIO_NOPULL;
? ? GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
? ? HAL_GPIO_Init(TRIG_GPIO_PORT, &GPIO_InitStruct);
? ??
? ??// 配置ECHO引腳為輸入
? ? GPIO_InitStruct.Pin = ECHO_GPIO_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
? ? GPIO_InitStruct.Pull = GPIO_PULLDOWN;
? ? HAL_GPIO_Init(ECHO_GPIO_PORT, &GPIO_InitStruct);
}
// 觸發(fā)測量
void?Ultrasonic_Trigger(void)
{
? ? HAL_GPIO_WritePin(TRIG_GPIO_PORT, TRIG_GPIO_PIN, GPIO_PIN_SET);
? ? Delay_us(12); ?// 觸發(fā)信號至少10us
? ? HAL_GPIO_WritePin(TRIG_GPIO_PORT, TRIG_GPIO_PIN, GPIO_PIN_RESET);
}
// 獲取高電平時(shí)間(微秒)
uint32_t?Ultrasonic_GetPulseWidth(void)
{
? ??uint32_t?start_time =?0, end_time =?0;
? ??
? ??// 等待ECHO變高
? ??uint32_t?timeout =?0;
? ??while(HAL_GPIO_ReadPin(ECHO_GPIO_PORT, ECHO_GPIO_PIN) == GPIO_PIN_RESET){
? ? ? ??if(++timeout >?1000)?return0;?// 1ms超時(shí)
? ? ? ? Delay_us(1);
? ? }
? ??
? ??// 記錄高電平開始時(shí)間
? ? start_time = __HAL_TIM_GET_COUNTER(&htim2);
? ??
? ??// 等待ECHO變低
? ? timeout =?0;
? ??while(HAL_GPIO_ReadPin(ECHO_GPIO_PORT, ECHO_GPIO_PIN) == GPIO_PIN_SET){
? ? ? ??if(++timeout > TIMEOUT_US)?break;
? ? ? ? Delay_us(1);
? ? }
? ? end_time = __HAL_TIM_GET_COUNTER(&htim2);
? ??
? ??return?(end_time - start_time);
}
// 中值濾波
float?MedianFilter(float?new_value)
{
? ??staticfloat?buffer[MEDIAN_FILTER_SIZE];
? ??staticuint8_t?index =?0;
? ??float?temp[MEDIAN_FILTER_SIZE];
? ??
? ? buffer[index] = new_value;
? ? index = (index +?1) % MEDIAN_FILTER_SIZE;
? ??
? ??// 復(fù)制數(shù)組并排序
? ??for(uint8_t?i=0; i<MEDIAN_FILTER_SIZE; i++) temp[i] = buffer[i];
? ??for(uint8_t?i=0; i<MEDIAN_FILTER_SIZE-1; i++){
? ? ? ??for(uint8_t?j=i+1; j<MEDIAN_FILTER_SIZE; j++){
? ? ? ? ? ??if(temp[i] > temp[j]){
? ? ? ? ? ? ? ??float?swap = temp[i];
? ? ? ? ? ? ? ? temp[i] = temp[j];
? ? ? ? ? ? ? ? temp[j] = swap;
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ??return?temp[MEDIAN_FILTER_SIZE/2];
}
// 移動平均濾波
float?MovingAverageFilter(float?new_value)
{
? ??staticfloat?buffer[MOVING_AVERAGE_SIZE];
? ??staticuint8_t?index =?0;
? ??staticfloat?sum =?0;
? ??
? ? sum -= buffer[index];
? ? buffer[index] = new_value;
? ? sum += new_value;
? ? index = (index +?1) % MOVING_AVERAGE_SIZE;
? ??
? ??return?sum / MOVING_AVERAGE_SIZE;
}
// 計(jì)算距離(帶溫度補(bǔ)償)
float?CalcDistanceWithTemp(uint32_t?pulse_us,?float?temp)
{
? ??// 聲速計(jì)算(331.5 + 0.6*T)m/s
? ??float?sound_speed =?33150.0f?+?60.0f?* temp;
? ??float?distance = (pulse_us * sound_speed) /?20000.0f;?// 單位cm
? ??
? ??// 限制有效范圍
? ??if(distance < MIN_DISTANCE_CM)?return?MIN_DISTANCE_CM;
? ??if(distance > MAX_DISTANCE_CM)?return?MAX_DISTANCE_CM;
? ??return?distance;
}
// 主函數(shù)示例
int?main(void)
{
? ? HAL_Init();
? ? SystemClock_Config();
? ? MX_TIM2_Init();?// 配置TIM2為1us計(jì)數(shù)
? ??
? ? Ultrasonic_Init();
? ? Ultrasonic_State state = {
? ? ? ? .temperature =?25.0f,?// 默認(rèn)25℃
? ? ? ? .distance_cm =?0,
? ? ? ? .timeout =?0
? ? };
? ??
? ??while(1)
? ? {
? ? ? ? Ultrasonic_Trigger();
? ? ? ??uint32_t?pulse_us = Ultrasonic_GetPulseWidth();
? ? ? ??
? ? ? ??if(pulse_us ==?0){
? ? ? ? ? ? state.timeout++;
? ? ? ? ? ??if(state.timeout >?3)?printf("Sensor Error!rn");
? ? ? ? ? ??continue;
? ? ? ? }
? ? ? ??
? ? ? ??// 原始距離計(jì)算
? ? ? ??float?raw_distance = CalcDistanceWithTemp(pulse_us, state.temperature);
? ? ? ??
? ? ? ??// 雙重濾波處理
? ? ? ??float?median = MedianFilter(raw_distance);
? ? ? ??float?filtered = MovingAverageFilter(median);
? ? ? ??
? ? ? ? state.distance_cm = filtered;
? ? ? ? state.timeout =?0;
? ? ? ??
? ? ? ??printf("Distance: %.1f cmrn", state.distance_cm);
? ? ? ? HAL_Delay(100);?// 最小測量間隔60ms
? ? }
}
7.氣體傳感器 MQ-2
應(yīng)用場景
智能家居:燃?xì)庑孤﹫?bào)警(如海爾燃?xì)鈭?bào)警器)
礦業(yè)安全:井下瓦斯?jié)舛缺O(jiān)測
車載設(shè)備:新能源汽車電池?zé)崾Э仡A(yù)警
STM32例程
#include?"main.h"
#include?<stdio.h>
#include?<math.h>
#define?ADC_HANDLE ? ? hadc1
#define?HEATER_GPIO ? ?GPIOA
#define?HEATER_PIN ? ? GPIO_PIN_4
#define?CALIBRATION_SAMPLES 50 ?// 校準(zhǔn)采樣次數(shù)
typedefenum?{
? ? GAS_LPG =?0,
? ? GAS_SMOKE,
? ? GAS_HYDROGEN,
? ? GAS_TYPE_COUNT
} GasType;
// 傳感器參數(shù)結(jié)構(gòu)體
typedefstruct?{
? ??float?Ro; ? ? ? ? ? ? ? ? ??// 干凈空氣中傳感器電阻
? ??float?RL; ? ? ? ? ? ? ? ? ??// 負(fù)載電阻值
? ??float?VCC; ? ? ? ? ? ? ? ? ?// 供電電壓
? ??float?temp_compensation; ? ?// 溫度補(bǔ)償系數(shù)
? ??float?hum_compensation; ? ??// 濕度補(bǔ)償系數(shù)
? ??float?gas_curve[GAS_TYPE_COUNT][3];?// 氣體曲線參數(shù)
} MQ2_Calibration;
// 初始化函數(shù)
void?MQ2_Init(void)
{
? ? ADC_ChannelConfTypeDef sConfig = {0};
? ? sConfig.Channel = ADC_CHANNEL_0;
? ? sConfig.Rank =?1;
? ? sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
? ? HAL_ADC_ConfigChannel(&ADC_HANDLE, &sConfig);
? ??
? ??// 加熱器控制引腳初始化
? ? GPIO_InitTypeDef GPIO_InitStruct = {0};
? ? GPIO_InitStruct.Pin = HEATER_PIN;
? ? GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
? ? GPIO_InitStruct.Pull = GPIO_NOPULL;
? ? GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
? ? HAL_GPIO_Init(HEATER_GPIO, &GPIO_InitStruct);
}
// 預(yù)熱傳感器(建議首次使用前預(yù)熱24小時(shí))
void?MQ2_Preheat(uint32_t?minutes)
{
? ? HAL_GPIO_WritePin(HEATER_GPIO, HEATER_PIN, GPIO_PIN_SET);
? ? HAL_Delay(minutes *?60?*?1000);
? ? HAL_GPIO_WritePin(HEATER_GPIO, HEATER_PIN, GPIO_PIN_RESET);
}
// 獲取ADC原始值(12位分辨率)
float?MQ2_ReadAnalog(void)
{
? ??uint32_t?raw =?0;
? ? HAL_ADC_Start(&ADC_HANDLE);
? ??for(int?i=0; i<5; i++){?// 5次采樣平均
? ? ? ? HAL_ADC_PollForConversion(&ADC_HANDLE,?10);
? ? ? ? raw += HAL_ADC_GetValue(&ADC_HANDLE);
? ? }
? ? HAL_ADC_Stop(&ADC_HANDLE);
? ??return?raw /?5.0f;
}
// 校準(zhǔn)函數(shù)(需在干凈空氣中執(zhí)行)
void?MQ2_Calibrate(MQ2_Calibration *calib)
{
? ??float?avg =?0;
? ??for(int?i=0; i<CALIBRATION_SAMPLES; i++){
? ? ? ??float?Vout = MQ2_ReadAnalog() /?4095.0f?* calib->VCC;
? ? ? ??float?Rs_air = (calib->VCC - Vout) / Vout * calib->RL;
? ? ? ? avg += Rs_air;
? ? ? ? HAL_Delay(100);
? ? }
? ? calib->Ro = avg / CALIBRATION_SAMPLES /?9.8f;?// 清潔空氣系數(shù)9.8
}
// 計(jì)算氣體濃度(應(yīng)用溫度補(bǔ)償)
float?MQ2_GetGasPPM(MQ2_Calibration *calib, GasType gas_type)
{
? ??float?Vout = MQ2_ReadAnalog() /?4095.0f?* calib->VCC;
? ??float?Rs = (calib->VCC - Vout) / Vout * calib->RL;
? ??float?Rs_Ro = Rs / calib->Ro;
? ??
? ??/* 氣體靈敏度曲線公式:Rs/Ro = a*(ppm)^b + c */
? ??float?a = calib->gas_curve[gas_type][0];
? ??float?b = calib->gas_curve[gas_type][1];
? ??float?c = calib->gas_curve[gas_type][2];
? ??
? ??float?ppm = powf(((Rs_Ro - c)/a),?1.0f/b);
? ??return?ppm * calib->temp_compensation * calib->hum_compensation;
}
int?main(void)
{
? ? HAL_Init();
? ? SystemClock_Config();
? ? MX_ADC1_Init();
? ??
? ??// 初始化校準(zhǔn)參數(shù)
? ? MQ2_Calibration calib = {
? ? ? ? .Ro =?10.0f, ? ??// 初始值(需校準(zhǔn))
? ? ? ? .RL =?5.0f, ? ? ?// 分壓電阻(單位:kΩ)
? ? ? ? .VCC =?5.0f, ? ??// 傳感器供電電壓
? ? ? ? .temp_compensation =?1.0f, ??// 默認(rèn)補(bǔ)償系數(shù)
? ? ? ? .hum_compensation =?1.0f,
? ? ? ? .gas_curve = { ??// 典型靈敏度曲線參數(shù)
? ? ? ? ? ? [GAS_LPG] ? ? ? = {212.7,?-0.5,?100}, ?// LPG
? ? ? ? ? ? [GAS_SMOKE] ? ? = {300.0,?-0.55,?120},?// Smoke
? ? ? ? ? ? [GAS_HYDROGEN] ?= {150.0,?-0.4,?90} ? ?// H2
? ? ? ? }
? ? };
? ??
? ? MQ2_Init();
? ? MQ2_Calibrate(&calib);
? ??
? ??while(1)
? ? {
? ? ? ??float?lpg_ppm = MQ2_GetGasPPM(&calib, GAS_LPG);
? ? ? ??float?smoke_ppm = MQ2_GetGasPPM(&calib, GAS_SMOKE);
? ? ? ??float?hydrogen_ppm = MQ2_GetGasPPM(&calib, GAS_HYDROGEN);
? ? ? ??
? ? ? ??printf("LPG: %.1fppm ?Smoke: %.1fppm ?H2: %.1fppmrn",?
? ? ? ? ? ? ? lpg_ppm, smoke_ppm, hydrogen_ppm);
? ? ? ??
? ? ? ??// 報(bào)警檢測
? ? ? ??if(lpg_ppm >?2000)?printf("LPG Danger!rn");
? ? ? ??if(smoke_ppm >?1000)?printf("Fire Warning!rn");
? ? ? ??if(hydrogen_ppm >?500)?printf("H2 Leakage!rn");
? ? ? ??
? ? ? ? HAL_Delay(1000);
? ? }
}