这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取手持数字示波器】CH32X035的定时器以及外部中断体验

共7条 1/1 1 跳转至

【换取手持数字示波器】CH32X035的定时器以及外部中断体验

高工
2024-03-11 11:20:09   被打赏 50 分(兑奖)     打赏

为了得到更好得体验,我们本次主要是对定时器进行多重得体验,通过板载得两个LED灯结合按键进行多种展示功能切换。

首先了解一下CH32X035得定时器,高级定时器模块(ADTM)包含两个功能强大的16位自动重装定时器(TIM1/TIM2),可用于测量脉冲宽度或产生脉冲、PWM波等。用于电机控制、电源等领域;通用定时器模块包含一个16位可自动重装的定时器(TIM3),用于测量脉冲宽度或者产生特定频率的脉冲、PWM波等。可用于自动化控制、电源等领域。差异主要体现在一下方向:计数模式、捕获通道、死区等等。

通用定时器的定时体验,目前使用的LED闪烁是通过在while中延时实现的,这里我们通过定时器实现LED的闪烁功能。

初始化代码:

void port_Time_init(void)

{

   Time3_init(48000, 10);//定时10ms

}

void Time3_init(u16 arr, u16 psc)

{

   TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};

   NVIC_InitTypeDef NVIC_InitStruct={0};

   RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );

   TIM_TimeBaseInitStructure.TIM_Period = arr-1;

   TIM_TimeBaseInitStructure.TIM_Prescaler = psc-1;

   TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

   TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

   TIM_TimeBaseInit( TIM3, &TIM_TimeBaseInitStructure);

   NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;

   NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = NVIC_PriorityGroup_0;

   NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;

   NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStruct);

   TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

   TIM_Cmd(TIM3, ENABLE);

}

中断代码:

void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void TIM3_IRQHandler(void)

{

   if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)

   {

       TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

       LED.Upcnt++;

       if(LED.Upcnt%50 == 0)

       {

           LED.Upcnt = 0;

           LED.UpFlag = 1;

       }

   }

}

定时器中断主要涉及的就是定时器的配置与中断配置,在官方的定时器使用模块中并没有有关定时器中断方面的例程,这方面也确实让我着实费了好长时间,一直无法进入中断,而且切换不同的定时器也无法进入,最后发现是出现在void TIM3_IRQHandler(void) attribute((interrupt("WCH-Interrupt-fast")));也就是除了在中断处理函数写相应代码,最重要的是上边这一句,为什么呢?而且一旦你前面中断开启,这里就必须有对应的开启,差一个程序就乱掉了,没有查到这一句是什么意思。

为了实现状态的切换,我们使用了五向按键的上键实现LED状态的切换:

初始化代码如下:

void port_EXTI_init(void)

{

   GPIO_InitTypeDef GPIO_InitStructure = {0};

   EXTI_InitTypeDef EXTI_InitStructure = {0};

   NVIC_InitTypeDef NVIC_InitStructure = {0};

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;

   GPIO_Init(GPIOC, &GPIO_InitStructure);

   /* GPIOC ----> EXTI_Line17 */

   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

   EXTI_InitStructure.EXTI_Line = EXTI_Line0;

   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

   EXTI_InitStructure.EXTI_LineCmd = ENABLE;

   EXTI_Init(&EXTI_InitStructure);

   NVIC_InitStructure.NVIC_IRQChannel = EXTI7_0_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);

}

中断处理:

void EXTI7_0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

void EXTI7_0_IRQHandler(void)

{

 if(EXTI_GetITStatus(EXTI_Line0)==SET)

 {

   LED.UpFlag = 1;

   EXTI_ClearITPendingBit(EXTI_Line0);     /* Clear Flag */

 }

}

效果如下:

1.gif

接下来就是体验定时器的PWM,这里我们使用的是定时器的互补PWM输出控制LED实现呼吸灯的效果,这也和我们后续对直流风机的控制是类似的,一个吹风一个吸风,正好是一个互补的效果。

