当前位置:首页 >> 信息与通信 >>

STM32学习笔记(2):外部中断的使用


中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在 C51 单片机时代,一共只 有 5 个中断, 其中 2 个外部中断, 个定时/计数器中断和一个串口中断, 2 但是在 STM32 中, 中断数量大大增加,而且中断的设置也更加复杂。今天就将来探讨一下关于 STM32 中的中 断系统。

1 基本概念
ARM Coetex-M3 内核共支持 256

个中断,其中 16 个内部中断,240 个外部中断和可编 程的 256 级中断优先级的设置。STM32 目前支持的中断共 84 个(16 个内部+68 个外部), 还有 16 级可编程的中断优先级的设置,仅使用中断优先级设置 8bit 中的高 4 位。 STM32 可支持 68 个中断通道,已经固定分配给相应的外部设备,每个中断通道都具备 自己的中断优先级控制字节 PRI_n(8 位,但是 STM32 中只使用 4 位,高 4 位有效),每 4 个 通道的 8 位中断优先级控制字构成一个 32 位的优先级寄存器。68 个通道的优先级控制字至 少构成 17 个 32 位的优先级寄存器。 4bit 的中断优先级可以分成 2 组,从高位看,前面定义的是抢占式优先级,后面是响应 优先级。按照这种分组,4bit 一共可以分成 5 组 第 0 组:所有 4bit 用于指定响应优先级; 第 1 组:最高 1 位用于指定抢占式优先级,后面 3 位用于指定响应优先级; 第 2 组:最高 2 位用于指定抢占式优先级,后面 2 位用于指定响应优先级; 第 3 组:最高 3 位用于指定抢占式优先级,后面 1 位用于指定响应优先级; 第 4 组:所有 4 位用于指定抢占式优先级。 所谓抢占式优先级和响应优先级,他们之间的关系是:具有高抢占式优先级的中断可 以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套。 当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来 后, 如果正在处理另一个中断, 这个后到来的中断就要等到前一个中断处理完之后才能被处 理。 如果这两个中断同时到达, 则中断控制器根据他们的响应优先级高低来决定先处理哪一 个; 如果他们的抢占式优先级和响应优先级都相等, 则根据他们在中断表中的排位顺序决定 先处理哪一个。每一个中断源都必须定义 2 个优先级。 有几点需要注意的是: 1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围, 将可能得到意想不到的结果; 2)抢占式优先级别相同的中断源之间没有嵌套关系; 3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占 式优先级别,则可以为这个中断源指定任意有效的响应优先级别。

2 GPIO 外部中断
STM32 中,每一个 GPIO 都可以触发一个外部中断,但是,GPIO 的中断是以组位一个 单位的,同组间的外部中断同一时间只能使用一个。比如说,PA0,PB0,PC0,PD0,PE0, PF0,PG0 这些为 1 组,如果我们使用 PA0 作为外部中断源,那么别的就不能够再使用了, 在此情况下,我们智能使用类似于 PB1,PC2 这种末端序号不同的外部中断源。每一组使用

一个中断标志 EXTIx。EXTI0 – EXTI4 这 5 个外部中断有着自己的单独的中断响应函数, EXTI5-9 共用一个中断响应函数,EXTI10-15 共用一个中断响应函数。 对于中断的控制,STM32 有一个专用的管理机构:NVIC。对于 NVIC 的详细解释,可 以参考《ARM Cortex-M3 权威指南》,Joseph Yiu 著,宋岩译,北京航空航天大学出版社出 版,第 8 章 NVIC 与中断控制。中断的使能,挂起,优先级,活动等等部都是 NVIC 在管理 的。因为我学习 STM32 重点在于如何开发程序,所以内部的一些东西,在此我就不详细说 明了,有感兴趣的可以参看上面提到的那本数。

3 程序开发
其实上面那些基本概念和知识只是对 STM32 的中断系统有一个大概的认识,用程序说 话将会更能够加深如何使用中断。使用外部中断的基本步骤如下: 1. 2. 3. 4. 5. 设置好相应的时钟; 设置相应的中断; IO 口初始化; 把相应的 IO 口设置为中断线路(要在设置外部中断之前)并初始化; 在选择的中断通道的响应函数中中断函数。

