北京交通大学2019年校内电子设计竞赛单片机部分——STM32F103正点原子开发板实现

因为在学STM32,所以闲着无事找了找有没有什么简单的利于上手开工的小项目,恰巧碰到了“北京交通大学2019年校内电子设计竞赛单片机部分”。想着练一下手也不错。

首先来看一下题目:
在这里插入图片描述

要求很简单,“单击、双击、长按”三个动作对应三种不同的响应,可以用状态机来完成。

这里一个一个分解每个要求:

  1. 单击按键
    单击按键要求实现四档亮度“灭-低亮度-中亮度-高亮度”,这个很简单,我们可以通过PWM波来实现。这里我就直接贴代码上来了。不难读懂,直接利用了STM32库函数的TIM_SetCompare2()实现。
int     ValueBright[4]         =                 { 1,3,5,0 };
void Single_Press(void)
{
    if(stateNow == StateSinglePress)
        TIM_SetCompare2(TIM3,ValueBright[valueIndex]*100);
    if(stateNow == StateNotPressed)
    {
        TIM_SetCompare2(TIM3,0);
    }
}

  1. 双击按键
    双击按键要求进入呼吸灯状态,这个如果是跟我一样学正点原子的STM32的话是自然不陌生的,我也不多说了,直接使用PWM波完成。上代码。
void Double_Press(void) 
{
    if(stateNow == StateDoublePress)
    {
        delay_ms(10);
        if(flagPwm) valuePwm += 2;
        else valuePwm -= 2;
        
        if(valuePwm > 500) flagPwm = 0;
        if(valuePwm == 0) flagPwm = 1;
        
        TIM_SetCompare2(TIM3,valuePwm);
    }
}
  1. 长按按键
    长按按键有点不同,因为这个地方要求实现LED以50%的占空比循环亮灭,并且整个周期的时间是根据自己的按键时长来决定的。所以这里给我们提出的要求就是:使用PWM波实现50%占空比和使用定时器记录按键时长
    因此这个地方就不能像上面两个那样定义一个普通函数来完成响应动作,而应该通过TIM的中断处理函数来实现这个功能。这里解释一下:
    通过设置TIM4每10ms触发一次中断,在中断处理函数内累加timePressed来记录长按时间,如果长按时间大于预设的阈值TimeLongPress那我们就认为进入长按状态了。但是进入了长按状态之后我们不能马上就开始响应动作,因为这个时候如果还没有抬起按键就会出错的。所以通过一句if(valueBefore == 1 && valueNow == 0)来判断是否抬起按键了。
void TIM4_IRQHandler(void)
{
	case StatePressed:
		timePressed++;
        if(valueBefore == 1 && valueNow == 0)
        {
        	if(timePressed >= TimeLongPress)
            	stateNow = StateLongPress;
            else
                stateNow = StateNextState;
         }
    break;
    
    case StateLongPress:
		cnt++;
		if(cnt <= timePressed/2)
			TIM_SetCompare2(TIM3,450);
		else if(cnt >= timePressed/2)
		    TIM_SetCompare2(TIM3,0);
		if(cnt >= timePressed)
		     cnt = 0;
	break;
}
  1. 单击按键退出当前工作模式
    这个地方需要我们在进行相应动作的时候能根据按键退出当前的响应动作,所以我选用了简单的外部中断处理。这里我就直接上代码了。
void EXTI4_IRQHandler(void)
{
    delay_ms(50);
    if(isIntHappen == 0 && GPIO_ReadInputDataBit(KEY_PORT,KEY_PIN) == 0)
    {
        isIntHappen = 1;
        if(stateNow == StateSinglePress)
        {
            valueIndex++;
            if(valueIndex == 3)
            {
                EXTIX_Disable();//关闭外部按键中断
                TIM_SetCompare2(TIM3,0);
                CLEAR_ALL_PARA();//还原所有数据至初始状态 
                TIM_Cmd(TIM4, ENABLE);//开启TIM4中断
                flagQuit = 1;
            }
        }
        else if(stateNow == StateDoublePress)
        {
            EXTIX_Disable();//关闭外部按键中断
            TIM_SetCompare2(TIM3,0);
            CLEAR_ALL_PARA();//还原所有数据至初始状态 
            TIM_Cmd(TIM4, ENABLE);//开启TIM4中断
            flagQuit = 1;
        }
        else if(stateNow == StateLongPress)
        {
            EXTIX_Disable();//关闭外部按键中断
            stateNow = StateNotPressed;
            TIM_SetCompare2(TIM3,0);
            CLEAR_ALL_PARA();//还原所有数据至初始状态
            GPIO_ResetBits(GPIOE,GPIO_Pin_5);
        }            
        isIntHappen = 0;
    }
    EXTI_ClearITPendingBit(EXTI_Line4);
}

其实功能很简单,就是检测到外部按键中断后进入外部中断处理函数EXTI4_IRQHandler(void)中,在这个中断处理函数里面把工作状态还原到最初的工作状态,然后清除掉那些临时变量的值,然后关闭外部中断(后面说明为什么要关闭外部中断)。

最后把上面的代码合并一次,构思一下整体。在上面的代码中,我用到了外部中断EXTI4_IRQHandler(void),用到了定时器中断处理函数TIM4_IRQHandler(void),用到了PWM波TIM_SetCompare2()函数。所以这里我们需要使用两个TIM,一个用来做普通的计时检测按键状态,一个用来专门PWM相关。

所以整体的系统工作为:

  • 通过TIM4实现按键状态的检测,通过改变stateNow这个变量来记录现在的工作状态。提前设置了下面几种工作状态:
#define StateNotPressed          0x11//空闲
#define StatePressed             0x22//被按下了
#define StateLongPress           0x33//长按状态
#define StateDoublePress         0x44//双击状态
#define StateSinglePress         0x55//单击状态
#define StateNextState           0x66//被按下后抬起等待是否会双击状态
  • 当进入某一工作状态后进行相应的响应动作,这个时候激活外部中断EXTI4检测是否有外部中断触发中断处理函数退出工作状态
  • 当退出工作状态时要再次使失活外部中断EXTI4,防止下次按键被读取为外部中断。

最后的最后放个链接,整个工程写的比较仓促,用了很多正点原子的代码,有些也没有细改了,如果发现有些地方名字和实际不和还以实际情况为主(只是我偷懒没改)。大家多多包容,新手上路。欢迎交流
链接:https://pan.baidu.com/s/1asVjmNFozLC1_etJ4pBYKw
提取码:ux7f

发布了4 篇原创文章 · 获赞 2 · 访问量 159

猜你喜欢

转载自blog.csdn.net/weixin_43680772/article/details/105431015