/* * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "soc/dac_channel.h" #include "esp_adc/adc_oneshot.h" #include "esp_check.h" #include "dac_continuous_example.h" /** * 有两种方式可以连续将数字数据转换为模拟信号: * - 使用定时器:在定时器中断中定期设置DAC电压 * 这种方式,DAC可以达到相对较低的转换频率 * 但与使用DMA相比,这不是一种高效的方式 * - 使用DMA:通过DMA传输数据缓冲区, * 转换频率由DMA传输速度控制 * 这种方式,转换频率可以达到几MHz, * 但由于受DMA时钟源限制,无法达到很低的转换频率 * 一般来说,推荐使用DMA,如果DMA外设被占用或所需的转换频率很低, * 则使用定时器代替 */ /* ADC配置 */ #if CONFIG_IDF_TARGET_ESP32 #define EXAMPLE_DAC_CHAN0_ADC_CHAN ADC_CHANNEL_8 // GPIO25,与DAC通道0相同 #define EXAMPLE_DAC_CHAN1_ADC_CHAN ADC_CHANNEL_9 // GPIO26,与DAC通道1相同 #define EXAMPLE_ADC_WIDTH ADC_WIDTH_BIT_12 #elif CONFIG_IDF_TARGET_ESP32S2 #define EXAMPLE_DAC_CHAN0_ADC_CHAN ADC_CHANNEL_6 // GPIO17,与DAC通道0相同 #define EXAMPLE_DAC_CHAN1_ADC_CHAN ADC_CHANNEL_7 // GPIO18,与DAC通道1相同 #define EXAMPLE_ADC_WIDTH ADC_WIDTH_BIT_13 #endif #define EXAMPLE_DAC_CHAN0_IO DAC_CHAN0_GPIO_NUM // DAC通道0的IO号 #define EXAMPLE_DAC_CHAN1_IO DAC_CHAN1_GPIO_NUM // DAC通道1的IO号 #define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_12 _Static_assert(EXAMPLE_DAC_AMPLITUDE < 256, "DAC精度为8位,不支持超过255的幅度"); static const char *TAG = "dac continuous"; uint8_t sin_wav[EXAMPLE_ARRAY_LEN]; // 用于存储正弦波值 uint8_t tri_wav[EXAMPLE_ARRAY_LEN]; // 用于存储三角波值 uint8_t saw_wav[EXAMPLE_ARRAY_LEN]; // 用于存储锯齿波值 uint8_t squ_wav[EXAMPLE_ARRAY_LEN]; // 用于存储方波值 static void example_generate_wave(void) { uint32_t pnt_num = EXAMPLE_ARRAY_LEN; for (int i = 0; i < pnt_num; i ++) { sin_wav[i] = (uint8_t)((sin(i * CONST_PERIOD_2_PI / pnt_num) + 1) * (double)(EXAMPLE_DAC_AMPLITUDE) / 2 + 0.5); tri_wav[i] = (i > (pnt_num / 2)) ? (2 * EXAMPLE_DAC_AMPLITUDE * (pnt_num - i) / pnt_num) : (2 * EXAMPLE_DAC_AMPLITUDE * i / pnt_num); saw_wav[i] = (i == pnt_num) ? 0 : (i * EXAMPLE_DAC_AMPLITUDE / pnt_num); squ_wav[i] = (i < (pnt_num / 2)) ? EXAMPLE_DAC_AMPLITUDE : 0; } } void example_log_info(uint32_t conv_freq, uint32_t wave_freq) { ESP_LOGI(TAG, "--------------------------------------------------"); #if CONFIG_EXAMPLE_DAC_CONTINUOUS_BY_DMA ESP_LOGI(TAG, "DAC continuous output by DMA"); #else ESP_LOGI(TAG, "DAC continuous output by timer"); #endif ESP_LOGI(TAG, "DAC channel 0 io: GPIO_NUM_%d", EXAMPLE_DAC_CHAN0_IO); ESP_LOGI(TAG, "DAC channel 1 io: GPIO_NUM_%d", EXAMPLE_DAC_CHAN1_IO); ESP_LOGI(TAG, "Waveform: SINE -> TRIANGLE -> SAWTOOTH -> SQUARE"); ESP_LOGI(TAG, "DAC conversion frequency (Hz): %"PRIu32, conv_freq); ESP_LOGI(TAG, "DAC wave frequency (Hz): %"PRIu32, wave_freq); ESP_LOGI(TAG, "--------------------------------------------------"); } static void adc_monitor_task(void *args) { adc_oneshot_unit_handle_t adc2_handle = (adc_oneshot_unit_handle_t)args; int chan0_val = 0; int chan1_val = 0; while (1) { /* 读取DAC输出电压 */ ESP_ERROR_CHECK(adc_oneshot_read(adc2_handle, EXAMPLE_DAC_CHAN0_ADC_CHAN, &chan0_val)); ESP_ERROR_CHECK(adc_oneshot_read(adc2_handle, EXAMPLE_DAC_CHAN1_ADC_CHAN, &chan1_val)); printf("DAC channel 0 value: %4d\tDAC channel 1 value: %4d\n", chan0_val, chan1_val); vTaskDelay(pdMS_TO_TICKS(100)); } } void app_main(void) { example_generate_wave(); #if CONFIG_EXAMPLE_DAC_CONTINUOUS_BY_DMA /* 使用DMA输出2kHz波形 */ example_dac_continuous_by_dma(); #else /* 使用定时器中断输出50Hz波形 */ example_dac_continuous_by_timer(); #endif /* 设置ADC2通道,这些通道内部连接到DAC通道 */ adc_oneshot_unit_handle_t adc2_handle; adc_oneshot_unit_init_cfg_t adc_cfg = { .unit_id = ADC_UNIT_2, .ulp_mode = false, }; ESP_ERROR_CHECK(adc_oneshot_new_unit(&adc_cfg, &adc2_handle)); adc_oneshot_chan_cfg_t chan_cfg = { .atten = EXAMPLE_ADC_ATTEN, .bitwidth = ADC_BITWIDTH_DEFAULT, }; ESP_ERROR_CHECK(adc_oneshot_config_channel(adc2_handle, EXAMPLE_DAC_CHAN0_ADC_CHAN, &chan_cfg)); ESP_ERROR_CHECK(adc_oneshot_config_channel(adc2_handle, EXAMPLE_DAC_CHAN1_ADC_CHAN, &chan_cfg)); /* 创建ADC监控任务以检测DAC引脚上的电压 */ xTaskCreate(adc_monitor_task, "adc_monitor_task", 4096, adc2_handle, 5, NULL); }