zoukankan      html  css  js  c++  java
  • STM32中断调试中遇到的问题

    STM32应用过程中遇到的问题

    实现功能:

    1、自动流水灯:在LED1~LED4上实现自动流水灯,流水间隔时间为200ms/bit,然后通过按键KEY1改变流水灯的速度,每次按键间隔时间增加200ms:当间隔时间增加到1s后(蜂鸣器报警),再次按键间隔时间恢复为初始值200ms。//注:按键同通过中断实现

    2、手动流水灯功能:通过按键KEY1控制流水灯一位,每次按键流水灯移动一位,可循环实现。//(1)、在新的程序中实现,不涵盖上题功能。(2)按键通过中断实现

    3、综合流水灯:1)通过按键KEY2实现自动流水灯和手动流水灯两种模式的切换。初始模式为自动流水灯模式。当处于自动流水灯模式时,KEY1用于改变流水灯速度,如1题所述。当处于手动流水灯模式时,KEY1用于控制流水灯移位,如2提所述。//注:所有按键用中断实现,延时采用定时器中断实现,操作稳定,可循环实现,对按键抖动和按键时间具有鲁棒性。

    对于功能1的实现,我书写的中断内容为:

    /*	@函数名称 :中断服务子程序0
    	@函数功能 :响应中断0的子程序
    	@输入参数 :无
    	@返回值   :无
    	@注意     :中断中不要放延时过长的程序,也不要写死循环
    */
    void EXTI0_IRQHandler(void)
    {
    	delay_ms(20);		//消抖		——请不要在中断消抖,删掉这句
    	if(EXTI_GetFlagStatus(EXTI_Line0)==SET)		//标志位是否使能
    	{
    		if(time_flag==5)		//200*5=1s
    		{
    			time_flag=0;
    		}
    		else if(time_flag<5)
    			time_flag=time_flag+1;
    	}
    	EXTI_ClearITPendingBit(EXTI_Line0);
    }
    

    然后功能实现程序如下图所示:

    /*	@函数名称:void LED_Base_200ms(u16 t)
    	@函数功能:以200ms为基准时间进行延时
    	@输入参数:t延时基准
    	@返回值	 :无
    */
    void LED_Base_200ms(void)
    {
    //	u16 temp;		//延时基准时间
    //	temp=200*(time_flag+1);
    //	u8 i=1;
    //	for(;i<=4;i++)
    //	{
    //		LED_ON(i);
    //		delay_ms(temp);
    //		LED_OFF(i);
    //		delay_ms(temp);
    //	}
    	u8 i;
    	switch(time_flag+1)
    	{
    		case 1 : {
    			for(i=1;i<=4;i++)
    			{
    				LED_ON(i);
    				delay_ms(200);
    				LED_OFF(i);
    				delay_ms(200);
    			}
    			
    		};
    		break;
    		
    		case 2 : {
    			for(i=1;i<=4;i++)
    			{
    				LED_ON(i);
    				delay_ms(400);
    				LED_OFF(i);
    				delay_ms(400);
    			}
    			
    		};
    		break;
    		case 3 : {
    			for(i=1;i<=4;i++)
    			{
    				LED_ON(i);
    				delay_ms(600);
    				LED_OFF(i);
    				delay_ms(600);
    			}
    			
    		};
    		break;
    		case 4 : {
    			for(i=1;i<=4;i++)
    			{
    				LED_ON(i);
    				delay_ms(800);
    				LED_OFF(i);
    				delay_ms(800);
    			}
    			
    		};
    		break;
    		default:{
    			for(i=1;i<=4;i++)
    			{
    				LED_ON(i);
    				delay_ms(1000);
    				LED_OFF(i);
    				delay_ms(1000);
    				Beep_Two_DiDi();
    			}
    			
    		}
    		
    	}
    }
    
    

    解决问题来了,问题出在延时函数中,其实在中断中最好不要用延时函数,用延时函数容易导致程序跑飞。在本次历程中,进入中断的delay_ms(20);延时还是滴答时钟的延时,虽然精确,但是精确的实验现象无法出来也不行啊,所以解决方案是去掉延时程序,或者换成普通的的循环,最好不用循环。通过本例也说明了在中断可不能乱用延时啊,能不用延时就不用延时。一个小小的破程序,调了我一天,可真是太难受。
    对于题目一的实现代码如下所示,每按一次,时间标志位加一,当大于等于5时候清零,主要最好不要包含任何延时,简单的修改标志位就行:

    /*	@函数名称 :中断服务子程序0
    	@函数功能 :响应中断0的子程序
    	@输入参数 :无
        @返回值   :无
    	@注意     :中断中不要放延时过长的程序,也不要写死循环
    */
    void EXTI0_IRQHandler(void)
    {
    	if(EXTI_GetFlagStatus(EXTI_Line0)==SET)		//标志位是否使能
    	{
    		if(time_flag==5)		//200*5=1s
    		{
    			time_flag=0;
    		}
    		else 
    			time_flag++;
    		
    	}
    	EXTI_ClearITPendingBit(EXTI_Line0);
    }
    

    注意:time_flag是全局变量,并且在h文件中用“extern”修饰,便可在外部调用了

    然后实现函数如下:

    /*	@函数名称:void LED_Base_200ms(u16 t)
    	@函数功能:以200ms为基准时间进行延时
    	@输入参数:time延时基准
    	@返回值	 :无
    */
    void LED_Base_200ms(u16 time)
    {
    	u16 temp_time=(time+1)*200;
    	u8 i=1;
    	for(;i<=4;i++)
    	{
    		LED_ON(i);
    		delay_ms(temp_time);
    		LED_OFF(i);
    		delay_ms(temp_time);
    	}
    }
    

    然后在主函数中调用LED_Base_200ms即可

    	LED_Base_200ms(time_flag);
    

    对于功能二实现,还是上面的那个中断程序,但是考虑到,由于用按键触发中断,因此还是会存在一定的抖动,我们就使用非滴答时钟写的延时程序消抖,就普通用循环来消抖,注意最好不用滴答时钟写的延时程序,具体原因由于学的不精,不能解释,如果有大佬可以解释一下,感激不尽。

    /*	@函数名称 :中断服务子程序0
    		@函数功能 :响应中断0的子程序
    		@输入参数 :无
    		@返回值   :无
    		@注意     :中断中不要放延时过长的程序,也不要写死循环
    */
    void EXTI0_IRQHandler(void)
    {
    	delay_non_ms(10);
    	if(EXTI_GetFlagStatus(EXTI_Line0)==SET)		//标志位是否使能
    	{	
    		if(time_flag==5)		//200*5=1s
    		{
    			time_flag=0;
    		}
    		else 
    			time_flag++;
    		
    	}
    	EXTI_ClearITPendingBit(EXTI_Line0);
    

    然后还是通过标志位来调用灯的亮灭,具体函数如下所示

    /*	@函数名称:中断标志控制函数
    		@函数功能:根据中断的标志来执行响应的功能
    		@输入参数:无
    		@返回值	 :无
    */
    void flag_Control(void)
    {
    	switch(time_flag)
    	{
    		case 1 : {LED_Close_All(); LED_ON(1);}break;
    		case 2 : {LED_Close_All(); LED_ON(2);}break;
    		case 3 : {LED_Close_All(); LED_ON(3);}break;
    		case 4 : {LED_Close_All(); LED_ON(4);}break;
    		default: LED_Close_All();
    	}
    }
    

    然后在主函数中调用flag_Cont();即可实现

    对于功能3的实现,就更容易了,首先定义一个模式选择器,全局外部变量哦;然后中断函数是这样写的

    /*	@函数名称:中断服务子程序2
    		@函数功能:响应中断2的子程序
    		@输入参数:无
    		@返回值	 :无
    		@注意		 :中断中不要放延时过长的程序,也不要写死循环
    */
    void EXTI2_IRQHandler(void)
    {
    	delay_non_ms(10);
    	if(EXTI_GetFlagStatus(EXTI_Line2)==SET)
    	{
    		if(mode==1)
    		{
    			mode=0;
    		}
    		else
    			mode++;
    	}
    	EXTI_ClearITPendingBit(EXTI_Line2);
    	
    }
    

    然后模式选择器函数是这样写的

    /*	@函数名称:void Select_Mode(void)
    		@函数功能:模式选择器
    		@输入参数:无
    		@返回值	 :无
    		@注意		 :
    */
    void Select_Mode(void)
    {
    	 switch(mode+1)
    	 {
    		 case 1 : LED_Base_200ms(time_flag);break;
    		 default: flag_Control();
    	 }
    }
    
    

    后面就可在主程序中调用flag_Control();

  • 相关阅读:
    洛谷—— P2234 [HNOI2002]营业额统计
    BZOJ——3555: [Ctsc2014]企鹅QQ
    CodeVs——T 4919 线段树练习4
    python(35)- 异常处理
    August 29th 2016 Week 36th Monday
    August 28th 2016 Week 36th Sunday
    August 27th 2016 Week 35th Saturday
    August 26th 2016 Week 35th Friday
    August 25th 2016 Week 35th Thursday
    August 24th 2016 Week 35th Wednesday
  • 原文地址:https://www.cnblogs.com/liyingji/p/14241900.html
Copyright © 2011-2022 走看看