
硬件ESP32-Devkit-V4 MODEL:ESP32-32U库ESP-IDF v5.4.1系统windows中的虚拟机 ubuntu 22.041. 核心驱动模块ADC 外设驱动 (driver/adc.h)基础配置通道、衰减、位宽。List item适用于单次读取手动触发。ADC 连续转换驱动 (driver/adc_continuous.h)支持 DMA 传输可连续采集多通道。List item适用于音频、实时监测等场景。2. ADC 外设驱动 API单次读取头文件#ifndefBSP_ADC_H_#defineBSP_ADC_H_voidadc_run_task(void*arg);#endif源文件#includebsp_adc.h#includestring.h#includestdio.h#includesdkconfig.h#includeesp_log.h#includefreertos/FreeRTOS.h#includefreertos/task.h#includefreertos/semphr.h#includeesp_adc/adc_continuous.h#defineEXAMPLE_ADC_UNITADC_UNIT_1#define_EXAMPLE_ADC_UNIT_STR(unit)#unit#defineEXAMPLE_ADC_UNIT_STR(unit)_EXAMPLE_ADC_UNIT_STR(unit)#defineEXAMPLE_ADC_CONV_MODEADC_CONV_SINGLE_UNIT_1#defineEXAMPLE_ADC_ATTENADC_ATTEN_DB_0#defineEXAMPLE_ADC_BIT_WIDTHSOC_ADC_DIGI_MAX_BITWIDTH#ifCONFIG_IDF_TARGET_ESP32||CONFIG_IDF_TARGET_ESP32S2#defineEXAMPLE_ADC_OUTPUT_TYPEADC_DIGI_OUTPUT_FORMAT_TYPE1#defineEXAMPLE_ADC_GET_CHANNEL(p_data)((p_data)-type1.channel)#defineEXAMPLE_ADC_GET_DATA(p_data)((p_data)-type1.data)#else#defineEXAMPLE_ADC_OUTPUT_TYPEADC_DIGI_OUTPUT_FORMAT_TYPE2#defineEXAMPLE_ADC_GET_CHANNEL(p_data)((p_data)-type2.channel)#defineEXAMPLE_ADC_GET_DATA(p_data)((p_data)-type2.data)#endif#defineEXAMPLE_READ_LEN256#ifCONFIG_IDF_TARGET_ESP32staticadc_channel_tchannel[2]{ADC_CHANNEL_6,ADC_CHANNEL_7};#elsestaticadc_channel_tchannel[2]{ADC_CHANNEL_2,ADC_CHANNEL_3};#endifstaticTaskHandle_t s_task_handle;staticconstchar*TAGEXAMPLE;staticbool IRAM_ATTRs_conv_done_cb(adc_continuous_handle_thandle,constadc_continuous_evt_data_t*edata,void*user_data){BaseType_t mustYieldpdFALSE;//Notify that ADC continuous driver has done enough number of conversionsvTaskNotifyGiveFromISR(s_task_handle,mustYield);return(mustYieldpdTRUE);}staticvoidcontinuous_adc_init(adc_channel_t*channel,uint8_tchannel_num,adc_continuous_handle_t*out_handle){adc_continuous_handle_thandleNULL;adc_continuous_handle_cfg_tadc_config{.max_store_buf_size1024,.conv_frame_sizeEXAMPLE_READ_LEN,};ESP_ERROR_CHECK(adc_continuous_new_handle(adc_config,handle));adc_continuous_config_tdig_cfg{.sample_freq_hz20*1000,.conv_modeEXAMPLE_ADC_CONV_MODE,.formatEXAMPLE_ADC_OUTPUT_TYPE,};adc_digi_pattern_config_tadc_pattern[SOC_ADC_PATT_LEN_MAX]{0};dig_cfg.pattern_numchannel_num;for(inti0;ichannel_num;i){adc_pattern[i].attenEXAMPLE_ADC_ATTEN;adc_pattern[i].channelchannel[i]0x7;adc_pattern[i].unitEXAMPLE_ADC_UNIT;adc_pattern[i].bit_widthEXAMPLE_ADC_BIT_WIDTH;ESP_LOGI(TAG,adc_pattern[%d].atten is :%PRIx8,i,adc_pattern[i].atten);ESP_LOGI(TAG,adc_pattern[%d].channel is :%PRIx8,i,adc_pattern[i].channel);ESP_LOGI(TAG,adc_pattern[%d].unit is :%PRIx8,i,adc_pattern[i].unit);}dig_cfg.adc_patternadc_pattern;ESP_ERROR_CHECK(adc_continuous_config(handle,dig_cfg));*out_handlehandle;}voidadc_run_task(void*arg){esp_err_tret;uint32_tret_num0;uint8_tresult[EXAMPLE_READ_LEN]{0};memset(result,0xcc,EXAMPLE_READ_LEN);s_task_handlexTaskGetCurrentTaskHandle();adc_continuous_handle_thandleNULL;continuous_adc_init(channel,sizeof(channel)/sizeof(adc_channel_t),handle);adc_continuous_evt_cbs_tcbs{.on_conv_dones_conv_done_cb,};ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(handle,cbs,NULL));ESP_ERROR_CHECK(adc_continuous_start(handle));while(1){/** * This is to show you the way to use the ADC continuous mode driver event callback. * This ulTaskNotifyTake will block when the data processing in the task is fast. * However in this example, the data processing (print) is slow, so you barely block here. * * Without using this event callback (to notify this task), you can still just call * adc_continuous_read() here in a loop, with/without a certain block timeout. */ulTaskNotifyTake(pdTRUE,portMAX_DELAY);charunit[]EXAMPLE_ADC_UNIT_STR(EXAMPLE_ADC_UNIT);while(1){retadc_continuous_read(handle,result,EXAMPLE_READ_LEN,ret_num,0);if(retESP_OK){ESP_LOGI(TASK,ret is %x, ret_num is %PRIu32 bytes,ret,ret_num);for(inti0;iret_num;iSOC_ADC_DIGI_RESULT_BYTES){adc_digi_output_data_t*p(adc_digi_output_data_t*)result[i];uint32_tchan_numEXAMPLE_ADC_GET_CHANNEL(p);uint32_tdataEXAMPLE_ADC_GET_DATA(p);/* Check the channel number validation, the data is invalid if the channel num exceed the maximum channel */if(chan_numSOC_ADC_CHANNEL_NUM(EXAMPLE_ADC_UNIT)){ESP_LOGI(TAG,Unit: %s, Channel: %PRIu32, Value: %PRIx32,unit,chan_num,data);}else{ESP_LOGW(TAG,Invalid data [%s_%PRIu32_%PRIx32],unit,chan_num,data);}}/** * Because printing is slow, so every time you call ulTaskNotifyTake, it will immediately return. * To avoid a task watchdog timeout, add a delay here. When you replace the way you process the data, * usually you dont need this delay (as this task will block for a while). */vTaskDelay(1);}elseif(retESP_ERR_TIMEOUT){//We try to read EXAMPLE_READ_LEN until API returns timeout, which means theres no available databreak;}}}ESP_ERROR_CHECK(adc_continuous_stop(handle));ESP_ERROR_CHECK(adc_continuous_deinit(handle));}