目录
前言
刚刚接触培训的我一开始肯定是茫然的,但是经过了两周的培训,第一次任务已经完美完成了。现在把自己的心得记录一下。
首先本次培训的内容很简单:
1.介绍了STM32F407的使用方法,以及如何查看其相关数据手册。
2.介绍了基于keli5的基本程序编译,调用正点原子库函数中的跑马灯进行演示。
3.介绍了一个完整的单片机程序包括但不限于主函数中的循环部分,中断函数的中断条件以及中断语句中的执行。
4.串口的使用,以及串口的调试方法。
5.如何调试单片机程序以及一些同学遇到的问题。
这些内容都很碎片化,并且很抽象,对于笔者这种单片机新手来说是很不友好的。但是之后我根据老师布置的任务一步一步学习,最后总结了一下,发现还是收获颇丰。
下面先介绍一下任务详情:
按键控制流水灯
(以下全部程序都是在正点原子的库函数中的程序加以引用和改动)
KEY0按一下,开启流水灯,再按一下,LED灯熄灭。
看上去很简单的一个功能,但就是这样简单一个功能让我纠结了1个晚上。
一开始我的想法是不使用中断(因为当时还不是很熟练),就用简单的flag奇偶判断,于是我在主函数里写道:
int main()
...//一些初始化
while(1)
if(key1==0)
{
delay_ms(10);//按键消抖
flag++;
}
if(flag%2==0)//判断为偶,则两个灯都灭
{
led1=0;
led2=0;
}
if(flag%2==1)//判断为奇,则开始流水灯
{
led1=~led1;
delay_ms(100);//延时100ms,不然两个灯闪的太快,下面同理
led2=~led2;
delay_ms(100);
}
但是烧入程序后我发现流水灯只能用一次,之后再按开关就没有用了,我以为是循环的问题,于是将控制流水灯启动的条件里面加了个while死循环,之后就不用说了......自然是流水灯一直在闪烁,无法关闭。
就在我一筹莫展时,我想到了中断系统这一单片机神奇的功能,因为单片机的中断系统将迫使暂停CPU正在执行的程序,转而去进行中断事件的处理;中断处理完毕后。又返回被中断的程序处,继续执行下去。于是我将外部中断的库函数也加入了进来:
void EXTIX_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
KEY_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);
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);
EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
之后就是在中断函数里写中断条件以及中断后执行的语句了
void EXTI4_IRQHandler(void)
{
delay(1);//注意这里要在中断函数里重新定义一个delay函数,如果用库函数里自带的会导致程序卡死
if(KEY0==0)
{
Num++;
}
EXTI_ClearITPendingBit(EXTI_Line4);
}
然后就是在主函数里写入功能循环
int main(void)
...//一些初始化
extern u8 Num;
while(1)
{
if(Num%2==1)
{
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //相当于LED0=0,LED0对应引脚拉低
GPIO_SetBits(GPIOF,GPIO_Pin_10); //相当于LED1=1,LED1对应引脚拉高
delay_ms(100); //延时100ms
GPIO_SetBits(GPIOF,GPIO_Pin_9); //相当于LED0=1,LED0对应引脚拉高
GPIO_ResetBits(GPIOF,GPIO_Pin_10); //相当于LED1=0,LED1对应引脚拉低
delay_ms(100); //延时100ms
}
if(Num%2==0)
{
LED0=1;
LED1=1;
}
}
烧入程序,发现流水灯可以完美执行,一次开关按下启动,再次按下开关关闭。
总结
就如同我开头所写的那样,一个完整的单片机程序中是肯定的包括主函数和中断函数的(除非特别简单的),所以当你发现你的程序在单片机里运行起来就无法打断时,可以试一试中断系统。希望能够通过这一个简单的程序帮助到你之后“玩”单片机。