ESP32S3基于espidf ADC使用

ESP32S3基于espidf ADC使用


  • 官方在线文档介绍模数转换器:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/peripherals/adc_oneshot.html
  • 🔖espidf版本:v5.4
  • 模数转换器 (ADC)转换方式:
    • 模数转换器 (ADC) 单次转换模式驱动
    • 模数转换器 (ADC) 连续转换模式驱动
    • 模数转换器 (ADC) 带校准驱动
  • ESP32-S3 功能框图
    在这里插入图片描述

ESP32S3 ADC介绍

ESP32-S3 内置了两个 12 位的 SAR ADC,可测量最多来自 20 个管脚的模拟信号。

  • SAR ADC概图
    在这里插入图片描述
主要特性
  • 支持 12 位采样分辨率
    • 支持采集最多 20 个管脚上的模拟电压

  • RTC ADC1/2 控制器:
    – 支持单次转换
    – 支持在低功耗模式下工作,如 Deep-sleep
    – 可由 ULP 协处理器配置

  • DIG ADC1 控制器:
    – 配有多通道扫描控制模块,支持多通道扫描模式
    – 提供模式控制模块,支持单 SAR ADC 采样模式
    – 在多通道扫描模式下,支持自定义扫描通道顺序
    – 提供两个滤波器,滤波系数可配
    – 支持阈值监控,采样值大于设置的高阈值或小于设置的低阈值将产生中断
    – 支持 DMA。

  • SAR ADC 的主要元件与连接情况见图
    在这里插入图片描述
    在这里插入图片描述

  • SAR ADC 模块主要包括以下部分:
    • SAR ADC1:可对 10 个通道进行电压检测;
    • SAR ADC2:可对 10 个通道进行电压检测;

  • SAR ADC 的信号输入
    在这里插入图片描述
    在这里插入图片描述

ADC 转换和衰减

SAR ADC 转换模拟信号时,转换分辨率(12 位)电压范围为 0 mV ~ Vref。其中,Vref 为 SAR ADC 内部参考电
压,出厂设定为 1100 mV。因此,转换结果 (data) 可以使用以下公式转换成模拟电压输出 Vdata:
在这里插入图片描述

  • ADC 经硬件校准和 软件校准后的结果如表下表 所示。如需更高的精度,可选用其他方法自行校准。
    在这里插入图片描述
  • ✨在使用ADC测量模拟输入电压时,被测电压信号,阈值最好不要超过3V。不然精度会比上表所述低。
  • 针对esp32型号,只有在未启动Wi-Fi 驱动程序下,才能使用 ADC2。
    在这里插入图片描述
  • esp32S3 SAR ADC2的数字控制器无法工作

ESP32-S3 SAR ADC2 的数字控制器(即DIGADC2控制器)可能收到错误的采样启动信号,导致控制器进入无法工作的状态。

  • 无变通方法。建议使用RTC控制器来控制SAR ADC2。

🔰编译器不同版本和ADC驱动程序差异

  • 在当前所使用的v5.4版本下,所调用的ADC驱动头文件:
    adc_cali.h
    adc_cali_scheme.h
    adc_continuous.h
    adc_oneshot.h
  • 在旧版本中,所包含的头文件:
#include "driver/adc.h"

当前版本(v5.4)下,部分旧版本的API程序还是可以使用,可能在未来某个版本中会全部移除。有些API已经不支持了,仍继续使用的话,程序运行可能会报错。并且编译时会报警告信息:

#warning "legacy adc driver is deprecated, please migrate to use esp_adc/adc_oneshot.h and esp_adc/adc_continuous.h for oneshot mode and continuous mode drivers respectively"

📘数转换器 (ADC) 单次转换模式驱动


  • 所需包含的头文件:
#include "esp_adc/adc_oneshot.h"
  • ADC 驱动代码
  • 模数转换器 (ADC) 单次转换模式驱动可以参考:v5.4\esp-idf\examples\peripherals\adc\oneshot_read
#include <stdio.h>
#include "esp_adc/adc_oneshot.h"

#define ADC1_CHANNEL ADC_CHANNEL_6  // 使用 ADC1 通道 6 (GPIO 6)
#define ADC_ATTEN    ADC_ATTEN_DB_12  // 衰减值
#define ADC_BITWIDTH ADC_BITWIDTH_12  // 位宽

