Stm32 adc多通道+dma传输(乒乓缓冲)
adc配置连续转换模式,ADC在完成一次转换(或一次扫描序列)后,自动开始下一次转换,无需再次调用 HAL_ADC_Start。后3个存入buffer2,使能DMA中断处理adc_buffer2。前3个存入Buffer1,使能DMA半中断处理buffer1。存储6个数据进入缓冲区。
·
1.多通道DMA传输
adc配置连续转换模式,ADC在完成一次转换(或一次扫描序列)后,自动开始下一次转换,无需再次调用 HAL_ADC_Start
DMA配置
代码
/* ADC buffer for DMA */
uint16_t adc_buffer[3]; // DMA缓冲区
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
/* 校准ADC */
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
/* 启动ADC和DMA */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 3); //数据存入adc_buffer
while (1)
{
}
}
2.多通道DMA传输(乒乓缓存)
简述:
- 当DMA将数据传输到 buffer1(Ping)时,CPU可以同时处理 buffer2(Pong)中的数据。
- 当 buffer1 填满后,DMA切换到 buffer2,CPU则处理刚填满的 buffer1。
- 如此循环,形似“乒乓”球的来回切换。
原理:
存储6个数据进入缓冲区
前3个存入Buffer1,使能DMA半中断处理buffer1
后3个存入buffer2,使能DMA中断处理adc_buffer2
uint16_t adc_buffer1[3]; // 第一个缓冲区(保证两个地址是连续的)
uint16_t adc_buffer2[3]; // 第二个缓冲区(保证两个地址是连续的)
/* 启动ADC和DMA */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer1, BUFFER_SIZE*2);
// 前3个存入Buffer1,后3个存入buffer2
代码配置:
确保dma中断使能
主程序
/* ADC buffers for ping-pong mechanism */
uint16_t adc_buffer1[3]; // 第一个缓冲区(保证两个地址是连续的)
uint16_t adc_buffer2[3]; // 第二个缓冲区(保证两个地址是连续的)
uint16_t* current_adc_buffer = adc_buffer1; // 当前就绪的缓冲区
volatile uint8_t buffer_ready = 0; // 缓冲区就绪标志
volatile uint32_t sample_counter = 0; // 采样计数器,用于控制输出频率
//DMA半中断
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
if (hadc->Instance == ADC1)
{
current_adc_buffer = adc_buffer1; // 处理第一个缓冲区
buffer_ready = 1;
}
}
//DMA全中断
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if (hadc->Instance == ADC1)
{
current_adc_buffer = adc_buffer2; // 处理第二个缓冲区
buffer_ready = 1;
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); /* 校准ADC */
/* 启动ADC和DMA */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer1, 3*2); //存储6个数据进入缓冲区,前3个存入Buffer1,后3个存入buffer2
while (1)
{
/* 检查缓冲区是否就绪 */
if (buffer_ready)
{
buffer_ready = 0; // 重置标志
sample_counter++;
/* 每4000次采样输出一次(约1秒,视ADC时钟和采样时间调整) */
if (sample_counter >= 10000)
{
sample_counter = 0;
char adc_str[64];
sprintf(adc_str, "CH1: %u, CH2: %u, Temp: %u\n",
current_adc_buffer[0], // ADC1_IN1
current_adc_buffer[1], // ADC1_IN2
current_adc_buffer[2]); // Temperature Sensor
SEGGER_RTT_printf(0, "%s", adc_str);
}
}
}
}
更多推荐



所有评论(0)