初始化代码:

void TIM1_Dead_Time_Init(u16 arr, u16 psc, u16 ccp)

{

   TIM_OCInitTypeDef       TIM_OCInitStructure = {0};

   TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};

   TIM_BDTRInitTypeDef     TIM_BDTRInitStructure = {0};

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_TIM1, ENABLE);

   /* TIM1_CH1- GPIO_Pin_9   TIM1_CH2- GPIO_Pin_10*/

   LED_GPIOPWM_init();

   TIM_TimeBaseInitStructure.TIM_Period = (arr-1);

   TIM_TimeBaseInitStructure.TIM_Prescaler = (psc-1);

   TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

   TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

   TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

   TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

   TIM_OCInitStructure.TIM_Pulse = ccp;

   TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

   TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;

   TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;

   TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

   TIM_OC1Init(TIM1, &TIM_OCInitStructure);

   TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable;

   TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable;

   TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;

   TIM_BDTRInitStructure.TIM_DeadTime = 0xFF;

   TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;

   TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;

   TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;

   TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

   TIM_CtrlPWMOutputs(TIM1, ENABLE);

   TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Disable);

   TIM_ARRPreloadConfig(TIM1, ENABLE);

   TIM_Cmd(TIM1, ENABLE);

}

并修改LED的控制函数:

void App_LED(void)

{

   if(LED.Mode_Dis != LED.Mode_OidDis)

   {

       switch(LED.Mode_Dis)

       {

           case 0:

               LED_GPIO_init();

               TIM_Cmd(TIM1, DISABLE);

               break;

           case 1:

               TIM1_Dead_Time_Init(100, 4800, 0);

               LED.PWMcnt = 0;

               break;

           default:

               break;

       }

       LED.Mode_OidDis = LED.Mode_Dis;

   }

   if(LED.UpFlag == 1)

   {

       if(LED.Mode_Dis == 0)

       {

           GPIO_WriteBit(GPIOB, GPIO_Pin_6, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));

           GPIO_WriteBit(GPIOB, GPIO_Pin_9, (i != 0) ? (i = Bit_SET) : (i = Bit_RESET));

       }

       LED.UpFlag = 0;

   }

}

中断处理函数:

void TIM3_IRQHandler(void)

{

   if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)

   {

       TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

       if(LED.Mode_Dis == 0)

       {

           LED.Upcnt++;

           if(LED.Upcnt%50 == 0)

           {

               LED.Upcnt = 0;

               LED.UpFlag = 1;

           }

       }

       else if(LED.Mode_Dis == 1)

       {

           LED.PWMcnt++;

           if(LED.PWMcnt < 100)

           {

               TIM_SetCompare1(TIM1,100-LED.PWMcnt);

           }

           else if(LED.PWMcnt >= 100 && LED.PWMcnt < 200)

           {

               TIM_SetCompare1(TIM1,LED.PWMcnt-100);

           }

           else if(LED.PWMcnt >= 200)

           {

               LED.PWMcnt = 0;

           }

       }

   }

}

void EXTI7_0_IRQHandler(void)

{

 if(EXTI_GetITStatus(EXTI_Line0)==SET)

 {

     LED.Mode_Dis++;

     LED.Mode_Dis = LED.Mode_Dis%2;

     EXTI_ClearITPendingBit(EXTI_Line0);     /* Clear Flag */

 }

}

效果如下:

2.gif

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





关键词: CH32X035     定时器     外部中断    

专家
2024-03-12 00:14:29     打赏
2楼

谢谢分享


院士
2024-03-12 06:09:52     打赏
3楼

谢谢楼主的分享~!


工程师
2024-03-13 06:26:23     打赏
4楼

谢谢分享


高工
2024-03-14 13:24:43     打赏
5楼

谢谢楼主的


工程师
2024-03-18 09:45:52     打赏
6楼

谢谢分享。


高工
2024-03-18 10:33:13     打赏
7楼

谢谢分享


共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]