• 正文
  • 相关推荐
申请入驻 产业图谱

分享几种常用的嵌入式传感器应用场景以及详细单片机使用例程

05/06 09:05
2088
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是专注分享职业规划/技术科普/智能生活有关原创文章的allen康哥。嵌入式开发其实某种意义上来说就是传感器的使用,所以今天就总结分享7种常用的传感器应用场景以及单片机例程,仅供参看。

1.温湿度传感器 DHT11

应用场景

智能家居:温湿度联动空调/加湿器(如米家温湿度计)

农业大棚:环境监控系统(阈值触发通风/喷淋)

冷链运输:药品/食品运输箱温湿度记录

STM32例程

#include "main.h"
#include <stdio.h>

#define DHT11_PORT GPIOA
#define DHT11_PIN  GPIO_PIN_0

TIM_HandleTypeDef htim2;  // 需要配置一个基本定时器

// 微秒延时函数(需要配置一个基本定时器,比如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数据
uint8_t DHT11_Read(float *temp, float *humi)
{
    uint8_t data[5] = {0};
    uint8_t retry = 0;
    
    // 发送开始信号
    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响应
    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);
        }
        
        // 开始接收数据
        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) // 高电平持续时间大于30us表示'1'
            {
                data[i/8] |= 1;
            }
        }
        
        // 校验数据
        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; // 失败
}

// 主函数示例
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_TIM2_Init(); // 初始化定时器
    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

应用场景

工业设备:电机/变压器温度监控

医疗设备:血液存储箱温度监测

汽车电子电池组温度管理

STM32例程(单总线协议

#include "main.h"
#include <stdio.h>

#define DS18B20_PORT GPIOA
#define DS18B20_PIN  GPIO_PIN_0

TIM_HandleTypeDef htim2;  // 用于微秒延时的基础定时器

/* 微秒延时函数(需要配置定时器,例如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表示检测到设备
}

/* 写入1位数据 */
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字节数据 */
void DS18B20_WriteByte(uint8_t data)
{
    for(uint8_t i=0; i<8; i++){
        DS18B20_WriteBit(data & 0x01);
        data >>= 1;
    }
}

/* 读取1位数据 */
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);
    
    // 产生读时隙
    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字节数据 */
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; // 设备未响应
    
    DS18B20_WriteByte(0xCC);  // 跳过ROM指令
    DS18B20_WriteByte(0x44);  // 启动温度转换
    Delay_us(800000);         // 等待转换完成(最大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位精度时的分辨率
}

/* 主函数示例 */
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_TIM2_Init();  // 初始化定时器
    
    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

应用场景

可穿戴设备智能手环步数检测(如小米手环)

无人机飞控:姿态解算(大疆飞控IMU模块)

工业机器人:振动监测(库卡机械臂)

STM32例程(I2C通信

#include "main.h"
#include <stdio.h>
#include <math.h>

#define MPU6050_ADDR 0xD0  // I2C地址(AD0接地时为0x68,左移1位后为0xD0)
#define SMPLRT_DIV 0x19    // 采样率分频
#define CONFIG 0x1A        // 配置寄存器
#define GYRO_CONFIG 0x1B   // 陀螺仪配置
#define ACCEL_CONFIG 0x1C  // 加速度计配置
#define PWR_MGMT_1 0x6B    // 电源管理1
#define WHO_AM_I 0x75      // 设备ID寄存器

I2C_HandleTypeDef hi2c1;  // 需要配置I2C外设

// 校准参数结构体
typedefstruct {
    int16_t x_offset;
    int16_t y_offset;
    int16_t z_offset;
} MPU6050_Calib;

// 原始数据结构体
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; // 检测设备ID
    
    // 唤醒设备,选择时钟源
    uint8_t data = 0x00;
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, PWR_MGMT_1, 1, &data, 1, 100);
    
    // 设置采样率分频(1kHz/(1+SMPLRT_DIV))
    data = 0x07; // 125Hz
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, SMPLRT_DIV, 1, &data, 1, 100);
    
    // 设置低通滤波器带宽
    data = 0x06; // 5Hz
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, CONFIG, 1, &data, 1, 100);
    
    // 设置加速度计量程 ±4g
    data = 0x08; // ±4g (8192 LSB/g)
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, ACCEL_CONFIG, 1, &data, 1, 100);
    
    // 设置陀螺仪量程 ±500°/s
    data = 0x08; // ±500°/s (65.5 LSB/°/s)
    HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, GYRO_CONFIG, 1, &data, 1, 100);
    
    return0;
}

