stm32中断的实际操作
0 2023-01-20

这一部分我们将使用按键作为触发源,在产生中断时,实现控制LED灯的亮灭状态切换。

在具体应用前,我们还需先认识认识EXTI。

EXTI

全称为External interrupt/event controller,即外部中断/事件控制器。其管理了20个中断/事件线,每条线都有对应的一个边沿检测器,用于输入信号上升沿和下降沿的检测。如图6-1为stm32参考手册里的EXTI框图。

stm32中断初识与实践(下)图6-1

图中有两条走向的线路,蓝色线路用于产生中断,绿色线路产生事件。我们从右往左看图。

查阅按键原理图可知,按键按下时,电平状态由低变高,会在输入线呈现出一个上升沿信号,这个信号到达边沿检测电路后,会被上升沿触发选择寄存器(EXTI_RTSR)检测并触发,输出有效信号1给编号3电路,否则输出无效信号0。如果电平由高变低,则会被下降沿触发选择寄存器(EXTI_FTSR)检测触发。

触发的信号到达编号3电路,这是一个或门电路,它的输入信号除了来源于边沿检测电路,还有来自软件中断事件寄存器(EXTI_SWIER)。无论是来自EXTI_SWIER或边沿检测电路的信号,只要有一个是有效信号1,那么便可以输出有效信号1给编号3电路。编号3电路之后,分为两条线,一条产生中断,一条产生事件。

信号沿着蓝色线路产生中断,编号3输出信号到编号4。编号4是一个与门电路,它的另一个信号来源是中断屏蔽寄存器(EXTI_IMR)。众所周知,与门电路要求输入信号都为1才能输出1,换言之,如果EXTI_IMR置为0,那么编号4电路输出的信号都为0,只有EXTI_IMR置1时,编号4输出的信号才由编号3决定。这样一来我们可以通过EXTI_IMR来控制是否产生中断。随后,编号4电路输出的信号会被保存到挂起寄存器(EXTI_PR)内。最后将EXTI_PR里的值输出到NVIC,实现中断控制。

信号沿着绿色线路产生事件,最终会输出一个脉冲信号。编号3输出信号到编号5,编号5也是一个与门电路,信号来源于编号3电路和事件屏蔽寄存器(EXTI_EMR)。和编号4的与门电路一样,我们可以通过EXTI_EMR来控制是否产生事件。当编号5输出有效信号1时会在脉冲发生器(Pulse generator)输出一个脉冲信号(无效信号不会输出脉冲)。这个脉冲信号可以给其他外设电路使用,如TIM、ADC等等,一般用来触发TIM或ADC开始转换。

EXTI的中断/事件线

EXTI有20条中断/事件线,其中有16条用于GPIO线上的外部中断/事件,占用EXTI0~EXTI15,其他4条用于特定外设的外部中断/事件。如图6-2。

stm32中断初识与实践(下)图6-2

可以通过操作AFIO的四个外部中断配置寄存器(AFIO_EXTICR1~AFIO_EXTICR4)的EXTIx[3:0]位选择配置PAx、PBx、PCx...PGx等引脚。如图6-3为AFIO_EXTICR1寄存器描述。

stm32中断初识与实践(下)图6-3

EXTI_InitTypeDef

EXTI_InitTypeDef是EXTI初始化结构体,其定义在stm32f10x.h文件中,如图6-4所示。

stm32中断初识与实践(下)图6-4

有四个结构体成员,

•  EXTI_Line:中断/事件线,可选择EXTI0~EXTI19,如图6-2所示;
•  EXTI_Mode:EXTI模式,可设置产生中断(EXTI_Mode_Interrupt)或产生事件(EXTI_Mode_Event);
•  EXTI_Trigger:EXTI边沿触发,可选择上升沿触发(EXTI_Trigger_Rising)、下降沿触发(EXTI_Trigger_Falling)或者上升沿下降沿都触发(EXTI_Trigger_Rising_Falling);
•  EXTI_LineCmd:使能(ENABLE)/失能(DISABLE)EXTI线。

开始实验

按键按下时,产生电平变化,EXTI检测到上升沿信号,触发中断,执行中断服务函数,实现LED灯的亮灭切换。

简要分析下编程要点:

•  初始化产生中断的外设(GPIO);
•  配置NVIC;
•  初始化EXTI;
•  中断服务函数;
•  main函数

NVIC配置

我们先对NVIC进行配置,将其封装为函数NVIC_Configuration(),供后续调用。

/**
* @brief NVIC配置
* @param 无
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 配置优先级分组

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 配置按键中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断寄存器

NVIC_Init(&NVIC_InitStructure);
}
NVIC配置部分,需要配置优先级分组、中断源、抢占优先级、子优先级以及使能中断寄存器等。关于优先级分组配置以及NVIC_InitTypeDef结构体分析,已在里详细说明,读者可点击进入阅读。

EXTI中断配置

/**
* @brief EXTI按键中断配置
* @param 无
* @retval 无
*/
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;

/* 调用函数配置NVIC */
NVIC_Configuration();

/* 初始化GPIO */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* 初始化EXTI */
// 配置中断线的输入源
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 配置中断线为EXTI0
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 配置为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;// 上升沿触发中断
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能中断
EXTI_Init(&EXTI_InitStructure);
}
这个配置函数里用到了GPIO和EXTI两个初始化结构体,对其分别进行初始化配置,同时调用NVIC_Configuration()函数配置NVIC。

