[活动] 【APM32F411V Tiny Board测评】5 定时器的使用(基础定时+PWM)

[复制链接]
 楼主| 孤独的单行者 发表于 2024-5-28 10:29 | 显示全部楼层 |阅读模式
本帖最后由 孤独的单行者 于 2024-5-28 10:30 编辑

       本章节主要是进行定时器的基本使用以及PWM的产生与控制,结合前面的按键以及LED的控制,再加上串口的打印功能,就可以实现,不连接其他外部器件进行定时器的使用和测试。
我们首先看一下定时器的基本使用,在使用基本定时功能时,我们通常需要进行定时器的初始化后,在定时器的中断中进行处理,我们现在通过现有的资源实现LED的非阻塞闪烁,一个按键对应一个LED,并通过串口打印状态。
       这里我们还要了解一个点,也就是系统的时钟频率是多少,注意之前的测试可以不考虑,这里要计算定时器的时间则必须要考虑了,下面是本芯片的时钟树,板载的外部高速时钟是8Mhz:
1.png

       我们找到system_apm32f4xx.C中有关时钟的配置,注意一点,才发现这里的配置真的很乱,我不知道对于官方的SDK为什么会这样配置,可能只是为了能达到最大时钟吧,原始配置如下:
  1. /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_B) * PLL_A */
      咱们简单计算一下,外部时钟8Mhz,按照如上的计算,PLL_VCO=200M,USB OTG FS = 28.57 M,SYSCLK= 100M,为了后续的USB功能的测试(一般USB的时钟要求为48M),我们重新梳理一下时钟配置,最大时钟不得超过120Mhz,为了比较好计算,SYSCLK取96中,一种参数计算配置如下:
  1. /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_B) * PLL_A */
  2. #define PLL_B      8
  3. /* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLL_D */
  4. #define PLL_D      4
  5. #define PLL_A      192
  6. /* SYSCLK = PLL_VCO / PLL_C */
  7. #define PLL_C      2
      接下来继续进行定时器的初始化配置:
  1. void APM_TMR1_Init(void)
  2. {
  3.     TMR_BaseConfig_T TMR_BaseConfigStruct;

  4.     /* Enable TMR1 Periph Clock */
  5.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1);
  6.    
  7.     APM_HCLKFreq = RCM_ReadHCLKFreq();
  8.     /* 定时10ms */
  9.     APM_TMR1_DIV = APM_HCLKFreq/1000*10/1000-1;

  10.     /* Config TMR1 */
  11.     TMR_BaseConfigStruct.clockDivision = TMR_CLOCK_DIV_1;
  12.     TMR_BaseConfigStruct.countMode = TMR_COUNTER_MODE_UP;
  13.     TMR_BaseConfigStruct.division = APM_TMR1_DIV;
  14.     TMR_BaseConfigStruct.period = 999;
  15.     TMR_BaseConfigStruct.repetitionCounter = 0;
  16.     TMR_ConfigTimeBase(TMR1, &TMR_BaseConfigStruct);

  17.     /* Enable TMR1 Interrupt */
  18.     TMR_EnableInterrupt(TMR1, TMR_INT_UPDATE);
  19.     NVIC_EnableIRQRequest(TMR1_UP_TMR10_IRQn, 0, 0);

  20.     TMR_Enable(TMR1);
  21. }
      在中断处理中加入按键判断,KEY2控制灯的闪烁:
  1. void TMR1_UP_TMR10_IRQHandler(void)
  2. {
  3.     if(TMR_ReadIntFlag(TMR1, TMR_INT_UPDATE) == SET)
  4.     {
  5.         TMR_ClearIntFlag(TMR1, TMR_INT_UPDATE);
  6.             
  7.         if(APM_EINT0_flag == 1)
  8.         {
  9.         TMR1_cnt++;
  10.         if(TMR1_cnt%50 == 0)
  11.         {
  12.         APM_LED3_Toggle;  
  13.         APM_LED2_Toggle;
  14.         }
  15.         }
  16.                
  17.     }
  18. }
      接下来是通过定时器的PWM功能实现呼吸灯的效果,LED对应的PE5和PE6的引脚功能如下:
2.png

       可以看到对应的是定时器9的CH1和CH2,我们用的产生PWM的定时器为定时器9,使用的时钟依然是APB2.
       初始化如下:
  1. void APM_TMR9_Init(void)
  2. {
  3.     TMR_BaseConfig_T TMR_BaseConfigStruct;
  4.     TMR_OCConfig_T OCcongigStruct;
  5.     GPIO_Config_T GPIO_ConfigStruct;
  6.         
  7.    
  8.     /* Enable TMR1 Periph Clock */
  9.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR9);
  10.     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOE);
  11.    
  12.    
  13.     /* TMR9_CH1 */
  14.     GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_5, GPIO_AF_TMR9);
  15.     /* TMR9_CH2 */
  16.     GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_6, GPIO_AF_TMR9);
  17.    
  18. //        /* Config TMR2 GPIO for output PWM */
  19. //        GPIO_ConfigStruct.pin = GPIO_PIN_5|GPIO_PIN_6;
  20. //        GPIO_ConfigStruct.mode = GPIO_MODE_AF;
  21. //        GPIO_ConfigStruct.otype = GPIO_OTYPE_PP;
  22. //        GPIO_ConfigStruct.speed = GPIO_SPEED_100MHz;
  23. //        GPIO_Config(GPIOE, &GPIO_ConfigStruct);
  24.    
  25.    
  26.     APM_HCLKFreq = RCM_ReadHCLKFreq();
  27.     /* 频率200Hz */
  28.     APM_TMR1_DIV = APM_HCLKFreq/200/1000-1;

  29.     /* Config TMR1 */
  30.     TMR_BaseConfigStruct.clockDivision = TMR_CLOCK_DIV_1;
  31.     TMR_BaseConfigStruct.countMode = TMR_COUNTER_MODE_UP;
  32.     TMR_BaseConfigStruct.division = 999;
  33.     TMR_BaseConfigStruct.period = APM_TMR1_DIV;
  34.     TMR_ConfigTimeBase(TMR9, &TMR_BaseConfigStruct);
  35.    
  36.     /* Configure channel1 */
  37.     TMR_ConfigOCStructInit(&OCcongigStruct);

  38.     OCcongigStruct.mode = TMR_OC_MODE_PWM1;
  39.     OCcongigStruct.outputState = TMR_OC_STATE_ENABLE;
  40.     OCcongigStruct.polarity = TMR_OC_POLARITY_HIGH;
  41.    

  42.     OCcongigStruct.pulse = 500;
  43.     TMR_ConfigOC1(TMR9, &OCcongigStruct);
  44.     TMR_ConfigOC1Preload(TMR9, TMR_OC_PRELOAD_ENABLE);

  45.     /* Configure channel2 */
  46.     OCcongigStruct.pulse = 200;
  47.     TMR_ConfigOC2(TMR9, &OCcongigStruct);
  48.     TMR_ConfigOC2Preload(TMR9, TMR_OC_PRELOAD_ENABLE);

  49.     TMR_EnableAutoReload(TMR9);
  50. //    TMR_Enable(TMR9);

  51. }
      注意,我们在初始化里面没有开启定时器和引脚的初始化,这里主要因为LED的引脚的功能是复用的,在正常状态默认是输出控制,只有开启后才是PWM控制,这里面的切换在按键中断中进行:
  1. void EINT1_IRQHandler(void)
  2. {
  3.     if(EINT_ReadIntFlag(EINT_LINE_1))
  4.     {
  5.             
  6.             /*Clear EINT_LINE0 interrupt flag*/
  7.        EINT_ClearIntFlag(EINT_LINE_1);
  8.             
  9.             if(APM_EINT1_flag == 0)
  10.             {
  11.                 if(APM_EINT0_flag == 0)
  12.                 {
  13.                     GPIO_Config_T GPIO_ConfigStruct;
  14.                     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOE);
  15.                     /* Config TMR2 GPIO for output PWM */
  16.                     GPIO_ConfigStruct.pin = GPIO_PIN_5|GPIO_PIN_6;
  17.                     GPIO_ConfigStruct.mode = GPIO_MODE_AF;
  18.                     GPIO_ConfigStruct.otype = GPIO_OTYPE_PP;
  19.                     GPIO_ConfigStruct.speed = GPIO_SPEED_100MHz;
  20.                     GPIO_Config(GPIOE, &GPIO_ConfigStruct);
  21.                     
  22.                     TMR_EnableAutoReload(TMR9);
  23.                     TMR_Enable(TMR9);
  24.                     
  25.                     APM_EINT1_flag = 1;
  26.                     
  27.                     
  28.                     printf("APM_LED breathing start \r\n");
  29.                 }
  30.                 else
  31.                 {
  32.                     printf("Plase stop APM_LED bilinking \r\n");
  33.                 }
  34.             }
  35.             else
  36.             {
  37.                 APM_EINT1_flag = 0;
  38.                 TMR_Disable(TMR9);
  39.                
  40.                 GPIO_Config_T GPIO_ConfigStruct;
  41.                 RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOE);
  42.             
  43.                 GPIO_ConfigStruct.pin = GPIO_PIN_5|GPIO_PIN_6;
  44.                 GPIO_ConfigStruct.mode = GPIO_MODE_OUT;
  45.                 GPIO_ConfigStruct.otype = GPIO_OTYPE_PP;
  46.                 GPIO_ConfigStruct.speed = GPIO_SPEED_100MHz;
  47.                 GPIO_Config(GPIOE, &GPIO_ConfigStruct);
  48.                
  49.                 APM_LED2_Off;
  50.                 APM_LED3_Off;
  51.                
  52.                
  53.                 printf("APM_LED breathing stop \r\n");
  54.             }  
  55.     }
  56. }
      定时器中断中加入呼吸灯程序:
  1. if(APM_EINT1_flag == 1)
  2. {
  3.         TMR_OCConfig_T OCcongigStruct;
  4.         TMR1_breaking_cnt++;
  5.         
  6.         TMR_ConfigOCStructInit(&OCcongigStruct);
  7.         OCcongigStruct.mode = TMR_OC_MODE_PWM1;
  8.         OCcongigStruct.outputState = TMR_OC_STATE_ENABLE;
  9.         OCcongigStruct.polarity = TMR_OC_POLARITY_HIGH;
  10.    
  11.         if(TMR1_breaking_cnt >= 200)
  12.         {
  13.             TMR1_breaking_cnt = 0;
  14.         }
  15.    
  16.         if(TMR1_breaking_cnt<=100)
  17.         {
  18.             OCcongigStruct.pulse = TMR1_breaking_cnt*10;
  19.         }
  20.         else if(TMR1_breaking_cnt>100)
  21.         {
  22.             OCcongigStruct.pulse = (200 - TMR1_breaking_cnt)*10;
  23.         }
  24.    
  25.         TMR_ConfigOC1(TMR9, &OCcongigStruct);
  26.         TMR_ConfigOC2(TMR9, &OCcongigStruct);
  27.         TMR_ConfigOC1Preload(TMR9, TMR_OC_PRELOAD_ENABLE);
  28.         TMR_ConfigOC2Preload(TMR9, TMR_OC_PRELOAD_ENABLE);
  29.    
  30. }
      可以看到串口打印基本操作:
3.png

       实际上咱们得按键采集没有加入防抖,所以会有出现连键的情况,不过和现象还是一致的,效果如下:
20240528.gif

星辰大海不退缩 发表于 2024-6-22 20:52 | 显示全部楼层
PWM的产生与控制进行呼吸灯的测试非常简单
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

152

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部