void app_main(void) {
    // 初始化 ADC 单元
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config = {
        .unit_id = ADC_UNIT_1,  // 使用 ADC1
    };
    ESP_ERROR_CHECK(adc_oneshot_unit_init(&init_config, &adc1_handle));

    // 配置 ADC 通道
    adc_oneshot_chan_cfg_t channel_config = {
        .atten = ADC_ATTEN,  // 衰减值
        .bitwidth = ADC_BITWIDTH,  // 位宽
    };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_CHANNEL, &channel_config));

    // 读取 ADC 值
    while (1) {
        int adc_raw_value = 0;
        ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_CHANNEL, &adc_raw_value));
        printf("ADC Raw Value: %d\n", adc_raw_value);

        // 延时 1 秒
        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    // 释放资源(此代码不会执行到此处,仅为示例)
    ESP_ERROR_CHECK(adc_oneshot_unit_deinit(adc1_handle));
}

在这里插入图片描述

📗模数转换器 (ADC) 校准驱动

#include <stdio.h>
#include "driver/gpio.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_oneshot.h"
//#include "esp_adc/adc_oneshot_unit.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_err.h"

#define TAG "ADC_CAL"

#define DEFAULT_VREF    1100  // 默认内部参考电压 (mV)
#define NO_OF_SAMPLES   64    // 采样次数
#define ADC1_CHANNEL ADC_CHANNEL_6  // 使用 ADC1 通道 6 (GPIO 6)
#define ADC_ATTEN    ADC_ATTEN_DB_12  // 衰减值
#define ADC_BITWIDTH ADC_BITWIDTH_12  // 位宽

void app_main(void) {

   // 初始化 ADC 单元
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config = {
        .unit_id = ADC_UNIT_1,  // 使用 ADC1
    };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc1_handle));

    // 配置 ADC 通道
    adc_oneshot_chan_cfg_t channel_config = {
        .atten = ADC_ATTEN,  // 衰减值
        .bitwidth = ADC_BITWIDTH,  // 位宽
    };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_CHANNEL, &channel_config));
   // 初始化校准方案
    adc_cali_handle_t adc_cali_handle = NULL;
    adc_cali_curve_fitting_config_t cali_config = {
        .unit_id = ADC_UNIT_1,
        .atten = ADC_ATTEN,
        .bitwidth = ADC_BITWIDTH,
    };
    esp_err_t ret = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle);
 
    if (ret == ESP_OK) {
        printf("Calibration scheme created successfully\n");
    } else {
        printf("Failed to create calibration scheme\n");
        return;
    }

    while (1) {


    int adc_raw_value = 0;
        ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_CHANNEL, &adc_raw_value));
        printf("ADC Raw Value: %d\n", adc_raw_value);
        // 将原始值转换为电压
        int voltage = 0;
        if (adc_cali_raw_to_voltage(adc_cali_handle, adc_raw_value, &voltage) == ESP_OK) {
            printf("ADC Raw Value: %d\tVoltage: %dmV\n", adc_raw_value, voltage);
        } else {
            printf("Failed to convert raw value to voltage\n");
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
       // 释放校准方案资源
  //  ESP_ERROR_CHECK(adc_cali_delete_scheme(adc_cali_handle));
    // 释放 ADC 单元资源(此代码不会执行到此处,仅为示例)
  //  ESP_ERROR_CHECK(adc_oneshot_unit_deinit(adc1_handle));
}

在这里插入图片描述

📒模数转换器 (ADC) 连续转换模式驱动

  • 可以参考例程:v5.4\esp-idf\examples\peripherals\adc\continuous_read
  • ✨连续转换模式需要注意,输出数据格式,只能选择类型2:ADC_DIGI_OUTPUT_FORMAT_TYPE2,否则,使用类型1,烧录后会报错:
    在这里插入图片描述
单通道转换模式和连续多通道转换模式共用驱动实现程序
#include <stdio.h>
#include "driver/gpio.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_err.h"

#define TAG "ADC_CAL"

#define DEFAULT_VREF    1100  // 默认内部参考电压 (mV)
#define NO_OF_SAMPLES   64    // 采样次数
#define ADC1_CHANNEL ADC_CHANNEL_6  // 使用 ADC1 通道 6 (GPIO 6)
#define ADC_ATTEN    ADC_ATTEN_DB_12  // 衰减值
#define ADC_BITWIDTH ADC_BITWIDTH_12  // 位宽
#define ADC_CONV_MODE ADC_CONV_SINGLE_UNIT_1  // 使用 ADC1 单通道模式
#define DMA_BUFFER_SIZE 8                  // DMA 缓冲区大小
#define SAMPLE_RATE   10000                   // 采样率 (Hz)

//#define oneshot    1		//oneshot模式启用
#define continuous 1		//连续转换模式启用

