中断简介
中断定义
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+1
Counter 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
回调函数处理接收的数据