Arduino框架下I2S控制ADC采样以及PWM输出示例解析
Posted perseverance52
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Arduino框架下I2S控制ADC采样以及PWM输出示例解析相关的知识,希望对你有一定的参考价值。
Arduino框架下I2S控制ADC采样以及PWM输出示例
ESP32 LED PWM 控制器介绍
LED PWM 控制器主要用于控制 LED,也可产生 PWM 信号用于其他设备的控制。该控制器有 8 路高速通道和 8 路低速通道。
LED PWM 控制器的高速通道和低速通道均支持硬件渐变功能,可在无需 CPU 干预的情况下自动改变 PWM 信号的占空比,也可由软件改变 PWM 信号的占空比,实现亮度和颜色渐变。此外,低速通道在 Sleep 模式下仍可运行。
LED PWM 控制器 高速模式或低速模式 通道运行的配置选项:
- 配置定时器:指定 PWM 信号的频率和占空比分辨率。
- 配置通道:绑定定时器和输出 PWM 信号的 GPIO引脚。
- 改变 PWM 信号:输出 PWM 信号来驱动 LED。可通过软件控制或使用硬件渐变功能来改变 LED 的亮度。
- 信息参考来源;
https://docs.espressif.com/projects/esp-idf/zh_CN/v4.3.1/esp32/api-reference/peripherals/ledc.html#ledc-api-supported-range-frequency-duty-resolution
频率和占空比分辨率支持范围
ledcSetup(channel, freq, resolution);
// 设置通道,频率,占空比分辨率
channel
:通道0 -7 为高速通道,7-15 为低速通道
freq
:频率,最大设置5000
resolution
:占空比分辨率
LED PWM 控制器主要用于驱动 LED。该控制器 PWM 占空比设置的分辨率范围较广。比如,PWM 频率为 5 kHz 时,占空比分辨率最大可为 13 位。这意味着占空比可为 0 至 100% 之间的任意值,分辨率为 ~0.012%(2 ** 13 = 8192 LED 亮度的离散电平)。
LED PWM 控制器可用于生成频率较高的信号,足以为数码相机模组等其他设备计时。此时,最大频率可为 40 MHz,占空比分辨率为 1 位。也就是说,占空比固定为 50%,无法调整。
LED PWM 控制器 API 可在设定的频率和占空比分辨率超过 LED PWM 控制器硬件范围时报错。例如,试图将频率设置为 20 MHz、占空比分辨率设置为 3 位时,串行端口监视器上会报告如下错误:
E (196) ledc: requested frequency and duty resolution cannot be achieved, try reducing freq_hz or duty_resolution. div_param=128
此时,占空比分辨率或频率必须降低。比如,将占空比分辨率设置为 2 会解决这一问题,让占空比设置为 25% 的倍数,即 25%、50% 或 75%。
- 如设置的频率和占空比分辨率低于所支持的最低值,LED PWM 驱动器也会反映并报告,如:
E (196) ledc: requested frequency and duty resolution cannot be achieved, try increasing freq_hz or duty_resolution. div_param=128000000
占空比分辨率通常用 ledc_timer_bit_t 设置,范围是 10 至 15位。如需较低的占空比分辨率(上至 10,下至 1),可直接输入相应数值。
ADC通道与引脚映射关系
ADC 输入通道具有 12 位分辨率。范围从 0 - 4095 的模拟读数,其中 0 对应于 0V,4095 对应于
3.3
V。您还可以在代码和 ADC 范围上设置通道的分辨率。
ESP32 ADC 引脚没有线性行为。您可能无法区分 0 和 0.1V,或 3.2 和 3.3V。
I2S ADC
- I2S ADC的采样频率最大值为5MHz(值为5000000)
- 初始化配置函数
void i2sInit()
i2s_config_t i2s_config =
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = I2S_SAMPLE_RATE, // The format of the signal using ADC_BUILT_IN
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = I2S_DMA_BUF_LEN,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
;
示例代码
/*
This example demonstrates I2S ADC capability to sample high frequency analog signals.
The PWM signal generated with ledc is only for ease of use when first trying out.
To sample the generated signal connect default pins 22(PWM) and 32(Sampling) together.
If you do not wish to generate PWM simply comment out the definition of constant GENERATE_PWM
如果不希望生成PWM,只需注释掉常量GENERATE_PWM的定义
Try to change the PWM_DUTY_PERCENT and see how to averaged value changes.
The maximum for I2S ADC sampling frequency is 5MHz (value 5000000), however there will be many values repeated because the real
I2S ADC的采样频率最大值为5MHz(值为5000000),但是由于真实的采样频率,会有很多值重复。
sampling frequency is much lower -
By default this example will print values compatible with Arduino plotter
1. signal - all values
2. signal - averaged value
You can change the number of sample over which is the signal averaged by changing value of AVERAGE_EVERY_N_SAMPLES
If you comment the definition altogether the averaging will not be performed nor printed.
If you do not wish to print every value, simply comment definition of constant PRINT_ALL_VALUES
Note: ESP prints messages at startup which will pollute Arduino IDE Serial plotter legend.
To avoid this pollution, start the plotter after startup (op restart)
*/
#include <driver/i2s.h>
// I2S(ADC输入GPIO 32)
#define I2S_SAMPLE_RATE (20000) // Max sampling frequency(最大采样频率) = 277.777 kHz
#define ADC_INPUT (ADC1_CHANNEL_4) //pin 32
#define I2S_DMA_BUF_LEN (1024)
// PWM输出
#define GENERATE_PWM
#define OUTPUT_PIN (22) //Pin 22
#define PWM_FREQUENCY ((I2S_SAMPLE_RATE)/4) //PWM 频率为 I2S采样率的1/4
#define PWM_DUTY_PERCENT (50)//占空比
//PWM 频率越高,占空比分辨率越低,反之则越高
#define PWM_RESOLUTION_BITS (2) //较低的比特分辨率可以获得更高的频率,占空比分辨率设置为 25% 的倍数,即 25%、50% 或 75%。
#define PWM_DUTY_VALUE ((((1<<(PWM_RESOLUTION_BITS)))*(PWM_DUTY_PERCENT))/100) // Duty value used for setup function based on resolution占空值用于根据分辨率设置功能
// Sample post processing
#define PRINT_ALL_VALUES
#define AVERAGE_EVERY_N_SAMPLES (20)
void i2sInit()
i2s_config_t i2s_config =
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = I2S_SAMPLE_RATE, // The format of the signal using ADC_BUILT_IN
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = I2S_DMA_BUF_LEN,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
;
Serial.printf("Attempting to setup I2S ADC with sampling frequency %d Hz\\n", I2S_SAMPLE_RATE);//69444
if(ESP_OK != i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL))
Serial.printf("Error installing I2S. Halt!");
while(1);
if(ESP_OK != i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT))
Serial.printf("Error setting up ADC. Halt!");
while(1);
if(ESP_OK != adc1_config_channel_atten(ADC_INPUT, ADC_ATTEN_DB_11))
Serial.printf("Error setting up ADC attenuation. Halt!");
while(1);
if(ESP_OK != i2s_adc_enable(I2S_NUM_0))
Serial.printf("Error enabling ADC. Halt!");
while(1);
Serial.printf("I2S ADC setup ok\\n");
void setup()
Serial.begin(115200);
while(!Serial);
#ifdef GENERATE_PWM
// PWM setup
Serial.printf("Setting up PWM: frequency = %d; resolution bits %d; Duty cycle = %d; duty value = %d, Output pin = %d\\n", PWM_FREQUENCY, PWM_RESOLUTION_BITS, PWM_DUTY_PERCENT, PWM_DUTY_VALUE, OUTPUT_PIN);
uint32_t freq = ledcSetup(0, PWM_FREQUENCY , 12);//通道 频率 分辨率
if(freq != PWM_FREQUENCY)
Serial.printf("Error setting up PWM. Halt!");
while(1);
ledcAttachPin(OUTPUT_PIN, 0);
ledcWrite(0, PWM_DUTY_VALUE);
Serial.printf("PWM setup ok\\n");
#endif
// Initialize the I2S peripheral
i2sInit();
void loop()
// The 4 high bits are the channel, and the data is inverted
size_t bytes_read;
uint16_t buffer[I2S_DMA_BUF_LEN] = 0;
#ifdef AVERAGE_EVERY_N_SAMPLES
uint32_t read_counter = 0;
uint32_t averaged_reading = 0;
uint64_t read_sum = 0;
#endif
while(1)
i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, 15);
//Serial.printf("read %d Bytes\\n", bytes_read);
for(int i = 0; i < bytes_read/2; ++i)
#ifdef PRINT_ALL_VALUES
//Serial.printf("[%d] = %d\\n", i, buffer[i] & 0x0FFF); // Print with indexes
Serial.printf("Signal:%d ", buffer[i] & 0x0FFF); // Print compatible with Arduino Plotter
#endif
#ifdef AVERAGE_EVERY_N_SAMPLES
read_sum += buffer[i] & 0x0FFF;
++read_counter;
if(read_counter == AVERAGE_EVERY_N_SAMPLES)
averaged_reading = read_sum / AVERAGE_EVERY_N_SAMPLES;
//Serial.printf("averaged_reading = %d over %d samples\\n", averaged_reading, read_counter); // Print with additional info
Serial.printf("Averaged_signal:%d", averaged_reading); // Print compatible with Arduino Plotter
read_counter = 0;
read_sum = 0;
#endif
#if defined(PRINT_ALL_VALUES) || defined (AVERAGE_EVERY_N_SAMPLES)
Serial.printf("\\n");
#endif
// for
// while
-
串口监视器输出信息
-
串口绘图器波形
- 相关文章:基于ESP-IDF《ESP32使用I2S控制ADC和DAC》
- 官方文档《LED PWM 控制器》
以上是关于Arduino框架下I2S控制ADC采样以及PWM输出示例解析的主要内容,如果未能解决你的问题,请参考以下文章
CH559L单片机基于Arduino框架下实现USB CDC虚拟串口打印ADC数据