STM32-中断系统
STM32中断系统概述
-
中断处理过程
-
进入中断 :处理器自动保存现场到堆栈里 ---> 入栈结束,ISR寄存器开始执行指令 ---> 晚到的中断会重新取ISR
-
退出中断 :恢复现场 ---> 继续执行被中断打断的指令
-
NVIC主要功能 ---> 内嵌向量中断控制器( Nested Vectored Interrupt Controller (NVIC))
-
中断管理(外部中断使能或禁止,可设置挂起或者清除状态)
-
支持异常及中断向量化处理
-
支持嵌套处理
外部中断控制器EXTI
-
EXTI控制器的主要特性如下:
-
每个中断/事件都有独立的触发和屏蔽
-
每个中断线都有专用的状态位
-
支持多达19个中断/事件请求
-
检测脉冲宽度低于APB2时种宽度的外部信号。参见数据手册中电气特性部分的相关参数
-
框图(红蓝虚线为输入线,蓝色为产生中断,红色为产生事件输出脉冲信号)
-
STM32F103 的触发来源有两种(标号 1 的或门输入):
-
软件触发中断
-
外部边沿触发中断
2. STM32F103 的输出结果有两种(绿色和蓝色区域):
-
触发外部中断
-
产生事件脉冲
3. 结合上图作者来讲解一下:
-
当边沿检测电路检测到引脚上产生用户设置的触发沿时边沿检测电路会输出高电平给标号 1 部分,由于 1 是或门所以输入有一个是 1 输出就是 1, 此时 1 号或门的输出给请求中断挂起寄存器,并让该寄存器对应中断线挂起位为 1,如果此时中断屏蔽寄存器使能,即该中断线中断使能位为 1 时, 2 号与门输出 1,并传给 NVIC,如果此时 NVIC 使能了该中断线中断,则外部中断发生,外部中断服务函数得以执行。 同时,如果事件屏蔽寄存器中的对应位设置为 1,即开放来自该中断线的事件时, 3 号与门输出 1,进而使得脉冲发生器产生脉冲给对应外设,对应外设在收到脉冲后执行相应的联动触发动作,如触发 ADC 采集。
-
同理如果设置软件中断寄存器相应位为 1, 即通过软件产生外部中断时也会触发上面所述动作
-
中断屏蔽寄存器(EXTI_IMR)
-
当对应中断屏蔽位为 1 时,如果此时挂起寄存器对应位也为 1,则产生 NVIC 中断
-
事件屏蔽寄存器(EXTI_EMR)
-
当事件屏蔽寄存器对应位为 1 时, 一旦有触发信号产生,就会生成事件脉冲给其他外设
-
上升沿触发选择寄存器(EXTI_RTSR)
-
设置触发外部中断/事件的信号为上升沿触发。 上升下降沿寄存器可以同时配合使用来产生上升下降沿触发
-
下降沿触发选择寄存器(EXTI_FTSR)
-
设置触发外部中断/事件的信号为下降沿触发。上升下降沿寄存器可以同时配合使用来产生上升下降沿触发
-
挂起寄存器(EXTI_PR)
-
当外部信号/或软件产生了触发请求(即 1 号或门的输出为 1),则挂起寄存器对应位被设置为 1,通过写 1 清零
-
外部中断配置寄存器 1-4(AFIO_EXTICR1-4)
-
这里只列出 AFIO_EXTICR2,这样的 32 位寄存器一种有 4 组,每组用于设置 4 个外部中断,该寄存器用于指定外部中断的输入信号来自于那组 GPIO 的引脚,目的是将外部中断线和某个对应引脚连接在一起
按键中断实例
-
按键中断编程步骤分析
-
使能相应的时钟
-
配置GPIO管脚为中断功能
-
设置中断优先级
-
使能相应的中断
-
实现中断服务程序
-
中断配置程序
-
1 void MX_GPIO_Init(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStruct = {0}; 4 5 /* GPIO Ports Clock Enable */ 6 __HAL_RCC_GPIOA_CLK_ENABLE(); 7 8 /*Configure GPIO pin : PA8 */ 9 GPIO_InitStruct.Pin = GPIO_PIN_8; 10 GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;//上升沿触发 11 GPIO_InitStruct.Pull = GPIO_NOPULL; 12 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 13 14 /* EXTI interrupt init*/ 15 HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); 16 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); 17 }
串口中断实例-
串口中断编程步骤分析
-
使能相应的时钟
-
配置GPIO管脚为串口功能
-
设置中断优先级
-
使能相应的中断
-
实现中断服务程序
2. 程序- 更改printf函数为串口传输使用
int fputc(int ch, FILE *fp)//更改printf函数,使之可为串口传输使用 {
while(!(USART1->SR & (1<<7)));//判断发送寄存器是否为空 USART1->DR = ch;//若不为空,则将数据传输到数据发送寄存器 return ch;} * 串口发送中断程序 HAL_UART_Transmit_IT(&huart1, "Transmit INIT\n", 14);//main.c文件中编写//调用此函数发送字符串,发送完成产生串口发送完成中断,并调用HAL_UART_TxCpltCallback函数 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)//usart.c文件中编写 { if(huart->Instance == USART1) { printf("uart transmit end\n");//串口发送完成 }} * 串口接收中断程序 uint8_t RX[10] = {0};//定义接收数组HAL_UART_Receive_IT(&huart1, RX, 1);//接收一个字符数据,编写在main.c文件extern uint8_t RX[10];//声明外部变量,编写在usart.c文件 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//调用接收回调函数{ if(huart->Instance == USART1) { printf("RX: %x\n",RX[0]);//打印接收到的字符
HAL_UART_Receive_IT(&huart1, RX, 1);
}}
-