一、实验目的
1. 通过实验掌握中断式键盘控制与设计方法;
2. 熟悉编写中断服务程序;
3. 掌握中断系统相关知识,掌握外部中断应用方法和处理过程;
4. 掌握实验处理器中断处理的软件编程方法;
5. 从按键程序的设计对系统的编程进行深入了解,与单片机裸机编程进行区分;
6. 掌握基于固件库编程控制GPIO端口的输出,进而控制LED灯的显示状态。
二、实验内容
根据实验要求通过按键点亮LED灯,通过原理图了解硬件电路结构,实现初始化GPIO,并配置中断,编写中断处理程序,处理一个键盘中断,并在串口打印中断及按键显示信息。按键K1按下,触发外部中断,中断函数点亮LED灯,来实现对LED灯的控制以及硬件仿真软件的测试。
原理图如下:
三、实验器材(设备、元器件)
(一)装有Keil uVision5软件的计算机一台
(二)STM32f103VET6的开发板一块
四、实验步骤
1.原理说明
本实例需要创建两个文件“exti.c”和“exti.h”用来存放 EXTI驱动程序及相关宏定义,STM32的每个IO端口都可以作为中断输入,因此配置1/0端口,使之能响应中断。其编程要点和步骤如下:
查看STM32VET6开发板原理图,如下图为按键原理图,可以看见有key1,key2和key3三个按键,可以通过这三个按键来控制LED灯的亮灭。看到原理图的话,按下按钮PC5变为低电平,所以需要给PA5一个高电平,即内部上拉。利用STM32的外部中断输入功能,在外部设备触发中断信号时,中断模块会将中断信号转换为STM32的中断信号,从而触发LED灯亮灭。
2. STM32的中断控制器支持19个外部中断/事件请求
这⼗九个外部中断为:线0~15:对应外部IO口的输⼊中断;线16:连接到PVD输出;线17:连接到RTC时钟事件;线18:连接到USB唤醒事件。
配置使用时,需要先将IO口与相应中断线的映射关系建立,再对其进行使用。
3. 配置描述
(1)使能GPIO时钟,STM在使用任何外设之前,都需要使能其时钟,实验用到PB5 IO口,因此需要使能GPIOB时钟。首先我们要使用IO口作为中断输入,所以我们要使能相应IO口时钟,以及初始化相应IO空口为输入模式,我们使用按键为外部中断,此处应设置按键的IO口;
用GPIO_InitTypeDef和EXTI_InitTypeDef结构体定义两个用于GPIO和EXTI初始化配置的变量。初始化LED灯,按键的GPIO,作为中断/事件输入时需把GPIO配置为上拉输入模式,按下按钮PC5变为低电平,所以我们需要给PA5一个高电平,即内部上拉。推挽输出,频率为50MHz;
(2)将按键GPIO连接到EXTI源输入。由于GPIO并不是专用的中断引脚,因此在用GPIO来触发外部中断的时候需要设置将GPIO相应的引脚和中断线连接起来;
将函数GPIO端口与中断线映射起来;
(3)配置按键EXTI中断\事件线,配置中断产生的条件,PB5、PD6、PD3这三个口采用的是上拉输入模式,当有按键按下时,该IO口是低电平,所以要配置成下降沿触发,对应的就是GPIO mode;
(4)配置中断分组(NVIC),并使能中断。配置NVIC主要是配置一些中断源,中断的优先级(包括抢占优先级和相应优先级)还有设置使能中断(类似于C51中开启总开关);
系统运行开始的时候设置中断分组。确定组号,也就是确定抢占优先级和子优先级的分配位数。调用函数为NVIC_PriorityGroupConfig();设置所用到的中断的中断优先级别。对每个中断调用函数为NVIC_Init();
由于有三个中断,根据前面所说,需要有3个bit来指定抢占优先级,所以选择第二组。又由于EXTI5-9共用一个中断响应函数,所以EXTI5选择的中断通道是EXTI9_5_IRQn。
(5)编写EXTI的中断服务函数。在STM32的固件库中有一个结构体NVIC_InitTypeDef,里面有相应的标志位设置,然后再用NVIC_Init()函数进行初始化。设置中断优先级,可以根据系统需要设置不同优先级,确保系统稳定性。中断服务函数是用来设置产生中断后需要实现的功能。
(6)外部中断的中断标志位在发生中断后会由硬件置1,但是在执行完中断服务函数后硬件不会自动清零,所以需要我们手动在中断服务函数的最后标志位清零。
4. main( )函数
五、实验数据及结果分析
通过以上实验得出以下数据
1. 外部中断处理流程
2. main.c部分
#include "stm32f10x.h"
#include "key.h"
#include "exti0.h"
int main(void)
{
LED_inti(); //初始化与LED连接的硬件接口
exti0_Inti(); //初始化与按键连接的硬件接口
while(1);
}
3. extio.c部分
#include "stm32f10x.h"
#include "key.h"
void exti0_Inti(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU; //上拉输入
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct); //模式配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5); //把pc5挂到EXTI5总线上
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line5; //中断线5
EXTI_InitStruct.EXTI_LineCmd=ENABLE; //使能中断
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //EXTI为中断模式
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿中断
EXTI_Init(&EXTI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //配置中断优先组
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn; //选择EXTI9_5
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1; //中断优先级
NVIC_Init(&NVIC_InitStruct);
}
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line5)==SET) //确保是否产生中断
{
GPIO_SetBits(GPIOB, GPIO_Pin_5);
}
EXTI_ClearITPendingBit(EXTI_Line5); //清除中断标志位
}
4. extio.h部分
#ifndef __EXTI0_H
#define __EXTI0_H
void exti0_Inti(void);
void EXTI9_5_IRQHandler(void);
#endif
5.key.c部分
#include "stm32f10x.h"
void LED_inti(void) //灯引脚的配置函数,定义PC2
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
6. key.h部分
#ifndef __KEY_H
#define __KEY_H
void LED_inti(void);
#endif
7. 程序运行结果如下:
8. 软件仿真结果如下:
9. 硬件仿真结果如下:按键按下LED灯被点亮