本篇文章将讲述两种方法实现外部中断控制LED流水灯的方法及代码(按键控制流水灯)。
可以根据我的方法进行创新,我会将思路也一同介绍。
首先,第一种:(whlie里面实现,不用定时器,运行完一次之后才能实现反向,只能从头开始亮)
我考虑这个问题时,就会首先想到最简单的while循环,利用while循环来实现。先讲思路,就是我们的程序是会反复进行whlie里面的循环的,然后我们就可以进行延时,逐一点亮LED实现流水灯的效果,这在我之前文章中介绍过,然后我们现在是想每次按键它的方向改变,我们可以定义一个参数,然后按一次按键,这个参数改变一次,每次对应不同的结果,即流水灯不同的流动方向。我们可以利用switch函数来实现(在我C语言的文章中有讲解switch)
具体实操:这个不需要配置定时器等,只需要打开外部中断即可。然后我们先配置一下最基础的,备注一下led引脚和外部中断按键引脚。我之前文章中讲到过如何配置,我这里简单展示和讲解。我用的是STM32F107VCT6的板子,所以对应的引脚是PE9 PE11 PE13 PE14 外部按键对应的引脚是PC6,大家根据自己板子的原理图进行配置,我这里给它们分别备注为D1,D2,D3,D4和K1,方便我们引用。然后再NVIC中打开外部中断。


我们定义一个全局变量n(因为我们要在主函数中用又要在中断中使用,所以需要定义为全局变量),在main函数上面定义即可 例如下面位置

代码太长我不截图展示了,直接给大家打出来了
whlie(1)里面
switch(n)
{
case 0:
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,0);//写低电平,点亮第1个LED
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE,D2_Pin,0);
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_11,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE,D3_Pin,0);
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE,D4_Pin,0);
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_14,GPIO_PIN_SET);
break;
}
case 1:
{
HAL_GPIO_WritePin(GPIOE,D4_Pin,0);//写低电平,点亮第1个LED
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,D4_Pin,1);//
//中间不延时,1灯灭�?2灯亮
HAL_GPIO_WritePin(GPIOE,D3_Pin,0);
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,D3_Pin,1);
HAL_GPIO_WritePin(GPIOE,D2_Pin,0);
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,D2_Pin,1);
HAL_GPIO_WritePin(GPIOE,D1_Pin,0);
HAL_Delay(1000);//延时1000毫秒
HAL_GPIO_WritePin(GPIOE,D1_Pin,1);
break;
}
default:
{
break;
}
}外部中断(外部中断回调函数)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==K1_Pin)
{
for(long i =1; i<72000;i++)//消抖
{}
n=!n;//逻辑非 0或者1
}
}我们可以通过分析程序看出,我写了两种情况,一种是case 0 从D1到D4亮
另一种是case 1 从D4到D1亮
然后我们通过外部中断改变n值来实现这这两种流向的改变,但是这种只能是运行完一次后改变方向,从头开始亮,能部分达到我们的预期
第二种:(利用定时器,能直接反向,完全达到预期)
而且没有应用Delay,利用的是定时器中断
我们一样先将思路:我们先想到了第一种情况的办法,然后我之前也写过定时器控制流水灯的文章,我们结合起来,写两种情况,每种不同方向,但是我们要注意,我们利用定时器实现流水灯是利用了i++,然后if判断,如果我们改变了情况,也就是进入另一个case中的时候 i是多少,我们注意到这点之后,我们就可以判断当时是哪个灯亮了,在此基础上,顺时针方向亮的话是i++,改变方向,我们就可以i--实现
接着我们看具体实操
首先我们要配置一下io口和外部中断,如上,定时器我们可以配置溢出时间间隔,每次溢出都会进入中断回调函数,在之前的文章中有讲,不懂配置的可以去看看前面的文章。我简单展示
因为我的板子是25M频率的,所以我按照如下配置时间间隔为0.5ms

打开定时器中断

然后我们定义两个我们要用到的全局变量

打开定时器中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{ switch(n)
{
case 0:
{
if(i==1)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,0);
HAL_GPIO_WritePin(GPIOE,D2_Pin,1);
HAL_GPIO_WritePin(GPIOE,D3_Pin,1);
HAL_GPIO_WritePin(GPIOE,D4_Pin,1);
}
else if(i==2)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,1);
HAL_GPIO_WritePin(GPIOE,D2_Pin,0);
HAL_GPIO_WritePin(GPIOE,D3_Pin,1);
HAL_GPIO_WritePin(GPIOE,D4_Pin,1);
}
else if(i==3)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,1);
HAL_GPIO_WritePin(GPIOE,D2_Pin,1);
HAL_GPIO_WritePin(GPIOE,D3_Pin,0);
HAL_GPIO_WritePin(GPIOE,D4_Pin,1);
}
else if(i==4)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,1);
HAL_GPIO_WritePin(GPIOE,D2_Pin,1);
HAL_GPIO_WritePin(GPIOE,D3_Pin,1);
HAL_GPIO_WritePin(GPIOE,D4_Pin,0);
i=0;
}
i++;
break;
}
case 1 :
{
if(i==2)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,0);
HAL_GPIO_WritePin(GPIOE,D2_Pin,1);
HAL_GPIO_WritePin(GPIOE,D3_Pin,1);
HAL_GPIO_WritePin(GPIOE,D4_Pin,1);
i=6;
}
else if(i==3)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,1);
HAL_GPIO_WritePin(GPIOE,D2_Pin,0);
HAL_GPIO_WritePin(GPIOE,D3_Pin,1);
HAL_GPIO_WritePin(GPIOE,D4_Pin,1);
}
else if(i==4)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,1);
HAL_GPIO_WritePin(GPIOE,D2_Pin,1);
HAL_GPIO_WritePin(GPIOE,D3_Pin,0);
HAL_GPIO_WritePin(GPIOE,D4_Pin,1);
}
else if(i==5)
{
HAL_GPIO_WritePin(GPIOE,D1_Pin,1);
HAL_GPIO_WritePin(GPIOE,D2_Pin,1);
HAL_GPIO_WritePin(GPIOE,D3_Pin,1);
HAL_GPIO_WritePin(GPIOE,D4_Pin,0);
}
i--;
break;
}
default:
{
break;
}
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==K1_Pin)
{
for(long i =1; i<72000;i++)
{}
if (HAL_GPIO_ReadPin(K1_GPIO_Port,K1_Pin)==1)
{
n=!n;
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}
}我们注意在这里面与第一种方法的不同,我们在每次运行结束的时候i--或者i++,所以i++的时候是1234,i--的时候就应该是2345.每次改变的时候i有着对应的i值,所以能实现直接反向,不用从头又开始。
有些才用软件的朋友可能不清楚外部中断和定时器中断写在哪里,其实可以写在begin4里面,如图

这样我们就逐步的实现了外部中断控制流水灯。