1.STM32的IO口可以作为外部中断输入口。本文通过按键按下作为外部中断的输入,点亮LED灯。在STM32的19个外部中断中,0-15为外部IO口的中断输入口。STM32的引脚分别对应着0-15的外部中断线。比如,外部中断线0对应着GPIOA.0-GPIOG.0,以此类推就可以将所以的IO映射到0-15个外部中断线上。STM32的IO的外部中断映射图如下:
2.外部中断的配置步骤:
(1)将IO口映射到对应的外部中断线上,中断线河中断初始化。
(2)配置外部中断,即配置中断管理NVIC。
(3)重写中断服务函数,即中断回调函数。这些中断回调函数在startup_stm32f10x_xx.s中被规定好了名称,我们只需要重写对应的中断回调函数即可。
3.工程代码:
delay.h:
#ifndef __DELAY_H
#define __DELAY_H
#include "stm32f10x.h"
void delay_us(uint32_t us); //ÑÓʱ΢Ãë
void delay_ms(uint32_t ms); //ÑÓʱºÁÃë
#endif
delay.c:
#include "delay.h"
void delay_us(uint32_t us)
{
uint32_t i;
//1.Ñ¡ÔñHCLKʱÖÓ£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµ
SysTick_Config(72);
for(i = 0;i < us;i++)
{
while(!((SysTick->CTRL) & (1 << 16))); //µÈ´ý¼ÆÊýÍê³É
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}
void delay_ms(uint32_t ms)
{
uint32_t i;
//1.Ñ¡ÔñHCLKʱÖÓÔ´£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµ
SysTick_Config(72000);
for(i = 0;i < ms;i++)
{
while(!((SysTick->CTRL) & (1 << 16))); //µÈ´ý¼ÆÊýÍê³É
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}
key.h:
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
#define KEY_0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5) //¶ÁÈ¡°´¼üµÄ״̬
#define KEY_1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)
#define KEY_2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
void KEY_Init(void);
void KEY_Scan(void); //°´¼üɨÃ躯Êý
#endif
key.c:
#include "key.h"
#include "delay.h"
#include "led.h"
void KEY_Init(void)
{
/*1.¶¨ÒåÒý½ÅµÄ½á¹¹Ìå¡£
2.ʹÄÜÒý½Å¶ÔÓ¦µÄʱÖÓ¡£
3.ÅäÖÃÒý½ÅÐÅÏ¢*/
//¶¨ÒåÒý½Å½á¹¹Ì壺
GPIO_InitTypeDef GPIO_InitStruct;
//ʹÄÜʱÖÓ£º
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);
//ÅäÖÃÒý½ÅÐÅÏ¢(KEY0)£º
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
//ÅäÖÃKEY1£º
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //ÉèÖóÉÉÏÀÊäÈë
GPIO_Init(GPIOA,&GPIO_InitStruct);
//ÅäÖð´¼üWK_UP:
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA,&GPIO_InitStruct);
LED_Init(); //³õʼ»¯LED
}
void KEY_Scan(void)
{
static u8 key_up = 1; //°´¼üËÉ¿ª±ê־λ
if(key_up && (KEY_0 == 0|| KEY_1 == 0|| KEY_1 == 1))
{
delay_ms(10); //È¥¶¶¶¯
key_up = 0;
if(KEY_0 == 0)
{
GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
//delay_ms(1000);
}
else if(KEY_1 == 0)
{
GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
//delay_ms(1000);
}
else if(KEY_2 == 1)
{
GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
}
}
else if(KEY_0==1&&KEY_1==1&&KEY_2==0)
{
key_up = 1;
}
}
exti.h:
#ifndef __EXTI_H
#define __EXTI_H
#include "stm32f10x.h"
void EXTIx_Init(void);
#endif
exti.c:
#include "exti.h"
#include "key.h"
#include "delay.h"
void EXTIx_Init(void)
{
/*ÍⲿÖжϵÄÅäÖ÷½·¨£º
1.½«IO¿ÚÓ³Éäµ½¶ÔÓ¦ÍⲿÖжÏÏßÉÏ
2.ÅäÖÃÍⲿÖжÏ
3.ÖØдÖжϷþÎñº¯Êý£¬¼´Öжϻص÷º¯Êý*/
//¶¨ÒåÍⲿÖжϺÍÖжϵĽṹÌ壺
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//ʹÄÜʱÖÓ£º
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//ÍⲿÖжÏÐèÒª¸´ÓÃʱÖÓ
KEY_Init(); //³õʼ»¯°´¼ü
//GPIOC.5µÄÖжÏÏߺÍÖжϳõʼ»¯ÅäÖãº
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5); //GPIOÓëÖжÏÏß½øÐÐÓ³Éä
EXTI_InitStructure.EXTI_Line = EXTI_Line5;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_Init(&EXTI_InitStructure);//½«ÉÏÃæÅäÖõÄÐÅϢдÈëEXTI¼Ä´æÆ÷ÖÐ
//GPIOA.0µÄÖжÏÏߺÍÖжϳõʼ»¯ÅäÖãº
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //GPIOÓëÖжÏÏß½øÐÐÓ³Éä
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
//GPIOA.15µÄÖжÏÏߺÍÖжϳõʼ»¯ÅäÖãº
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15); //GPIOÓëÖжÏÏß½øÐÐÓ³Éä
EXTI_InitStructure.EXTI_Line = EXTI_Line15;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
//ÖжϹÜÀíÅäÖãº
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);
}
//ÖØдÖжϷþÎñº¯Êý.
void EXTI0_IRQHandlÕâЩÖжϻص÷º¯ÊýÔÚstartup_stm32f10x_xx.sÖб»¹æ¶¨ºÃÁËÃû³Æer(void)
{
//¾²Ì¬±äÁ¿Ö»»áÔÚµÚÒ»´ÎÔËÐÐʱ±»³õʼ»¯¡£ËùÒÔ£¬¿ÉÒÔÀí½âΪÕâÌõÓï¾äÖ»Ö´ÐÐÒ»´Î
static u8 flag1 = 1;
delay_ms(10); //Ïû¶¶
if(KEY_2 == 1)
{
if(flag1)
{
//GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
flag1 = !flag1;
}
else
{
GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
//GPIO_SetBits(GPIOD,GPIO_Pin_2);
flag1 = !flag1;
}
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI9_5_IRQHandler(void)
{
static u8 flag2 = 1;
delay_ms(10); //Ïû¶¶
if(KEY_0 == 0)
{
if(flag2)
{
//GPIO_ResetBits(GPIOA,GPIO_Pin_8);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
flag2 = !flag2;
}
else
{
//GPIO_ResetBits(GPIOA,GPIO_Pin_8);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
flag2 = !flag2;
}
}
EXTI_ClearITPendingBit(EXTI_Line5);
}
void EXTI15_10_IRQHandler(void)
{
static u8 flag3 = 1;
delay_ms(10); //Ïû¶¶
if(KEY_1 == 0)
{
if(flag3)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_8);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
flag3 = !flag3;
}
else
{
GPIO_SetBits(GPIOA,GPIO_Pin_8);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
flag3 = !flag3;
}
}
EXTI_ClearITPendingBit(EXTI_Line15);
}
main.c:
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
int main(void)
{
//LED_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2
KEY_Init();
EXTIx_Init();
while(1)
{
// GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
// GPIO_SetBits(GPIOA,GPIO_Pin_8);
// delay_ms(1000);
// GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
// GPIO_SetBits(GPIOD,GPIO_Pin_2);
// delay_ms(1000);
//KEY_Scan();
}
}
4.运行结果:按下key0,LED1亮,再按一下熄灭。按下key1,LED0亮,再按一下熄灭。按下key3,两个LED亮,再按一下两个LED熄灭。
5.总结:本文是通过key的外部中断来控制led的亮灭。其原理是利用STM32的IO可作为外部中断的输入口。当按下key时,对应的IO空作为输入会触发外部中断,然后系统会去调用对应的外部中断服务函数。通过中断,可以不用阻塞程序,在中断未被触发时,程序可以去执行其他的工作,提高系统的效率。
在配置外部中断的相关信息时,主要是配置相关的结构体信息、将IO映射到对应的中断线、配置中断管理NVIC。