// 读取原始数据
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];
}

// 自动校准(传感器需保持水平静止)
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;
}

// 姿态解算(互补滤波)
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;
    
    // 加速度计角度计算
    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;
    
    // 陀螺仪角速度(考虑校准偏移)
    float gyro_x = (raw->gyro_x - gyro_x_bias) / 65.5; // ±500dps时灵敏度65.5 LSB/°/s
    float gyro_y = (raw->gyro_y - gyro_y_bias) / 65.5;
    
    // 互补滤波(系数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;
}

// 主函数示例
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个样本校准
    
    MPU6050_RawData raw;
    float pitch, roll;
    uint32_t last_tick = HAL_GetTick();
    
    while(1) {
        // 读取原始数据并应用校准
        MPU6050_ReadRaw(&raw);
        raw.gyro_x -= calib.x_offset;
        raw.gyro_y -= calib.y_offset;
        raw.gyro_z -= calib.z_offset;
        
        // 计算时间差(单位:秒)
        uint32_t current_tick = HAL_GetTick();
        float dt = (current_tick - last_tick) * 0.001f;
        last_tick = current_tick;
        
        // 姿态解算
        MPU6050_GetAngle(&pitch, &roll, &raw, dt);
        
        // 输出结果
        printf("Pitch: %.2f°  Roll: %.2f°rn", pitch, roll);
        HAL_Delay(50); // 控制输出频率
    }
}

4.压力传感器 BMP280

应用场景

气象设备:便携式气压计(如Garmin手持GPS)

无人机:高度计(大疆Phantom系列)

智能手表:登山海拔显示(华为Watch GT)

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外设

// 校准参数结构体
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;

// 传感器配置结构体
typedefstruct {
    uint8_t ctrl_meas;
    uint8_t config;
} BMP280_Config;

// 初始化BMP280
uint8_t BMP280_Init(BMP280_Calib *calib, BMP280_Config *conf)
{
    // 检测设备ID
    uint8_t id;
    HAL_I2C_Mem_Read(&hi2c1, BMP280_I2C_ADDR, 0xD0, 1, &id, 1, 100);
    if(id != 0x58) return1;

    // 读取校准参数
    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;
}

// 读取原始数据
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));
}

// 温度补偿计算
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; // 返回摄氏度
}

// 压力补偿计算
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
}

// 计算海拔高度(国际标准大气模型)
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();

    // 配置参数:温度x2采样,压力x16采样,正常模式,滤波器系数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; // 用于压力补偿
        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

应用场景

服务机器人:自动避障(如扫地机器人

工业自动化:传送带物体位置检测

智能马桶:人体接近感应

STM32例程

#include "main.h"
#include <stdio.h>
#include <math.h>

#define IR_ADC hadc1          // 使用的ADC实例
#define SAMPLE_TIMES 5        // 采样次数(用于移动平均)
#define VALID_MIN_DISTANCE 10 // 有效测量范围10cm
#define VALID_MAX_DISTANCE 80 // 有效测量范围80cm

// ADC初始化(需在CubeMX中配置)
void MX_ADC1_Init(void);

// 非线性校准结构体
typedefstruct {
    float adc_min;    // 对应80cm的ADC值
    float adc_max;    // 对应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; // 返回平均值
}

// 查表法计算距离(基于典型特性曲线)
float IR_CalcDistance_LUT(uint32_t adc_val, IR_Calibration *cal)
{
    // 典型电压-距离对应表(需根据实测数据校准)
    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参考电压时的典型值
    
    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;
}

// 公式法计算距离(近似公式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;
    
    // 经验公式: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);
}

