案例
LCD屏显示时间,按键动态调节时、分、秒
案例说明
为什么会想到采用中断?
时钟设有一个初始的时间,时钟在运行时肯定要对时间调整。调整时间用按键来实现,对按键的处理有两种方法,一种是查询法,另一种是中断方法。查询法耗用大量的CPU运行时间,还要与动态扫描程序进行融合,效率低,编程复杂。中断法很好地克服上述缺点,故采用外部中断进行按键处理,完成时间调节。
设计分析
所有中断配置写在exit.c文件中。
代码编写
exti.c
extern u8 hour,minute,second;
EXTI初始化函数
void EXIT_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,ENABLE);//打开时钟并复用
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
//GPIO初始化
//PC13
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IPU; //上拉输入模式
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_13;
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
//PB12,14
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IPU; //上拉输入模式
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_12|GPIO_Pin_14;
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//给端口引脚加上中断线
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
//中断初始化
EXTI_InitStruct.EXTI_Line =EXTI_Line12|EXTI_Line13|EXTI_Line14;
EXTI_InitStruct.EXTI_Mode =EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger =EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd =ENABLE;
EXTI_Init(&EXTI_InitStruct);
//NVIC初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//中断线设置优先级
NVIC_InitStruct.NVIC_IRQChannel =EXTI15_10_IRQn;//中断线10-15的中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =1;//抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority =0;//响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;//使能
NVIC_Init(&NVIC_InitStruct);//中断初始化
NVIC_InitStruct.NVIC_IRQChannel =EXTI15_10_IRQn;//中断线10-15的中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority =0;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel =EXTI15_10_IRQn;//中断线10-15的中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority =1;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
问:pinN一定要连接中断线lineN,中断通道一定要是NIRQn吗?
答:pin0-4连接中断线line0-4,中断通道0-4IRQn
pin5-9连接中断线line5-9,中断通道5-9IRQn
pin10-15连接中断线line10-15,中断通道10-15IRQn
所以上面pin12,13,14分别连接中断线line12,13,14,中断通道为10-15IRQn。
问:那它们的中断通道都是exti15_10这咋办啊,中断函数要三个呢
答:在这个函数里面,用if去判断哪一个被触发。
中断函数
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line12)==SET) //获取中断标志
{
if(K_OK==0)
{
if(K_OK==0)
{
delay_ms(10);
if(++hour==24) hour =0;
}
}
EXTI_ClearITPendingBit(EXTI_Line12);//清除中断
}else if(EXTI_GetITStatus(EXTI_Line13)==SET){ //获取中断标志
if(K_UP==0)
{
if(K_UP==0)
{
delay_ms(10);
if(++minute==60) minute=0;
}
}
EXTI_ClearITPendingBit(EXTI_Line13);//清除中断
}else if(EXTI_GetITStatus(EXTI_Line14)==SET){ //获取中断标志
if(K_RIGHT==0)
{
if(K_RIGHT==0)
{
delay_ms(10);
if(++second==60) second=0;
}
}
EXTI_ClearITPendingBit(EXTI_Line14);//清除中断
}
}
main.c
u8 hour,minute,second;
int main()
{
hour=9;
minute=6;
second=18;
delay_init(72);
Power_Init(); //电源IO初始化
LED_Init(); //LED初始化
LCD_Init();
EXIT_Init();
LCD_ClearGram();
while(1)
{
char dissbuff[25];
LCD_ClearGram();
sprintf(dissbuff,"time:%d:%d:%d",hour,minute,second);//组合字符和变量
LCD_ShowAllString(0,20,(u8 *)dissbuff,16,1);
LCD_RefreshGram();
}
}
实现效果
参考
《ARM Cortex-M3嵌入式原理及应用》
我的学弟