继LED轮询之后https://blog.csdn.net/panrenqiu/article/details/79776083,今天写一个LED按键中断程序来记录一下学习情况。
***************************************************************************************************************************************
开发板 :奋斗STM32
CPU :STM32F103
开发环境:keil uVsion4
****************************************************************************************************************************************
前言:本文主要是通过按键中断,实现当按下按键时,LED灯灭,释放按键时,LED灯亮。(不过我设置LED的起始状态为亮,也就是上电就点亮了LED灯。)
下面看main.c
#include "stm32f10x.h"
#include "led.h"
#include "exti.h"
int main(void)
{
init_led_gpio();
turn_led(LED1,ON);
/*exti line config */
EXTI_PC_Config();
while(1)
{
;
}
}
led.c
#include "led.h"
led_gpio_t leds_gpio[MAX_LED] =
{
{LED1, GPIOB, GPIO_Pin_5}, /* LED1 用的GPB5 */
{LED2, GPIOD, GPIO_Pin_6}, /* LED2 用的GPD6 */
{LED3, GPIOD, GPIO_Pin_3}, /* LED3 用的GPD3 */
};
void init_led_gpio(void)
{
int i;
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能PB和PD组 GPIO的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD , ENABLE);
/*设置 PB5(LED1), PD6(LED2), PD3(LED3)为 GPIO 输出推免模式,口线翻转速度为50MHz */
for(i=0; i<MAX_LED; i++)
{
/*设置 PB5(LED1)为 GPIO 输出推免模式,口线翻转速度为50MHz */
GPIO_InitStructure.GPIO_Pin = leds_gpio[i].pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(leds_gpio[i].group, &GPIO_InitStructure);
}
}
void turn_led(int which, int cmd)
{
if(which<0 || which> MAX_LED )
return;
if(OFF == cmd)
GPIO_ResetBits(leds_gpio[which].group, leds_gpio[which].pin);
else
GPIO_SetBits(leds_gpio[which].group, leds_gpio[which].pin);
}
exti.c
#include "stm32f10x.h"
#include "exti.h"
#include "led.h"
void EXTI_PC_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_config();
NVIC_Configuration();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);
EXTI_InitStructure.EXTI_Line = EXTI_Line5;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* EXTI line gpio config (PE) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5);
}
void EXTI9_5_IRQHandler(void)
{
static uint8_t led1_status = OFF;
if(EXTI_GetITStatus(EXTI_Line5) != RESET)
{
led1_status ^= 1;
turn_led(LED1, led1_status);
// EXTI_ClearITPendingBit(EXTI_Line5);
}
}
我写的按键中断程序实现的功能是:按下按键K1,LED1由亮变灭,释放按键LED1又变亮。(按键K1对应PC5管脚,LED1对应PB5管脚)。
下面我们来具体分析本文的代码
1)初始化时钟和配置LED
void init_led_gpio(void)
{
int i;
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能PB和PD组 GPIO的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD , ENABLE);
/*设置 PB5(LED1), PD6(LED2), PD3(LED3)为 GPIO 输出推免模式,口线翻转速度为50MHz */
for(i=0; i<MAX_LED; i++)
{
/*设置 PB5(LED1)为 GPIO 输出推免模式,口线翻转速度为50MHz */
GPIO_InitStructure.GPIO_Pin = leds_gpio[i].pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(leds_gpio[i].group, &GPIO_InitStructure);
}
}
2.配置中断优先级
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
这个中断优先级的设置可以随便设置,原因是我创建的工程中只用到了按键中断,没有其他中断,当然如果有多个中断,就得按照中断向量表来设置
3.
配置外部中断线
EXTI_InitStructure.EXTI_Line = EXTI_Line5;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
4.中断处理函数
void EXTI9_5_IRQHandler(void)
{
static uint8_t led1_status = OFF;
if(EXTI_GetITStatus(EXTI_Line5) != RESET)
{
led1_status ^= 1;
turn_led(LED1, led1_status);
// EXTI_ClearITPendingBit(EXTI_Line5);
}
}
这里的中断处理函数我们通常最好是放在
stm32f10x_it.c这个文件,这是官方提供的一个用来放所有外部中断处理函数的文件,当主程序在执行程序时,如果发生中断,cpu会立即跳到这里来执行中断处理函数,这里因为只有按键中断,还体现不出这样做的好处,如果是一个大工程,用到多个中断时,把中断函数统一放在这个文件中的话,可以大大优化代码,当然这里也可以放在exti.c文件中。