// 自动校准函数(需在已知距离下校准)
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();
    
    // 初始化校准参数(需根据实际测量校准)
    IR_Calibration calib = {
        .adc_min = 3850,    // 10cm时的ADC值
        .adc_max = 620,     // 80cm时的ADC值
        .voltage_ref = 3.3f// 参考电压
    };
    
    while(1)
    {
        uint32_t raw_adc = IR_GetRawADC();
        
        // 两种计算方法
        float distance_lut = IR_CalcDistance_LUT(raw_adc, &calib);
        float distance_formula = IR_CalcDistance_Formula(raw_adc, &calib);
        
        // 输出结果
        printf("ADC: %4lu  LUT: %.1fcm  Formula: %.1fcmrn", 
              raw_adc, distance_lut, distance_formula);
        
        HAL_Delay(200); // 控制采样频率
    }
}

6.超声波测距 HC-SR04

应用场景

智能停车场:车位检测系统

液位监测:储油罐液位测量

安防系统:入侵检测报警

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

// 定时器配置(用于测量高电平时间)
TIM_HandleTypeDef htim2;

// 测量参数
#define SOUND_SPEED_25C 34300.0f  // 25℃时声速(cm/s)
#define MAX_DISTANCE_CM  400       // 最大有效距离
#define MIN_DISTANCE_CM  2         // 最小有效距离
#define TIMEOUT_US       60000     // 超时时间(对应400cm)

// 滤波器配置
#define MEDIAN_FILTER_SIZE 5       // 中值滤波窗口大小
#define MOVING_AVERAGE_SIZE 3      // 移动平均窗口大小

typedefstruct {
    float temperature;    // 环境温度(用于声速补偿)
    float distance_cm;    // 最终输出距离
    uint32_t timeout;     // 超时计数器
} Ultrasonic_State;

// 微秒延时函数
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);
}

// 触发测量
void Ultrasonic_Trigger(void)
{
    HAL_GPIO_WritePin(TRIG_GPIO_PORT, TRIG_GPIO_PIN, GPIO_PIN_SET);
    Delay_us(12);  // 触发信号至少10us
    HAL_GPIO_WritePin(TRIG_GPIO_PORT, TRIG_GPIO_PIN, GPIO_PIN_RESET);
}

// 获取高电平时间(微秒)
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超时
        Delay_us(1);
    }
    
    // 记录高电平开始时间
    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;
    
    // 复制数组并排序
    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;
}

// 计算距离(带温度补偿)
float CalcDistanceWithTemp(uint32_t pulse_us, float temp)
{
    // 声速计算(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;
}

// 主函数示例
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_TIM2_Init(); // 配置TIM2为1us计数
    
    Ultrasonic_Init();
    Ultrasonic_State state = {
        .temperature = 25.0f, // 默认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;
        }
        
        // 原始距离计算
        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

应用场景

智能家居:燃气泄漏报警(如海尔燃气报警器

矿业安全:井下瓦斯浓度监测

车载设备:新能源汽车电池热失控预警

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  // 校准采样次数

typedefenum {
    GAS_LPG = 0,
    GAS_SMOKE,
    GAS_HYDROGEN,
    GAS_TYPE_COUNT
} GasType;

// 传感器参数结构体
typedefstruct {
    float Ro;                   // 干净空气中传感器电阻
    float RL;                   // 负载电阻值
    float VCC;                  // 供电电压
    float temp_compensation;    // 温度补偿系数
    float hum_compensation;     // 湿度补偿系数
    float gas_curve[GAS_TYPE_COUNT][3]; // 气体曲线参数
} MQ2_Calibration;

// 初始化函数
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);
}

// 预热传感器(建议首次使用前预热24小时)
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;
}

// 校准函数(需在干净空气中执行)
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; // 清洁空气系数9.8
}

// 计算气体浓度(应用温度补偿)
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();
    
    // 初始化校准参数
    MQ2_Calibration calib = {
        .Ro = 10.0f,     // 初始值(需校准)
        .RL = 5.0f,      // 分压电阻(单位:kΩ)
        .VCC = 5.0f,     // 传感器供电电压
        .temp_compensation = 1.0f,   // 默认补偿系数
        .hum_compensation = 1.0f,
        .gas_curve = {   // 典型灵敏度曲线参数
            [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);
        
        // 报警检测
        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);
    }
}

 

相关推荐