其中,

•  GPIO_EXTILineConfig()固件函数是对AFIO_EXTICR1的操作,所以我们需要开启AFIO时钟;
•  需要把GPIO配置为输入模式(浮空输入),由外部电路决定引脚状态;
•  通过查阅按键原理图可得,按键引脚为PA0,可得GPIO端口源和引脚源,并将其中断线配置为EXTI0;
•  由按键原理图可得,按键按下时为高电平,所以使用上升沿触发中断。

中断服务函数

里已经说明中断服务函数名应在启动文件里找到,并统一写在stm32f10x_it.c文件中。

/**
* @brief EXTI0线中断服务函数
* @param 无
* @retval 无
*/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET) // 确保产生了EXTI0线中断
{
LED_TOGGLE; // LED灯状态切换
EXTI_ClearITPendingBit(EXTI_Line0);// 清除中断标志位
}
}
需要先确保是否产生了中断,这一步我们直接调用stm32f10x_exti.c文件里的库函数EXTI_GetITStatus(),通过其返回值判断。EXTI_GetITStatus()函数操作的是中断屏蔽寄存器(EXTI_IMR)和挂起寄存器(EXTI_PR),通过两个寄存器的值判断是否产生中断,。由图6-1功能框图可得,如果相应线的EXTI_IMR和EXTI_PR都置1,则返回“SET”,即产生中断。具体的源码实现可查看3.5版本的stm32f10x固件库。

LED_TOGGLE是一个宏,在宏里实现LED状态切换。具体的实现在文章里已经有过说明,读者可移步阅读。

中断服务实现后,需要清除该中断线的中断标志位,以免下次程序判断失误。

main函数

int main(void)
{
LED_GPIO_Config(); // LED端口初始化
EXTI_Key_Config(); // EXTI按键中断配置
while(1){} // 等待中断产生
}
当按键按下时,即进入中断,执行中断服务函数,完成实验。 

声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 相关技术文库
  • 单片机
  • 嵌入式
  • MCU
  • STM
  • 单片机内几种数据存储手段

    单片机就是个小计算机,跳蚤虽小不但五脏惧全,有时还跳得很高呢!自然,大计算机少不得的数据存储系统,小不点的单片机一样有,而且往往和CPU集成在一起,更加显得小巧

    昨天
  • 如何保证MCU上电后RAM的初始值唯一

    由于工作的原因,笔者经常接到工程师询问MCU内部的RAM上电之后的初始值到底是什么,有什么特性和规律。今天笔者就以设计过程中遇到的几个问题与大家做一个交流。首先

    昨天
  • P51XAG37单片机和液晶显示器的接口设计

    0引言P51XA是PHILIPS公司的一种16位单片机,可管理的存储器空间大,运行速度快,支持实时多任务系统的增强了实现高级语言的支持,可以运用在需要复杂、高速

    昨天
  • 基于C8051F系列单片机的数据采集系统USB接口设计

    1引言随着现代工业生产和科学研究对数据采集系统的要求日益提高,传输速度、纠错能力和操作安装的简易性是人们进行采集数据时一直关注的问题,这使得数据通讯技术不可避免

    前天
  • 硬中断和软中断的区别

    概述从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器。如果中断的线是激活的,中断控制器就把电信号发送给处

    前天
  • STM32时钟模型和内部时钟树

    时序在数字电路中的作用,就像通信中用到的载波,载波并不起眼,但是很重要。时钟也一样,现象上只是某种频率波峰波谷跳动,一成不变。但是有了它,就像人类的历史有了时间

    前天
  • 基于LPC54101和SDK实现串口DMA接收超时的机制

    在MCU的应用中,经常需要通过串口进行不定长数据包的传输。发送方很简单,不需特别的考虑,而接收方则需要能够侦测到数据包的结束。接收方的简单做法是结合串口的IDL

    前天
  • STM32基础精华及注意事项

    一、背景如果你正为项目的处理器而进行艰难的选择:一方面抱怨16位单片机有限的指令和性能,另一方面又抱怨32位处理器的高成本和高功耗,那么,基于ARMCortex

    前天
  • 如何采用FIFO存储器实现A/D转换器与ARM的接口设计

    在高频超声波数据采集系统中,很多高速A/D转换器往往不能直接与处理器相连接,这时就需要使用FIFO在处理器与A/D转换器之间架一座桥梁,FIFO的先入先出特性可

    02-06
  • 超声波无损检测系统的A/D与ARM接口设计

    在高频超声波数据采集系统中,很多高速A/D转换器往往不能直接与处理器相连接,这时就需要使用FIFO在处理器与A/D转换器之间架一座桥梁,FIFO的先入先出特性可

    02-06
  • 单片机定时器使用过程中常见的两种问题

    在单片机的学习过程中,单片机定时器的合理设置和应用是非常关键的一步,也是刚开始接触单片机知识的新人工程师们比较容易出错误的一个环节之一。在今天的文章中,我们为大

    02-03
  • 51单片机定时器的寄存器

    标准的51单片机内部有T0和T1这两个定时器,T就是Timer的缩写,现在很多51系列单片机还会增加额外的定时器,在这里我们先讲定时器0和1。前边提到过,对于单

    02-03
下载排行榜
更多
广告