***************************************************************************************************************************************
开发板 :奋斗STM32
CPU :STM32F103
开发环境:keil uVsion4
****************************************************************************************************************************************
前言:本文主要是通过按键中断,实现当按下按键时,LED灯灭,释放按键时,LED灯亮。(不过我设置LED的起始状态为亮,也就是上电就点亮了LED灯。)
我的开发板按键,LED所对应的GPIO管脚原理图如下:

我写的按键中断程序实现的功能是:按下按键K2,LED3由亮变灭,释放按键LED3又变亮。(按键K2对应PC2管脚,LED3对应PD3管脚)。
测试代码:
#include "misc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_rcc.h"
#define LED_ON GPIO_SetBits(GPIOD, GPIO_Pin_3);
//unsigned char flag=0;
//unsigned char num=0;
void LED_Config(void);
void EXTI_PC2_Config(void);
void RCC_Config(void);
//void KEY_Dither(void);
//void delay_nms(u16 time);
int main(void)
{
// unsigned char a = 0;
RCC_Config();
LED_Config();
EXTI_PC2_Config();
LED_ON;
while(1)
{
//KEY_Dither();
//if(num==1&&a==0){GPIO_ResetBits(GPIOD,GPIO_Pin_6);a=1;}
//else if(num==1&&a==1){GPIO_SetBits(GPIOD,GPIO_Pin_6);a=0;}
}
}
/*void KEY_Dither(void)
{
num=0;
if(flag==1)
{
delay_nms(12000);
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6)==0)
{
delay_nms(12000);
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6)==0)
{
while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_6)==0)
num=1;
goto n_exit;
}
}
else ;
n_exit:;
flag=0;
}
}
void delay_nms(u16 time)
{
u16 i=0;
while(time--)
{
i=12000; //自己定义
while(i--) ;
}
}
*/
void RCC_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOD,ENABLE);
SystemInit();
}
void LED_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*led config*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
void EXTI_PC2_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/*config for NVIC*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* key for exti */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2);
/*EXIT line(PC2) mode config */
EXTI_InitStructure.EXTI_Line = EXTI_Line2;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
void EXTI2_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line2) != RESET)
{
// flag= 1;//按键按下标志
/*LED取反*/
GPIO_WriteBit(GPIOD, GPIO_Pin_3,
(BitAction)((1-GPIO_ReadOutputDataBit(GPIOD, GPIO_Pin_3))));
EXTI_ClearITPendingBit(EXTI_Line2);
}
}
************************************************************************************************************************************
说明:我写的这个程序只是实现了按键按下灯由亮变灭的简单功能,但是测试发现,这个按键抖动太严重,轻轻的触摸按键,灯会闪闪的亮,有时
候碰一下按键,还没有按下按键时,LED灯就熄灭了。所以用delay_nms()延时函数进行去抖,代码中注释掉的代码是为了按键去抖,不过这个去抖效果不是很好,还是会有抖动现象,但相比之前会好一点!不过官方提供了一个延时函数,可以调用官方写好的延时函数,一般10ms的时间可以去抖。
************************************************************************************************************************************************
写这个程序主要是完成相应的配置工作,步骤如下:
(1)初始化系统时钟和
初始化外部时钟(时钟配置)
void RCC_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOD,ENABLE);
SystemInit(); //系统时钟初始化
}
*****************************************************************************************************************************************************************************
说明:我们可以不用加SystemInit();不加这个函数也没影响,因为startup_stm32f10x_hd.s这个文件已经帮我们做了这些事情。
*****************************************************************************************************************************************************************************
(3)配置LED
void LED_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*led config*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
(4)配置中断优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
*********************************************************************************************************************************************************************************
说明:这个中断优先级的设置可以随便设置,原因是我创建的工程中只用到了按键中断,没有其他中断,当然如果有多个中断,就得按照中断向量表
以及中断优先级设定规则来设,具体规则可以参考网上的资料,有很多,可以看看,这里我就不说明了。这里我设置的是第一组中断,抢占优先级是
0,响应优先级也是0。
************************************************************************************************************************************************************************************
(5)配置外部中断线
/*EXIT line(PC2) mode config */
EXTI_InitStructure.EXTI_Line = EXTI_Line2;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
*************************************************************************************************************************************************************************************
说明:这个中断模式有两种,一是Event,二是Interrupt,因为这里是中断,所以我们设为
Interrupt
,因为是按键Key2,则这里中断线为EXTI_Line2,如果按键是5-9则这里就要统一写成EXTI9_5_IRQn。
**************************************************************************************************************************************************************************************
(6)中断处理函数
void EXTI2_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line2) != RESET) //判断按键是否按下
{
/*LED反转*/
GPIO_WriteBit(GPIOD, GPIO_Pin_6,
(BitAction)((1-GPIO_ReadOutputDataBit(GPIOD, GPIO_Pin_6))));
EXTI_ClearITPendingBit(EXTI_Line2); //清除中断标志位
}
}
****************************************************************************************************************************************************************************************
说明:这里的中断处理函数我们通常最好是放在 stm32f10x_it.c这个文件,这是官方提供的一个用来放所有外部中断处理函数的文件,当主程序在执行程序时,如果发生中断,cpu会立即跳到这里来执行中断处理函数,这里因为只有按键中断,还体现不出这样做的好处,如果是一个大工程,用到多个中断时,把中断函数统一放在这个文件中的话,可以大大优化代码。
***************************************************************************************************************************************************************************************