由于我用的奋斗开发板没有引出相应的芯片引脚,所以只能用按键来触发相应的中断。 根据原理图,K1/K2/K3 连接的是 PC5/PC2/PC3,因此我将用 EXTI5/EXTI2/EXTI3 三个外部 中断。PB5/PD6/PD3 分别连接了三个 LED 灯。中断的效果是按下按键,相应的 LED 灯将会 被点亮。

1.

设置相应的时钟

首先需要打开 GPIOB、GPIOC 和 GPIOE(因为按键另外一端连接的是 PE 口)。然后 由于是要用于触发中断,所以还需要打开 GPIO 复用的时钟。相应的函数在 GPIO 的学习笔 记中有了详细了解释。详细代码如下: void RCC_cfg() { //打开 PE PD PC PB 端口时钟,并且打开复用时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); } 设置相应的时钟所需要的 RCC 函数在 stm32f10x_rcc.c 中,所以要在工程中添加此文件。

2.

设置好相应的中断

设置相应的中断实际上就是设置 NVIC,在 STM32 的固件库中有一个结构体 NVIC_InitTypeDef,里面有相应的标志位设置,然后再用 NVIC_Init()函数进行初始化。详 细代码如下:

void NVIC_cfg() { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择中断分组 2

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel;

//选择中断通道 2

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置 为0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //响应式中断优先级设置为 0 //使能中断

NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel; 为1

//选择中断通道 3

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占式中断优先级设置 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应式中断优先级设置为 1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //使能中断

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //选择中断通道 5 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占式中断优先级设置 为2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //响应式中断优先级设置为 2 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } //使能中断

由于有 3 个中断,因此根据前文所述,需要有 3 个 bit 来指定抢占优先级,所以选择第 2 组。又由于 EXTI5-9 共用一个中断响应函数,所以 EXTI5 选择的中断通道是 EXTI9_5_IRQChannel,详细信息可以在头文件中查询得到。用到的 NVIC 相关的库函数在 stm32f10x_nivc.c 中,需要将此文件复制并添加到工程中。具体位置可以查看关于 GPIO 的 笔记。这段代码编译起来没有任何问题,但是在链接的时候就会报错,需要把 STM32F10xR.LIB 加入工程中,具体位置在…\Keil\ARM\RV31\LIB\ST\STM32F10xR.LIB。

3.

IO 口初始化

void IO_cfg() { GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOE,&GPIO_InitStructure); GPIO_ResetBits(GPIOE,GPIO_Pin_2);

//选择引脚 2 //输出频率最大 50MHz //带上拉电阻输出

//将 PE.2 引脚设置为低电平输出

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5; //选择引脚 2 3 5 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择输入模式为浮空输 入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStructure); //输出频率最大 50MHz //设置 PC.2/PC.3/PC.5

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOD,&GPIO_InitStructure);

//选择引脚 3 6 //输出频率最大 50MHz //带上拉电阻输出

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB,&GPIO_InitStructure); }

//选择引脚 5 //输出频率最大 50MHz //带上拉电阻输出

其中连接外部中断的引脚需要设置为输入状态,而连接 LED 的引脚需要设置为输出状 态, 初始化 PE.2 是为了使得按键的另外一端输出低电平。 GPIO 中的函数在 stm32f10x_gpio.c 中。

4.

把相应的 IO 口设置为中断线路

