中断简介
中断定义
CPU执行程序中,由于发生了某种随机的事件(外部或内部),引起CPU暂时 中断正在运行的程序,转去执行一段特殊的服务程序(称为中断服务程序或 中断处理程序),以处理该事件,该事件处理完后又返回被中断的程序继续 执行,这一过程称为中断
对于单片机来说
- 中断事件发生
- 产生中断信号
- 单片机接收到中断信号,停止执行当前函数,跳转至中断处理函数
- 执行完中断处理函数后,单片机自动跳转回主函数执行被中断处
NVIC
NVIC是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。同时掌控中断优先级和中断向量表。
中断流程

- 请求挂起寄存器的改变由外设导致
- 中断信号传递至
NVIC,然后NVIC查找对应中断向量,执行中断处理函数 - 另外中断处理函数都需要去清除请求挂起寄存器对应位,避免中断处理函数被重复调用
HAL库的中断处理及回调函数实现流程
首先是外设发出中断请求信号,NVIC接收到后会根据中断向量表查询对应中断处理函数的入口,在HAL中是对应外设的外设number_IRQHandler,然后再进入HAL库统一的外设中断处理函数HAL_外设_IRQHandler,再调用对应的回调函数

NVIC嵌套向量中断控制器
NVIC会一直检测某一个中断线是否处于激活状态,当中断处理函数运行完成后,需要在中断处理函数中将请求挂起寄存器对应的位清除为0,避免NVIC一直检测到1,一直重复执行中断处理函数,而这一部分代码,在HAL库写的总IRQHandler中已经完成。
另外,NVIC对于中断还有中断优先级的设置,stm32f103c8t6中断优先级由NVIC的优先级寄存器里的4位决定。中断优先级分为抢占优先级和响应优先级(它们一起用这4位)
- 抢占优先级的级别越高,越能够抢占中断通道,优先执行中断 2. 响应优先级的级别越高,可以优先排队。
- 中断的优先级,都是数字越小,优先级越高

EXTI外部中断
EXTI外部中断实现
EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所不同。我们的主要关注点是中断。

- 边沿检测电路用来检测输入的电平信号的高低电平的转换,同时会根据 上升沿/下降沿触发选择寄存器来决定是否向后产生高电平信号
- 软件中断事件寄存器使用软件来模拟产生一个中断
- 请求挂起寄存器接收到高电平后会将对应通道的位置1(例如EXTI_9产生高电平进入请求挂起寄存器,则该寄存器会将第9位置1)
- 最后上面的线路就会进入
NVIC(嵌套向量中断控制器) - 下面的线路,脉冲发生器作为事件信号送到对应外设,这个脉冲信号可以给其他外设电路使用,比如定时器TIM、模拟数字转换器ADC等等,这样的脉冲信号一般用来触发TIM或者ADC开始转换
产生中断线路目的是把输入信号输入到
NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。 产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
调用流程
以EXTI1为例,下降沿触发,当出现下降沿时,就会触发EXTI5的外部中断,进入EXTI9_5_IRQHandler,在EXTI9_5_IRQHandler中调用HAL_GPIO_EXTI_IRQHandler函数统一处理外部中断,在该函数中对挂起寄存器进行清0操作,并调用HAL_GPIO_EXTI_Callback中断回调函数
按键实现外部中断控制小灯亮灭
Cube配置

EXTI配置
打开中断

配置的是下降沿触发,检测下降沿,上拉模式

配置参数解释
- 上升沿触发:指的是当引脚电平从低电平(0)转变为高电平(1)时,触发事件
- 下降沿触发:指的是当引脚电平从高电平(1)转变为低电平(0)时,触发事件
- 双边沿触发:指的是当引脚的电平发生任何变化(即从低电平到高电平或从高电平到低电平)时,都会触发事件
- 上拉:指使引脚在未连接(悬空)时默认为 高电平(1)
- 下拉:指使引脚在未连接(悬空)时默认为 低电平(0)
GPIO配置

推挽模式,初始输出为Low低电平
按键消抖
方式1
|
|
方式2
|
|
代码实现
|
|
TIM定时器定时中断
在f103c8t6中,TIM1是高级定时器,TIM2,TIM3,TIM4是通用计时器
下面例子中配置的是TIM1,实现每秒翻转1次小灯亮灭
调用流程
触发更新中断后进入更新中断服务函数TIM1_UP_IRQHandler,其中调用HAL_TIM_IRQHandler,在该函数中调用了HAL_TIM_PeriodElapsedCallback回调函数
CubeMX参数配置
使用内部时钟模式

参数配置如下,实现1s触发一次定时器更新中断

Prescaker:预分频,实际分频数是number+1Counter Mode:计数模式设置Counter Period:自动重装载计数器计数值Internal Clock Division:内部时钟预分频Repetiton Counter:重复计数器 (RCR -8 bits),属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出 PWM 的个数,与内部时钟模式无关auto-reload preload:是否开启影子寄存器模式
还需要开启定时器更新中断

代码实现
用的PA2作GPIO输出
|
|
USART中断
USART的轮询模式会阻塞程序运行,浪费CPU资源
轮询模式
CPU不断查询发送数据寄存器或者接受数据寄存器导致程序的阻塞
发送
在UART底层有发送移位寄存器和发送数据寄存器,发送数据时,需要CPU将发送数据寄存器的数据移动至发送移位寄存器,然后UART按照指定的波特率发送数据,CPU则不断查询数据发送寄存器是否空,如果空则需要移动数据进来

接收
在UART底层有接收移位寄存器和接收数据寄存器,接收数据时,UART按照指定的波特率接收数据至接收移位寄存器,然后数据会存储在接收数据寄存器,CPU则不断查询数据接收寄存器是否有数据,如果有数据,CPU会把寄存器的数据移动至我们用来接收数据的变量的内存里
当HAL_UART_Receive执行完成,我们就可以知道数据接收完成

中断模式
底层中断实现数据每传送一字节,召回CPU继续运输数据,不需要我们考虑,HAL库底层已经帮我们实现
上层中断实现数据接收完成后的数据处理,通过中断回调函数实现,需要我们自己设计
发送
CPU将数据送入 发送数据寄存器,然后就去执行其他代码,当发送移位寄存器的数据发送后,发送数据寄存器空,会触发发送数据寄存器空中断,CPU再次将数据送入 发送数据寄存器,然后又去执行其他代码,所有数据发送完成后会触发 传送完成中断,调用HAL_UART_TxCpltCallback中断回调函数

接收
CPU在处理其他代码,接收移位寄存器将一帧数据移动至 接受数据寄存器后,会触发 接收数据寄存器非空中断,CPU会回来将 接收数据寄存器 的数据移动至我们用来接收数据的变量的内存里,然后又去执行其他代码,所有数据完成后会调用_HAL_UART_RxCpltCallback_中断回调函数处理接收的数据
而执行HAL_UART_Receive_IT后,我们不能直接对数据继续处理,数据还没接收完成,因为CPU不会进入阻塞态,会去执行其他代码,需要通过HAL_UART_RxCpltCallback回调函数处理接收的数据