一、为什么需要HT与TC中断配合?

在STM32中使用ADC+DMA进行连续转换时,DMA通常配置为循环模式,自动将ADC数据搬运到指定内存数组。若只使用传输完成中断(TC),则必须等待整个缓冲区填满才能处理数据,导致:

  • 数据处理延迟大,实时性差;
  • 若处理速度跟不上采集速度,新数据会覆盖未处理数据;
  • 无法实现“乒乓”式分块处理。

半传输中断(HT) 在DMA传输完成一半时触发,与TC中断配合,可将缓冲区分为前后两块,实现“采集一块、处理另一块”的流水线操作,显著提高系统响应速度与数据安全性。

二、DMA双缓冲与分块原理

假设ADC采集缓冲区大小为 BUFFER_SIZE(偶数),DMA循环模式下的传输过程:

  1. DMA从外设(ADC)搬运数据到内存,计数器递减;
  2. 当传输过半(即搬运了 BUFFER_SIZE/2 个数据)时,触发HT中断;
  3. 当传输全部完成(BUFFER_SIZE 个数据)时,触发TC中断,同时DMA自动重装载计数器,开始下一轮循环。

因此,HT中断时前半缓冲区 [0, BUFFER_SIZE/2-1] 已满,可安全处理;TC中断时后半缓冲区 [BUFFER_SIZE/2, BUFFER_SIZE-1] 已满。两者交替,实现连续无缝处理。

注意:HAL库中DMA中断回调为 HAL_ADC_ConvHalfCpltCallback() 和 HAL_ADC_ConvCpltCallback(),分别对应HT和TC。

三、CubeMX配置步骤

  1. ADC配置:选择连续转换模式(Continuous Conversion Mode = Enabled),DMA连续请求(DMA Continuous Requests = Enabled);
  2. DMA配置:添加ADC对应的DMA通道,模式设为Circular,数据宽度根据ADC分辨率选择(通常Half Word),内存地址自增;
  3. NVIC配置:使能DMA通道的HT和TC中断;
  4. 生成代码:HAL库会自动初始化并启动ADC+DMA。

四、完整代码示例

#include "main.h"

#define BUFFER_SIZE  256
#define HALF_SIZE    (BUFFER_SIZE / 2)

uint16_t adc_buffer[BUFFER_SIZE];
volatile uint8_t half_ready = 0;
volatile uint8_t full_ready = 0;

/* HT中断回调:前半缓冲区就绪 */
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC1) {
        half_ready = 1;
        // 可在此处快速处理前半数据,或置标志由主循环处理
        // process_data(&adc_buffer[0], HALF_SIZE);
    }
}

/* TC中断回调:后半缓冲区就绪 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC1) {
        full_ready = 1;
        // 可在此处快速处理后半月数据
        // process_data(&adc_buffer[HALF_SIZE], HALF_SIZE);
    }
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();

    // 启动ADC+DMA连续转换
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, BUFFER_SIZE);

    while (1) {
        if (half_ready) {
            half_ready = 0;
            // 处理前半缓冲区数据(此时DMA正在填充后半部分)
            process_data(&adc_buffer[0], HALF_SIZE);
        }
        if (full_ready) {
            full_ready = 0;
            // 处理后半缓冲区数据(此时DMA已重新开始填充前半部分)
            process_data(&adc_buffer[HALF_SIZE], HALF_SIZE);
        }
    }
}

五、注意事项

  • 缓冲区大小必须为偶数,否则HT中断位置不准确;
  • 中断回调中避免耗时操作,建议只置标志位,由主循环或RTOS任务处理数据;
  • 数据一致性:处理某半区时,DMA不会写入该半区(循环模式下HT/TC交替),但若处理时间超过半缓冲区采集时间,仍可能被覆盖,需评估采样率与处理速度;
  • HAL库版本差异:部分系列(如G0/G4)DMA中断回调可能需通过 HAL_DMA_IRQHandler 间接调用,确保在 stm32fxx_hal_msp.c 中正确使能中断;
  • 调试时:可在HT/TC回调中翻转GPIO,用示波器观察中断频率,验证分块时序;
  • 若使用RTOS:可在回调中释放信号量,由任务处理数据,避免在中断上下文中进行复杂运算。

六、总结

通过HT与TC中断的配合,ADC+DMA连续转换可实现高效的双缓冲分块处理,既保证了数据采集的连续性,又为数据处理留出了充足时间。掌握这一模式,是开发高性能数据采集系统的关键技能。