void app_main(void) {
#ifdef oneshot
    // 初始化 ADC 单元
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config = {
       .unit_id = ADC_UNIT_1,  // 使用 ADC1
    };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc1_handle));
   // 初始化 ADC 单元
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config = {
        .unit_id = ADC_UNIT_1,  // 使用 ADC1
    };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc1_handle));

    // 配置 ADC 通道
    adc_oneshot_chan_cfg_t channel_config = {
        .atten = ADC_ATTEN,  // 衰减值
        .bitwidth = ADC_BITWIDTH,  // 位宽
    };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_CHANNEL, &channel_config));
 #elif continuous
    // 初始化 ADC 连续模式句柄
    adc_continuous_handle_t adc_handle = NULL;
    adc_continuous_handle_cfg_t handle_cfg = {
        .max_store_buf_size = DMA_BUFFER_SIZE,  // DMA 缓冲区大小
        .conv_frame_size = DMA_BUFFER_SIZE,     // 每帧数据大小
    };
    ESP_ERROR_CHECK(adc_continuous_new_handle(&handle_cfg, &adc_handle));
 // 配置 ADC 通道
    adc_digi_pattern_config_t adc_pattern_ch[2] = {
        {
            .atten = ADC_ATTEN,
            .channel = ADC_CHANNEL_6,
            .unit = ADC_UNIT_1,
            .bit_width = ADC_BITWIDTH,
        },
        {
            .atten = ADC_ATTEN,
            .channel = ADC_CHANNEL_7,
            .unit = ADC_UNIT_1,
            .bit_width = ADC_BITWIDTH,
        },
    };
    // 配置 ADC 连续模式
    adc_continuous_config_t adc_config = {
        .pattern_num = 2,  // 使用 2 个通道
        .adc_pattern = adc_pattern_ch,
        .sample_freq_hz = SAMPLE_RATE,  // 采样率
        .conv_mode = ADC_CONV_MODE,     // 转换模式
        .format = ADC_DIGI_OUTPUT_FORMAT_TYPE2,  // 输出格式
    };
    ESP_ERROR_CHECK(adc_continuous_config(adc_handle, &adc_config));

    // 启动连续采样
    ESP_ERROR_CHECK(adc_continuous_start(adc_handle));
    ESP_LOGI(TAG, "ADC continuous mode started");

    // 读取采样数据
    uint8_t buffer[DMA_BUFFER_SIZE] = {0};

#endif
    while (1) {

#ifdef oneshot
    int adc_raw_value = 0;
        ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_CHANNEL, &adc_raw_value));
        printf("ADC Raw Value: %d\n", adc_raw_value);
        // 将原始值转换为电压
        int voltage = 0;
        if (adc_cali_raw_to_voltage(adc_cali_handle, adc_raw_value, &voltage) == ESP_OK) {
            printf("ADC Raw Value: %d\tVoltage: %dmV\n", adc_raw_value, voltage);
        } else {
            printf("Failed to convert raw value to voltage\n");
        }
 #elif continuous

        // 读取采样数据
               uint32_t ret_num = 0;
        esp_err_t ret = adc_continuous_read(adc_handle, buffer, DMA_BUFFER_SIZE, &ret_num, 0);
        if (ret == ESP_OK) {
            ESP_LOGI(TAG, "Read %"PRIu32" bytes of data", ret_num);
            // 处理采样数据(例如打印或存储)
            // for (int i = 0; i < ret_num; i += 2) {  // 假设每个采样点占 2 字节
            //     uint16_t adc_value = (buffer[i + 1] << 8) | buffer[i];
            //     printf("ADC Value: %d\n", adc_value);
            // }
             // 解析 TYPE2 格式的数据
            for (int i = 0; i < ret_num; i += 2) {  // 每个采样点占 2 字节
                uint16_t adc_value = (buffer[i + 1] << 8) | buffer[i];
                uint8_t unit = (adc_value >> 12) & 0x0F;  // 提取单元标识
                uint16_t raw_data = adc_value & 0x0FFF;   // 提取 12 位原始数据
                printf("Unit: %d, Raw Data: %d\n", unit, raw_data);
            }
        } else {
            ESP_LOGE(TAG, "Failed to read data: %d", ret);
        }
#endif
        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    // 单采样释放校准方案资源
  //  ESP_ERROR_CHECK(adc_cali_delete_scheme(adc_cali_handle));
    // 释放 ADC 单元资源(此代码不会执行到此处,仅为示例)
  //  ESP_ERROR_CHECK(adc_oneshot_unit_deinit(adc1_handle));
  // 连续采样停止采样并释放资源
    // ESP_ERROR_CHECK(adc_continuous_stop(adc_handle));
    // ESP_ERROR_CHECK(adc_continuous_deinit(adc_handle));
    // ESP_LOGI(TAG, "ADC continuous mode stopped");
}

  • 🔖CMakeLists.txt:
idf_component_register(SRCS "main.c"
                    INCLUDE_DIRS "."
                    REQUIRES driver esp_adc)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值