ESP32单片机基础入门

第7章:ADC与传感器

ADC基础

ESP32内置12位逐次逼近型模数转换器(ADC),可用于将模拟信号转换为数字信号。ESP32的ADC特性包括:

注意: ESP32的ADC在默认配置下是非线性的,特别是接近电压范围极限时。对于精确测量,建议进行校准。

1. 光敏电阻数据采集(adc1_get_raw)

硬件连接

光敏电阻通常与固定电阻组成分压电路连接到ESP32的ADC引脚:

光敏电阻连接图

ADC初始化

// 包含必要的头文件
#include "driver/adc.h"
#include "esp_adc_cal.h"

// 配置ADC
void setup_adc() {
    adc1_config_width(ADC_WIDTH_BIT_12);  // 设置12位分辨率
    adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);  // 设置衰减
}
            

读取ADC值

// 读取ADC原始值
int read_light_sensor() {
    return adc1_get_raw(ADC1_CHANNEL_0);  // 读取ADC1通道0的值
}
            
提示: 实际应用中,建议多次采样取平均值以提高稳定性。

2. 校准曲线拟合(非线性校正)

由于ESP32的ADC存在非线性特性,特别是接近电压极限时,需要进行校准以提高测量精度。

两点校准法

使用已知的两个输入电压点进行线性校准:

// 两点校准函数
float two_point_calibration(int raw, int raw_min, int raw_max, float volt_min, float volt_max) {
    return volt_min + (volt_max - volt_min) * (raw - raw_min) / (float)(raw_max - raw_min);
}
            

多点曲线拟合

对于更高精度的要求,可以使用多项式拟合:

// 多项式拟合校准
float poly_calibration(int raw) {
    // 这些系数需要通过实际测量数据拟合得到
    const float a = 0.0001;
    const float b = -0.012;
    const float c = 0.5;
    const float d = 0.0;
    
    return a * pow(raw, 3) + b * pow(raw, 2) + c * raw + d;
}
            

实际校准步骤

  1. 准备已知光照强度的环境(如使用专业光照计)
  2. 在不同光照强度下记录ADC原始值
  3. 使用Excel或专业工具进行曲线拟合
  4. 将拟合得到的系数应用到程序中
最佳实践: 对于光敏电阻应用,建议使用对数拟合,因为光敏电阻的阻值与光照强度通常呈对数关系。

完整示例代码

#include "driver/adc.h"
#include "esp_adc_cal.h"

// 定义ADC通道
#define LIGHT_SENSOR ADC1_CHANNEL_0

// 初始化ADC
void setup_adc() {
    adc1_config_width(ADC_WIDTH_BIT_12);
    adc1_config_channel_atten(LIGHT_SENSOR, ADC_ATTEN_DB_11);
}

// 读取ADC原始值(多次采样取平均)
int read_light_sensor_raw() {
    int samples = 10;
    int sum = 0;
    
    for(int i = 0; i < samples; i++) {
        sum += adc1_get_raw(LIGHT_SENSOR);
        ets_delay_us(100);
    }
    
    return sum / samples;
}

// 校准函数(示例使用二次多项式)
float calibrate_light(int raw) {
    // 这些系数需要根据实际校准数据确定
    const float a = 0.00002;
    const float b = -0.015;
    const float c = 4.2;
    
    return a * raw * raw + b * raw + c;  // 返回校准后的光照强度(单位:lux)
}

void app_main() {
    setup_adc();
    
    while(1) {
        int raw = read_light_sensor_raw();
        float lux = calibrate_light(raw);
        
        printf("原始值: %d, 校准后光照强度: %.2f lux\n", raw, lux);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
            
客服小姐姐(优先添加)

客服小姐姐(优先添加)

客服微信

讲师微信(备用)