STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及傻瓜式解析)

STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及通俗解析)

​ 利用STM32的片上外设可采集多个模拟量(如传感器数值),并在嵌入式程序中使用。如果只使用了一个通道,用时令ADC转换而后读取DR寄存器即可。多通道时,可利用ADC+DMA可实时,有序的转存多通道数据至程序内存(数组),用时可随时访问并索引到对应通道。

CubeMX配置

  1. 时钟配置如下:

    ​ 原先经常忽视时钟的信息,这里注意一下ADC1,2,3的时钟频率,其于ADC采样时间有关。如果时钟配置的很高,那么选择1.5Cycles可能不满足最小转换时间,产生错误不易debug。

    image-20220118145753920

  2. ADCs配置如下:

    ​ ADC1的独立模式工作逻辑:一个ADC外设(ADC1)对应一个缓存(DR寄存器),同时采集多个通道指按配置的顺序依次将模拟量转换位数字量,然后储存在外设所谓的"共享内存"——DR寄存器中,DR的值被硬件不断的覆盖写入,在恰当时刻读取DR中的值,可得到对应通道的数据。通过一系列硬件中断信号,标志位等,可保证DR中读取的数据与期望的通道相对应。总而言之,DR成为了安全队列。

    ​ 各个选项含义见表格。

    image-20220118145547725

    ADCs_Common_Settings(ADC基础设置)
    Mode(工作模式)Independent mode(独立模式)在同一引脚上仅有一个ADC在采集模拟信号
    ADC_Settings(ADC设置)
    Data Alignment(数据对齐)Right alignment(数据右对齐)/Left alignment(数据左对齐)
    Scan Conversion Mode(扫描模式)ENABLE(使能)/DISABLE(禁止)#当有多个通道需要采集信号时必须开启扫描模式,此时ADC将会按设定的顺序轮流采集各通道信号
    Continuous Comverion Mode(连续转换模式)ENABLE(使能)/DISABLE(禁止)#连续转换模式将会在上一次ADC转换完成后立即开启下一次转换
    Discontinuous Comverion Mode(单次转换模式)ENABLE(使能)/DISABLE(禁止)#单次转换模式ADC只采集一次数据就停止采集,使用单次转换模式需要转换通道数大于1
    Number Of Discontinuous Conversions(单次转换次数)#此项设置为单次转换模式的附属设置,需要使能单次转换模式
    ADC_Regular_ConversionMode(规则通道模式)
    Enable Regular Conversions(规则通道控制)ENABLE(使能)、DISABLE(禁止)#需要使能规则通道控制才可以进一步对规则通道的使用进行配置
    Number Of Conversion(ADC转换通道数)#按照实际使用的通道数进行选择,会影响可供设置的通道数量
    External Trigger Conversion Source(外部触发转换模式)Regular Conversion Launched by software(软件控制触发)#ADC需要在接收到到触发信号后才开始模数转换,可以被定时器触发、外部中断触发、软件触发
    RANK(模拟信号采集及转换的次序)
    Channel(ADC转换通道)
    Sampling Time(采样周期)#ADC采样时间计算公式:TCONV=采样周期+12.5各周期
    ADC_Injected_ConversionMode(注入通道模式)#一般情况下不需要使用注入通道,可以将注入通道认为是ADC中断,即打断规则通道的采样进程执行注入通道的采样
    Enable Regular Conversions(注入通道控制)ENABLE(使能)、DISABLE(禁止)#需要使能注入通道控制才可以进一步对注入通道进行配置
    Number Of Conversion(ADC注入转换通道数)#按照实际使用的通道数进行选择,会影响可供设置的注入通道数量
    External Tigger Source(外部触发模式)
    Injected Conversion Mode(注入转换通道模式)
    Rank(注入转换通道大于0时才可对其配置,后面的数字代表顺序)
    Channel(转换通道)
    Sampling Time(转换时间)
    Injected Offset(注入通道偏移量)
    WatchDog(看门狗)
    Enable Analog WatchDog Mode(使能模拟量看门狗模式)#需要选中本项才可对看门狗进行进一步的设置
    Watchdog Mode(看门狗模式)Single regular channel
     Single injected channel
        Single regular or injected channel
    (监测单一通道的规则通道)
    (监测单一通道的注入通道)
    (监测单一通道的规则及注入通道)
    Analog WatchDog Channel(看门狗通道)
    High Threshold(高阈值)
    Low Threshold(低阈值)
    Interrupt Mode(看门狗中断)
  3. DMA配置如下

    由于开始不太理解DMA几个配置的含义,曾在这里踩了很多坑,对应在程序中说明。

    image-20220118145907694

  4. 因为没有使用中断,NVIC Settings中我把中断关闭了。

  5. 程序使用

    • 自动生成代码有时有坑:main中有系统生成的各外设初始化函数调用

      /* Initialize all configured peripherals */
      MX_GPIO_Init();
      MX_DMA_Init();
      MX_ADC1_Init();
      MX_DAC_Init();
      MX_UART4_Init();
      MX_USART3_UART_Init();
      ......
      

      检查MX_DMA_Init();是否在MX_ADC1_Init();之前调用,默认情况我的在后面,后发现DMA功能异常,手动更改顺序后正常

    • 启用ADC转换,DMA模式
      开一个数组存数,main中while前调用两个库函数开启外设即可。业务中随时访问数组得到ADC转换值。

      uint16_t testbuffer[4]={0};
      while(HAL_ADCEx_Calibration_Start(&hadc1)!=HAL_OK);
      while(HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&testbuffer,4)!=HAL_OK);
      

      调用HAL库函数HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&testbuffer,4)开启了配置好的ADC和DMA,其中:

      hadc1为外设的句柄,很好理解。

      testbuffer是DMA搬运的目的内存。 我希望testbuffer[0]~[3]分别存入四个通道的转换数据,因此创建了size为4的数组,函数第三个参数设置为4,并勾选了Memory下Increment Address选项框。Increment Address使得每搬运一次DR寄存器的数据后,搬运目的地的起始地址向后偏移一个Data With,注意这里是CubeMX配置的Data With而不是函数形参的类型宽度或目的数组的元素宽度。第三个参数为4告诉DMA搬运四次为一个循环,如果没有配置Circle模式,4次后停止。下次调用重新启用,从testbuffer地址重新写入。Circle模式下,四次搬运四次后自动重新开启,即目的地址回到testbuffer

      ​ 函数形参类型是uint32_t*,起初把我迷惑了,创建了uint32_t类型的数组以存放DMA搬运的数据。实际上,貌似函数只使用了传入的首地址。为了便于直接使用,这里的数据类型应与DMA配置的Data Width对应。我使用的MCU其ADC转换精度为12位,因此使用HalfWord(16bit)足以,因此配置时两边都使用了默认的HalfWord,该配置使DMA每次从ADC搬运16bit数据到地址testbuffer,下一波数据搬运到testbuffer+16bit的地址中,再下一次到testbuffer+2*16bit。如果testbufferuint32_t类型的,并不影响数据搬运行为,但访问testbuffer[0]时,得到的uint32_t类型的数值是通道ch1ch2合并而来的,还要取高16位和低16位将两帧分开。对于每一帧,低12位是数据,剩余的4位被0填充。

      testbuffersize不应小于第三个参数,否则数组越界。数组可以很大,但只循环使用前面的几段。有些程序采集四个通道,用size为400的数组,DMA也依次搬运400次,这时数组中同时保存了连续时间内的100组“四个通道的数据”,可对每个通道求取平均值当作检测值。

      ​ 在上述配置下,启动后ADC时刻转换着外界模拟量的值,DMA不停搬运数据,而DMA请求不同于中断请求,高频的DMA转换并不会不占用CPU,testbuffer[]中被这个硬件进程不断刷新着数据。可近似认为访问testbuffer[]时得到的是ADC转换的实时值。

  • 48
    点赞
  • 359
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值