嵌入式开发学习之--抢答器
本篇以一个简单的抢答器来学习外部中断。
文章目录
前言
一、项目概况
1.1项目需求
1.2 项目来源
1.3开发环境
1.4项目意义
二、开发步骤
2.1涉及硬件电路
2.2项目代码
2.2.1中断配置
总结
前言
前一篇大致了解了什么是中断,中断需要配置的参数,再结合之前的按键输入,这一篇实战一下。
提示:以下是本篇文章正文内容,下面案例可供参考
一、项目概况
1.1项目需求
两个按键,按下后蜂鸣器都会响;
1号按键按下,led红灯长亮;2号按键按下,led蓝灯长亮;
任意一个按键按下后,另一个按键按下将没有任何反应;也就是说led只会有一种颜色。
1.2 项目来源
作者脑洞;
1.3开发环境
软件:keil5;
硬件:野火挑战者开发板。
1.4项目意义
可以用在很多娱乐活动中,也可以增加家庭娱乐气氛,也可以用来维持讨论时的纪律,工作的人应该都知道讨论问题尤其是要负责任的问题时,有多么吵。
二、开发步骤
2.1涉及硬件电路
电路图请参考之前按键检测试验,这里不放了。
2.2项目代码
2.2.1中断配置
代码如下(示例):
exti.h
#ifndef __EXTI_H #define __EXTI_H #include "stm32f4xx.h" #define KEY1_INT_GPIO_PORT GPIOA #define KEY1_INT_GPIO_CLK RCC_AHB1Periph_GPIOA #define KEY1_INT_GPIO_PIN GPIO_Pin_0 #define KEY1_INT_EXTI_PORTSOURCE EXTI_PortSourceGPIOA #define KEY1_INT_EXTI_PINSOURCE EXTI_PinSource0 #define KEY1_INT_EXTI_LINE EXTI_Line0 #define KEY1_INT_EXTI_IRQ EXTI0_IRQn #define KEY1_IRQHandler EXTI0_IRQHandler #define KEY2_INT_GPIO_PORT GPIOC #define KEY2_INT_GPIO_CLK RCC_AHB1Periph_GPIOC #define KEY2_INT_GPIO_PIN GPIO_Pin_13 #define KEY2_INT_EXTI_PORTSOURCE EXTI_PortSourceGPIOC #define KEY2_INT_EXTI_PINSOURCE EXTI_PinSource13 #define KEY2_INT_EXTI_LINE EXTI_Line13 #define KEY2_INT_EXTI_IRQ EXTI15_10_IRQn #define KEY2_IRQHandler EXTI15_10_IRQHandler /*******************************************************/ void EXTI_Key_Config(void); #endif /* __EXTI_H */
exti.c
#include "exti.h" static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ; NVIC_Init(&NVIC_InitStructure); } void EXTI_Key_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; RCC_AHB1PeriphClockCmd(KEY1_INT_GPIO_CLK|KEY2_INT_GPIO_CLK ,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); NVIC_Configuration(); GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure); SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INT_EXTI_PINSOURCE); EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN; GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure); SYSCFG_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE,KEY2_INT_EXTI_PINSOURCE); EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); }
简单说一下,NVIC_Configuration(void)函数中定义了中断优先级以及初始化; EXTI_Key_Config(void)函数则是在按键输入的基础上又加了中断的一些配置,比如上升沿还是下降沿触发,触发的引脚是什么,宏定义中,注意外部中断用的是哪个,则后面的中断函数也需要用哪一个。
app.c
#include "app.h" enum Respond respond; //³õʼ»¯app void app_init(void) { respond=NOBODY; } uint8_t user_rank(void) { if(respond==NOBODY){ respond=FIRST; return FIRST; }else{ return NOBODY; } }
app.c中做了一个user_rank函数,利用类似互斥锁的理论,来锁定哪一个先触发。
stm32f4xx.c
void KEY1_IRQHandler(void) { if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) { if(user_rank()==FIRST){ LED_RED; } EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); } } void KEY2_IRQHandler(void) { if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) { if(user_rank()==FIRST){ LED_BLUE; } EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE); } }
将中断函数放在stm32f4xx.c中,无论哪一个触发一次后,另一个按键将不会生效了。
#include "stm32f4xx.h" #include "led.h" #include "beep.h" #include "key.h" #include "exti.h" #include "app.h" void bsp_init(void) { BEEP_GPIO_Config(); // Key_GPIO_Config(); LED_GPIO_Config(); EXTI_Key_Config(); } uint8_t key1_inspect() { if(KEY1_READ==KEY_ON){ return KEY_ON; }else if(KEY1_READ==KEY_OFF){ return KEY_OFF; } } uint8_t key2_inspect() { if(KEY2_READ==KEY_ON){ return KEY_ON; }else if(KEY2_READ==KEY_OFF){ return KEY_OFF; } } int main(void) { uint8_t led_status; led_status=OFF; bsp_init(); app_init(); while(1){ if(key1_inspect()==KEY_ON){ BEEP_ON; while(key1_inspect()==KEY_ON){ } BEEP_OFF; } if(key2_inspect()==KEY_ON){ BEEP_ON; while(key1_inspect()==KEY_ON){ } BEEP_OFF; } } }
main.c主要是按键按下后蜂鸣器的处理。
总结
1、利用中断能节省资源,提高效率;
2、能实现任务并行。
3、在写上层逻辑中,要注意的是当多中断同时调用某一变量或者某一函数,最好加互斥锁,否则可能数据会出错。