用STM32F103C8T6的中断原理点亮一个LED灯(标准库方式)【STM32开发板】
实验要求
用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。
关于中断
中断的定义及处理流程
计算机在执行程序过程中,当出现异常情况(断电等)或特殊请求(数据传输等)时,计算机暂停现行程序的运行,转向对这些异常情况或特殊请求进行处理,处理完毕后再返回到现行程序的中断处,继续执行原程序,这就是“中断”。中断是单片机实时处理内部或外部事件的一种机制。中断和异常其本质都是对主程序的“中断”。
中断处理流程:中断请求、中断响应、中断服务和中断返回。单重中断的处理流程如下。
多重中断的处理流程如下。
STM32的内部中断处理机制
STM32的外部中断 (EXTI)
STM32芯片之外的外设的中断(I/O端口)由EXTI和NVIC共同负责,即STM32的每一个GPIO引脚都可以配置成一个外部中断触发源。
EXTI(External interrupt/event controller,外部中断/事件控制器)支持19个外部中断/事件请求,每个中断/事件都有独立的触发和屏蔽设置,具有中断模式和事件模式两种设置模式。STM32 EXTI内部功能框图如下。
GPIO的中断是以组为单位的,同组的外部中断公用一条外部中断线。例如:PA0、PB0、PC0、PD0、PE0、PF0、PG0这些为一组,如果使用PA0作为外部中断源,那么PB0、PC0、PD0、PE0、PF0、PG0就不能同时再作为外部中断使用了,在此情况下,只能使用类似于PB1、PC2这种末端序号不同的外部中断源。
uEXTI0-EXTI4这5个外部中断有着各自独立的中断服务函数,如EXTI3的中断服务函数为void EXTI3_IRQHandler(void);uEXTI5-9共用一个中断服务函数void EXTI9_5_IRQHandler(void);uEXTI10-15共用一个中断服务函数void EXTI15_10_IRQHandler(void)。
标准库方式的开发环境搭建
STM32F1的Keil固件包的下载安装
在Keil官网 (www.keil.com) 上下载STM32F1的Keil固件包。具体过程是:进入Keil官网后点击 “Products”,点击 “ARM development tools”,进入ARM产品页面后点击 “Public Software Packs”,在 “MDK5 Software Packs” 下方找到Keil,接着在Keil下方找到 “STMicroelectronics STM32F1 Series Device Support”,即STM32F1的Keil固件包,点击“下载”。下载完成后打开该文件,安装固件包即可。
STM32F10x固件库的下载
在ST官网上下载STM32F10x的固件库。
下载完成并解压后的固件库包含_htmresc, Libraries, Project, Utilities四个文件夹以及使用手册和帮助文档。
开发环境的搭建与配置
选择STM32F103C8芯片建立工程后,在工程内Target下建立4个文件夹:User文件夹用于存放主程序 (main.c), 中断程序stm32f10x_it.c和系统文件system_stm32f10x.c; BSP文件夹用于存放用户编写的头文件等,如本次实验的LED.h, LED.c; Core文件夹用于存放core_cm3.c和启动文件startup_stm32f10x_hd.s; FWLib存放STM32标准外设库的src和inc两个文件夹,这两个文件夹下存有各种驱动文件。在该工程文件所在的文件夹下新建这四个文件夹,从STM32固件库复制上述文件及其头文件并粘贴到相应的文件夹。再在工程内将上述文件添加到相应的文件夹。
之后,打开Options,在Target选项页中设置晶振为8MHz,勾选 “Use MicroLIB”(使用Micro库);在Output选项页中勾选 “Create HEX File”(生成HEX文件);在C/C++选项页的Define中输入宏 “USE_STDPERIPH_DRIVER”,并将全部头文件所在的文件夹添加进搜索路径 (include path) 中;在Debug选项页中选择使用ST-Link调试器,点击设置 (settings),选择 “Erase Full Chip”,勾选 “Reset and Run”。这样开发环境的配置就算完成了。
项目编写
LED.h
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
void LED_Init(void); //函数声明
#endif
LED.c
#include "LED.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启GPIOB的时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //选择要使用的I/O引脚,此处选择PB5引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置引脚输出模式为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚的输出速度为50MHz
GPIO_Init(GPIOB,&GPIO_InitStructure); //调用初始化库函数初始化GPIOB端口
}
exti_key.h:
#ifndef __EXTI_KEY_H
#define __EXTI_KEY_H
#include "stm32f10x.h"
void EXTI_Key_Init(void);
#endif
exti_key.c:
#include "exti_key.h"
#include "misc.h"
void EXTI_Key_Init(void)
{
//GPIO初始化配置
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE); //开启I/O端口的时钟和复用时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//初始化NVIC,配置NVIC参数并使能
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_ClearITPendingBit(EXTI_Line3);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource3); //设置I/O引脚与中断线路的映射关系
//初始化EXTI,配置EXTI相关参数并使能
EXTI_InitStructure.EXTI_Line = EXTI_Line3;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
main.c
#include "stm32f10x.h"
#include "LED.h"
#include "exti_key.h"
//编写中断服务程序
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_5,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5))));
EXTI_ClearITPendingBit(EXTI_Line3);
}
}
int main(void)
{
LED_Init();
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
EXTI_Key_Init();
while(1)
{
}
}
STM32开发板实现
如下图所示,将STM32开发板插入面包板并与ST-link连接(相接的两接口应同名),分别用导线将开发板两侧的3.3V输出接至面包板两侧的正极槽、接地输入接至面包板两侧的负极槽。将一个LED接在开发板的B5接口上,具体做法是将正极(长管脚)接至正极槽,负极(短管脚)接至开发板B5接口所接在的一槽。再将一根导线的一端接至开发板A3接口所在的一槽。实验时将此导线的另一端接地,观察灯的亮灭变化;再将该导线的接地端拔出,观察灯的亮灭变化。
代码在Keil中编译完成后,点击“下载”,即可将代码载入STM32单片机中并开始运行。运行结果如下。
总结
本次实验学习了STM32的中断原理,并将其应用到点灯等简单操作中。