由于 GPIO 并不是专用的中断引脚,因此在用 GPIO 来触发外部中断的时候需要设置将 GPIO 相应的引脚和中断线连接起来,具体代码如下: void EXTI_cfg() { EXTI_InitTypeDef EXTI_InitStructure; //清空中断标志 EXTI_ClearITPendingBit(EXTI_Line2); EXTI_ClearITPendingBit(EXTI_Line3); EXTI_ClearITPendingBit(EXTI_Line5);

//选择中断管脚 PC.2 PC.3 PC.5 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2); GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource3); GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5);

EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line5; //选择中断线路 235 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断请求,非事件请求 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //设置中断触发方式为 上下降沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); } EXTI_cfg 中需要调用到的函数都在 stm32f10x_exti.c。 //外部中断使能

5.

写中断响应函数

STM32 不像 C51 单片机那样,可以用过 interrupt 关键字来定义中断响应函数,STM32 的中断响应函数接口存在中断向量表中,是由启动代码给出的。默认的中断响应函数在 stm32f10x_it.c 中。因此我们需要把这个文件加入到工程中来。 在这个文件中,我们发现,很多函数都是只有一个函数名,并没有函数体。我们找到 EXTI2_IRQHandler()这个函数, 这就是 EXTI2 中断响应的函数。 我的目标是将 LED 灯点亮, 所以函数体其实很简单: void EXTI2_IRQHandler(void) { //点亮 LED 灯 GPIO_SetBits(GPIOD,GPIO_Pin_6); //清空中断标志位,防止持续进入中断

EXTI_ClearITPendingBit(EXTI_Line2); }

void EXTI3_IRQHandler(void) { GPIO_SetBits(GPIOD,GPIO_Pin_3); EXTI_ClearITPendingBit(EXTI_Line3); }

void EXTI9_5_IRQHandler(void) { GPIO_SetBits(GPIOB,GPIO_Pin_5);

EXTI_ClearITPendingBit(EXTI_Line5); } 由于 EXTI5-9 是共用一个中断响应函数,因此所有的 EXTI5 – EXTI9 的响应函数都写 在这个里面。

6.

写主函数

#include "stm32f10x_lib.h"

void RCC_cfg(); void IO_cfg(); void EXTI_cfg(); void NVIC_cfg();

int main() { RCC_cfg(); IO_cfg(); NVIC_cfg(); EXTI_cfg();

while(1); }

main 函数前是函数声明,main 函数函数体中都是调用初始化配置函数,然后进入死循 环,等待中断响应。

由于文中牵涉到很多库函数,我们可以通过查找库函数说明文档来了解相应的函数有 些什么作用, 《ARM?-based 32-bit MCU STM32F101xx and STM32F103xx firmware library》 在 中。网上也有中文版的说明文档可供参考。


相关文章:
STM32学习笔记(2):外部中断的使用
STM32学习笔记(2):外部中断的使用_信息与通信_工程科技_专业资料。STM32学习笔记(2):外部中断的使用中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在 C51 ...
S.D.Lu的STM32学习笔记(7)外部中断实验
S.D.Lu 的 STM32 学习笔记(7)外部中断实验概述:中断的应用是单片机初学者...简化后得到下图: -2- 所以,在外部中断控制器部分我们只需要操作 4 个寄存器...
外部中断学习笔记
外部中断学习笔记_电子/电路_工程科技_专业资料。资料来源:http://blog.csdn....2)开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。 STM32 的 IO 口与...
STM32外部中断详解
、 GPIO 外部中断 STM32 中,每一个 GPIO 都可以触发一个外部中断,但是,...相应的 函数在 GPIO 的学习笔记中有了详细了解释。详细代码如下: void RCC_...
STM32外部中断配置例程
STM32外部中断配置例程_电子/电路_工程科技_专业资料。本章简介stm32在使用外部...STM32学习笔记(2):外部... 7页 1下载券 喜欢此文档的还喜欢 STM...
STM32外部中断总结
STM32学习笔记:外部中断... 8页 2下载券 stm32的外部中断 3页 免费 Stm32外部中断 4页 免费 关于STM32的配置总结 1页 免费 stm32外部中断的使用 1页 免费...
stm32外部中断的使用
关键词:STM32外部中断stm32外部中断的中断使用 1/2 相关文档推荐 ...2页 免费 STM32学习笔记:外部中断的... 8页 5财富值 STM32学习笔记(2):外部...
STM32外部中断
STM32外部中断_电子/电路_工程科技_专业资料。STM32外部中断详解,很详细STM32 外部中断一、基本概念 ARM Coetex-M3 内核共支持 256 个中断,其中 16 个内部中断...
STM32学习笔记--使用TIM5-TIM8中断
STM32学习笔记--使用TIM5-TIM8中断_信息与通信_工程科技_专业资料。这是本人学习...1/2 相关文档推荐 STM32时钟学习笔记 6页 免费 STM32学习笔记(2):外部......
STM32函数库之外部中断
新手入门使用 STM32 函数库之外部中断作者:佚名 来源:本站原创 点击数: 756 ...第步,配置IO及其功能, GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 得代码...
更多相关标签: