[单片机芯片] 【CH32X035评估板测评】第四章 多样得定时器体验与外部中断

[复制链接]
 楼主| qintian0303 发表于 2023-10-6 13:26 | 显示全部楼层 |阅读模式
本帖最后由 qintian0303 于 2023-10-6 13:25 编辑

       为了得到更好得体验,我们本次主要是对定时器进行多重得体验,通过板载得两个LED灯结合按键进行多种展示功能切换。
首先了解一下CH32X035得定时器,高级定时器模块(ADTM)包含两个功能强大的16位自动重装定时器(TIM1/TIM2),可用于测量脉冲宽度或产生脉冲、PWM波等。用于电机控制、电源等领域;通用定时器模块包含一个16位可自动重装的定时器(TIM3),用于测量脉冲宽度或者产生特定频率的脉冲、PWM波等。可用于自动化控制、电源等领域。差异主要体现在一下方向:计数模式、捕获通道、死区等等。
      
       通用定时器的定时体验,目前使用的LED闪烁是通过在while中延时实现的,这里我们通过定时器实现LED的闪烁功能。
       初始化代码:
  1. //******************************************************************************
  2. //* 函数名称  : port_Time_init
  3. //* 函数描述  : 定时器初始化
  4. //* 输入参数  :
  5. //* 参数描述  : 对应    定时器引脚初始化及配置
  6. //* 输出参数  : 无
  7. //* 返回值    : 无
  8. //******************************************************************************
  9. void port_Time_init(void)
  10. {
  11.     Time3_init(48000, 10);//定时10ms

  12. }

  13. //******************************************************************************
  14. //* 函数名称  : Time3_init
  15. //* 函数描述  : 定时器3初始化
  16. //* 输入参数  :
  17. //* 参数描述  : 对应    定时器引脚初始化及配置
  18. //* 输出参数  : 无
  19. //* 返回值    : 无
  20. //******************************************************************************
  21. void Time3_init(u16 arr, u16 psc)
  22. {
  23.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};
  24.     NVIC_InitTypeDef NVIC_InitStruct={0};

  25.     RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );
  26.    

  27.     TIM_TimeBaseInitStructure.TIM_Period = arr-1;
  28.     TIM_TimeBaseInitStructure.TIM_Prescaler = psc-1;
  29.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  30.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  31.     TIM_TimeBaseInit( TIM3, &TIM_TimeBaseInitStructure);

  32.     NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
  33.     NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = NVIC_PriorityGroup_0;
  34.     NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
  35.     NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  36.     NVIC_Init(&NVIC_InitStruct);

  37.     TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

  38.     TIM_Cmd(TIM3, ENABLE);

  39. }
  40. 中断代码:
  41. void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
  42. void TIM3_IRQHandler(void)
  43. {
  44.     if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
  45.     {
  46.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

  47.         LED.Upcnt++;
  48.         if(LED.Upcnt%50 == 0)
  49.         {
  50.             LED.Upcnt = 0;
  51.             LED.UpFlag = 1;

  52.         }
  53.     }
  54. }
       定时器中断主要涉及的就是定时器的配置与中断配置,在官方的定时器使用模块中并没有有关定时器中断方面的例程,这方面也确实让我着实费了好长时间,一直无法进入中断,而且切换不同的定时器也无法进入,最后发现是出现在void TIM3_IRQHandler(void) attribute((interrupt("WCH-Interrupt-fast")));也就是除了在中断处理函数写相应代码,最重要的是上边这一句,为什么呢?而且一旦你前面中断开启,这里就必须有对应的开启,差一个程序就乱掉了,没有查到这一句是什么意思。
      
       为了实现状态的切换,我们使用了五向按键的上键实现LED状态的切换:
       初始化代码如下:
  1. //******************************************************************************
  2. //* 函数名称  : port_EXTI_init
  3. //* 函数描述  : 外部中断初始化
  4. //* 输入参数  :
  5. //* 参数描述  : 对应   
  6. //* 输出参数  : 无
  7. //* 返回值    : 无
  8. //******************************************************************************
  9. void port_EXTI_init(void)
  10. {
  11.     GPIO_InitTypeDef GPIO_InitStructure = {0};
  12.     EXTI_InitTypeDef EXTI_InitStructure = {0};
  13.     NVIC_InitTypeDef NVIC_InitStructure = {0};

  14.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);

  15.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  17.     GPIO_Init(GPIOC, &GPIO_InitStructure);

  18.     /* GPIOC ----> EXTI_Line17 */
  19.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
  20.     EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  21.     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  22.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  23.     EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  24.     EXTI_Init(&EXTI_InitStructure);

  25.     NVIC_InitStructure.NVIC_IRQChannel = EXTI7_0_IRQn;
  26.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  27.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  28.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  29.     NVIC_Init(&NVIC_InitStructure);
  30. }
      中断处理:
  1. void EXTI7_0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

  2. void EXTI7_0_IRQHandler(void)
  3. {
  4.   if(EXTI_GetITStatus(EXTI_Line0)==SET)
  5.   {
  6.     LED.UpFlag = 1;
  7.     EXTI_ClearITPendingBit(EXTI_Line0);     /* Clear Flag */
  8.   }
  9. }
      效果如下:
1.gif
      
       接下来就是体验定时器的PWM,这里我们使用的是定时器的互补PWM输出控制LED实现呼吸灯的效果,这也和我们后续对直流风机的控制是类似的,一个吹风一个吸风,正好是一个互补的效果。
       初始化代码:
  1. void TIM1_Dead_Time_Init(u16 arr, u16 psc, u16 ccp)
  2. {
  3.     TIM_OCInitTypeDef       TIM_OCInitStructure = {0};
  4.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
  5.     TIM_BDTRInitTypeDef     TIM_BDTRInitStructure = {0};

  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_TIM1, ENABLE);

  7.     /* TIM1_CH1- GPIO_Pin_9   TIM1_CH2- GPIO_Pin_10*/
  8.     LED_GPIOPWM_init();

  9.     TIM_TimeBaseInitStructure.TIM_Period = (arr-1);
  10.     TIM_TimeBaseInitStructure.TIM_Prescaler = (psc-1);
  11.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  12.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  13.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

  14.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  15.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  16.     TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  17.     TIM_OCInitStructure.TIM_Pulse = ccp;
  18.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  19.     TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
  20.     TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  21.     TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
  22.     TIM_OC1Init(TIM1, &TIM_OCInitStructure);

  23.     TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable;
  24.     TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable;
  25.     TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
  26.     TIM_BDTRInitStructure.TIM_DeadTime = 0xFF;
  27.     TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
  28.     TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
  29.     TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  30.     TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

  31.     TIM_CtrlPWMOutputs(TIM1, ENABLE);
  32.     TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Disable);
  33.     TIM_ARRPreloadConfig(TIM1, ENABLE);
  34.     TIM_Cmd(TIM1, ENABLE);
  35. }
      并修改LED的控制函数:
  1. void App_LED(void)
  2. {
  3.     if(LED.Mode_Dis != LED.Mode_OidDis)
  4.     {
  5.         switch(LED.Mode_Dis)
  6.         {
  7.             case 0:
  8.                 LED_GPIO_init();
  9.                 TIM_Cmd(TIM1, DISABLE);
  10.                 break;
  11.             case 1:
  12.                 TIM1_Dead_Time_Init(100, 4800, 0);
  13.                 LED.PWMcnt = 0;
  14.                 break;
  15.             default:
  16.                 break;
  17.         }

  18.         LED.Mode_OidDis = LED.Mode_Dis;

  19.     }

  20.     if(LED.UpFlag == 1)
  21.     {
  22.         if(LED.Mode_Dis == 0)
  23.         {
  24.             GPIO_WriteBit(GPIOB, GPIO_Pin_6, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));
  25.             GPIO_WriteBit(GPIOB, GPIO_Pin_9, (i != 0) ? (i = Bit_SET) : (i = Bit_RESET));
  26.         }
  27.         LED.UpFlag = 0;
  28.     }

  29. }
      中断处理函数:
  1. void TIM3_IRQHandler(void)
  2. {
  3.     if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
  4.     {
  5.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

  6.         if(LED.Mode_Dis == 0)
  7.         {
  8.             LED.Upcnt++;
  9.             if(LED.Upcnt%50 == 0)
  10.             {
  11.                 LED.Upcnt = 0;
  12.                 LED.UpFlag = 1;

  13.             }

  14.         }
  15.         else if(LED.Mode_Dis == 1)
  16.         {
  17.             LED.PWMcnt++;
  18.             if(LED.PWMcnt < 100)
  19.             {
  20.                 TIM_SetCompare1(TIM1,100-LED.PWMcnt);
  21.             }
  22.             else if(LED.PWMcnt >= 100 && LED.PWMcnt < 200)
  23.             {
  24.                 TIM_SetCompare1(TIM1,LED.PWMcnt-100);
  25.             }
  26.             else if(LED.PWMcnt >= 200)
  27.             {
  28.                 LED.PWMcnt = 0;
  29.             }
  30.         }
  31.     }
  32. }

  33. void EXTI7_0_IRQHandler(void)
  34. {
  35.   if(EXTI_GetITStatus(EXTI_Line0)==SET)
  36.   {
  37.       LED.Mode_Dis++;
  38.       LED.Mode_Dis = LED.Mode_Dis%2;
  39.       EXTI_ClearITPendingBit(EXTI_Line0);     /* Clear Flag */
  40.   }
  41. }
      效果如下:
2.gif

       通过本次章节的使用,我们对外部中断、定时器中断、定时器PWM输出有了基本的了解,里边有一些坑也采到了,通过这些功能的组合展现了一个LED的多样控制。





取名困难户9527 发表于 2023-12-11 17:51 | 显示全部楼层
有用,刚好遇到定时器中断问题。感谢楼主
weifeng90 发表于 2023-12-12 07:43 来自手机 | 显示全部楼层
这个亚克力板不错啊
 楼主| qintian0303 发表于 2023-12-12 13:21 | 显示全部楼层
weifeng90 发表于 2023-12-12 07:43
这个亚克力板不错啊

弄个小架子,要不连线总是烂七八糟的
电子乐园游园ing 发表于 2023-12-13 15:17 | 显示全部楼层
这个亚克力支架在哪里搞的?多少钱?

评论

这个是自己切得,没得花钱,就是根据扩展板尺寸自己画的  发表于 2023-12-14 09:54
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:硬件工程师
简介:有着多年硬件开发经验的专业人员,专注于医疗电子领域,热衷于对新鲜事物的探索,喜欢DIY!

556

主题

2718

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部
认证:硬件工程师
简介:有着多年硬件开发经验的专业人员,专注于医疗电子领域,热衷于对新鲜事物的探索,喜欢DIY!

556

主题

2718

帖子

12

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