使用STM32CubeMX实现定时器PWM输出触发ADC采样(DMA)

一、(单通道)使用定时器触发的ADC单通道转换

我用的单片机是STM32F103CBTX

  • 定时器:使用PWM输出的模式
  • ADC:使用DMA的模式(在不使用DMA的情况下,定时器控制ADC进行数据采集只能是单通道!如果开启了多通道,读取到的ADC采集值只会是最后一个通道的值!所以,要想使用定时器控制ADC采集多通道必须使用DMA!)
  • 定时器中cubemx配置:

     看STM32F103数据手册可以知道定时器TIM1是挂在APB1总线上

    c52adb17eb414ceb98da4346055d37a2.png

    我使用的是TIM1的通道2的上升沿(即PWM输出)触发ADC采样 

    4eaa649c71984633b73200b4164d7c5c.png

    PWM模式1和模式2区别:

    以下是使用逻辑分析仪观察到的PWM输出情况

    c665e23e417947b4a7376cd3a067a2f8.png

    137b6339728a4e51b11a9c8b6a2d94fe.png

    ADC中cubemx配置: 

    注意:此时不再需要ADC进行转换,把连续转换模式设为关闭!!!

    (我自己踩的坑,我试过开启的时候程序死掉了)

    a2554d931b4f447e994f58c0fad6cd46.png

    DMA模式选择: 

    Circular模式:

    就是ADC连续采样的意思,也就是HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_Value, 4)这句代码在程序中开启一次即可,不需要每次都重新打开。

    Normal模式:

    HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_Value, 4)执行完一次之后,如果想进行下一轮ADC采样,必须要重新开启,所以每一轮采样都要用一次这句代码,采样一次开启一次采样一次开启一次。

    参考别人的试了用了Circular模式,完全没问题,可以成功测出电压值。

    我自己也试了Normal模式,不行,只能测一次,后面没反应了。

    a8d2ba26f6304b67b830a6bc98196a48.png

     代码:

    uint8_t AdcConvEnd=0;
    
    int main()
    {
      uint16_t ADC_Value[4]= 0;
    
      HAL_TIM_Base_Start(&htim1);
      HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
    
      HAL_ADCEx_Calibration_Start(&hadc1);//自动校准
      HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_Value, 4);
    
    
      while(1)
      {
          if(AdcConvEnd)
          {
              uint16_t averageValue = 0;
              for(int i = 0; i < 4; i++)
              {
                  averageValue += ADC_Value[i];
                  printf("ADC_Value[%d]:%.3f\r\n",i,(float)ADC_Value[i]*3.3f/4096);
              }
              AdcConvEnd=0;
    
              averageValue/=4;
              printf("averageValue:%d\r\n",averageValue);
          }
    }
    
    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
    {
        if(hadc==&hadc1)
        {
            AdcConvEnd=1;
        }
    }

    结果:

    b14f3b94fe984e4cb342b1e8ca014931.png

    二、(双通道)使用定时器触发的ADC通道转换 

    注意:因为我们设置的是 2 个通道的采集,所以应该使能 ADC 的扫描模式,另一方面,我们采用的是 TIM 产生 pwm 触发 adc 进行采集,所以要禁止 ADC 的连续转换模式,这就是两个需要注意的地方。

    ADC中cubemx配置: 

    2bbbb2326c00463286845cbe99cb6a6c.png

    三、关于PWM的频率或周期的计算

    ef4c8d32cb554af9918b6697581516ac.png

    *注 :* ARR和PSC都是16位的寄存器, 数值一定要在0~65535这个范围。

    当我们设置了当前机器设置的是 72MHZ和 72分频,定时器输入时钟频率是72MHz / 72 = 1MHz:

  • 1MHZ ,即1秒计数 1M 次=1000000 次(1s产生1000000个脉冲方波)。
  • 1MHZ ,也就是1us产生1个脉冲方波。
  • 若重装载值 (Period 或 ARR)设置为 500。也就是0.1us*500=500us,对于当前 PWM 周期为 500us,也就是500us发生一次中断。

    当重装载值(Period 或 ARR)设置为 500 时,意味着定时器需要计数 500 个时钟周期才会触发中断。因此,中断发生的周期是 500us(即500 * 1us

    若Pulse设为250,即占空比=Pulse/ARR=250/500=50%

    四、寄存器TIMx_ARR、TIMx_CCRx 、TIMx_CNT

    向上计数为例,重载值为ARR,比较值为CRRx

    8e27aba90c9a4ff18d20c25dda041fb2.png

    上图可以看出:

  • 0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平
  • t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平
  • TIMx_CNT值达到ARR时,定时器溢出,重新向上计数…循环此过程至此一个PWM周期完成

    上图更加形象的说明了

    信号频率由 TIMx_ARR 寄存器值决定。

    占空比则由 TIMx_CCRx 寄存器值决定。

    参考:

    STM32 HAL库:ADC+DMA应用(连续采样、触发采样)_hal adc dma-CSDN博客

    【STM32】定时器TIM触发ADC采样,DMA搬运到内存(超详细讲解)-CSDN博客

    作者:LiMinyu_IoT

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用STM32CubeMX实现定时器PWM输出触发ADC采样(DMA)

    发表评论