你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32的中断系统

[复制链接]
STMCU小助手 发布时间:2022-1-17 21:33
STM32具有十分强大的中断系统,将中断分为了两个类型:内核异常和外部中断。并将所有中断通过一个表编排起来,下面是stm32中断向量表的部分内容:
% ]+ c3 e0 N; S$ @$ W& ~
1097927-20180814123940440-1953049551.png
: H( }: K6 n" j
1097927-20180814123948507-6094837.png

1 S9 o# i$ z1 ~4 O$ j
上图-3到6这个区域被标黑了,这个区域就是内核异常。内核异常不能够被打断,不能被设置优先级(也就是说优先级是凌驾于外部中断之上的)。常见的内核异常有以下几种:复位(reset),不可屏蔽中断(NMI),硬错误(Hardfault),其他的也可以在表上找到。
从第7个开始,后面所有的中断都是外部中断。外部中断是我们必须学习掌握的知识,包含线中断,定时器中断,IIC,SPI等所有的外设中断,可配置优先级。外部中断的优先级分为两种:抢占优先级和响应优先级。
什么是抢占优先级?
抢占优先级比较霸道,一言不和就插队。抢占优先级高的,能够打断优先级低的任务,等优先级较高的任务执行完毕后,再回来继续执行之前的任务。所以当存在多个抢占优先级不同的任务时,很有可能会产生任务的嵌套。
什么是响应优先级?
响应优先级则稍微谦逊些,比较有礼貌。响应优先级又被称为次优先级,若两个任务的抢占式优先级一样,那么响应优先级较高的任务则先执行,且在执行的同时不能被下一个响应优先级更高的任务打断,所以我说它比较有有礼貌。。
中断控制器(NVIC)
因为stm32的中断系统比较复杂,所以在内核中有一个专门管理中断的控制器:NVIC.
NVIC负责除了SYSTICK之外的所有中断的控制,十分重要!
在标准库中,提供了一套通过NVIC来控制中断的API,我们首先来看NVIC_Init()函数,这套函数首先要定义并填充一个结构体:NVIC_InitTypeDef 该结构体的定义如下:
NVIC_IRQChannel 需要配置的中断向量
NVIC_IRQChannelCmd 使能或者关闭相应中断向量的中断响应
NVIC_IRQChannelPreemptionPriority 配置相应中断向量的抢占优先级
NVIC_IRQChannelSubPriority 配置相应中断的响应优先级
结构体的四个成员都比较好理解,这里就不再累述了。
不过要注意一点的是,NVIC只可以配置16种中断向量的优先级,其抢占优先级和响应优先级都用一个4位的数字来决定。在库函数中,将其分为了5中不同的分配方式:
第0组:所有的4位都有来表示响应优先级,能够配置16种不同的响应优先级。中断优先级则都相同。
第1组:最高一位用来配置抢占优先级,剩余三位用来表示响应优先级。那么就有两种不同的抢占优先级(0和1)和8种不同的响应优先级(0~7)。
第2组:高两位用来配置抢占优先级,低位用来配置响应优先级。那么两种优先级就各有4种。
第3组:高三位用来配置抢占优先级,低位用来配置响应优先级。有8种抢占优先级和2种相应优先级。
第4组:所有位都用来配置抢占优先级,即有16种抢占优先级,没有响应属性。
这5种不同的分配方式,根据项目的实际需求来配置。
配置的API如下:
  1. NVIC_PriorityGroupConfig();
复制代码

* O! S# h" s% v9 ]) Z
其中括号内可以输入以下一个参数,代表不同的分配方式:
NVIC_PriorityGroup_0
NVIC_PriorityGroup_1
NVIC_PriorityGroup_2
NVIC_PriorityGroup_3
NVIC_PriorityGroup_4

" k* G' ~2 ?  [1 L6 l
EXTI外部中断
STM32的所有GPIO都引入到了EXTI外部中断线上,也就是说,所有的IO口经过配置后都能够触发中断。下图就是GPIO和EXTI的连接方式:
从上图我们可以看出,一共有16个中断线: EXTI0到EXTI15.
每个中断线都对应了从PAx到PGx一共7个GPIO。也就是说,在同一时刻每个中断线只能相应一个GPIO端口的中断,不能够同时相应所有端口的中断事件,但是可以分时复用,在程序执行过程中,这个不需要我们太多的去关心。我们关心最多的是中断触发的方式:
) x* G! F7 K" u$ o7 r8 e' w
1097927-20180814124003510-425482330.png
; N/ ?. Q, O7 _( i. X
在EXTI中,有三种触发中断的方式:上升沿触发,下降沿触发,双边沿触发。根据不同的电路,我们选择不同的触发方式,以确保中断能够被正常触发。

( y: c% X1 L' S4 \/ [2 O# f- L" J  D& u
实例
为了便于理解,这里我们将中断配置代码贴上来。
  1. void NVIC_Configuration(void)5 m- D2 k3 K' q& v
  2. {
    . U! R# `! H0 ?9 Q* O% m# w
  3.   NVIC_InitTypeDef NVIC_InitStructure;
    ' T: P8 B  h6 O* f& ~7 w1 B& ^
  4.   : F1 v, ?; {7 }" `3 u; `7 v* O9 D' F5 U
  5.   /* 配置NVIC为优先级组1 */  O- K# d; U, h7 S9 f
  6.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);5 v8 H6 \9 ?. U/ \0 T
  7.   $ x! {* L) U3 ^+ E
  8.   /* 配置中断源:按键1 */& t5 B& D" E5 y$ j
  9.   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;  //配置为EXTI0通道
    8 r9 \& |, `8 E* ^, o' ?6 Q
  10.   /* 配置抢占优先级 */
    6 M4 G) a, q. z- [4 c8 _
  11.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;) P# ?& B3 ^2 J1 R: o9 |  |; U. m: {
  12.   /* 配置子优先级 */0 ]" v7 M* S" m, `
  13.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    % O3 {8 L: b7 B9 r& a$ z+ h
  14.   /* 使能中断通道 */6 p0 C, i* G+ X. [
  15.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    " n, |) N4 p2 ?( {7 \: o
  16.   NVIC_Init(&NVIC_InitStructure); //将上述配置参数传入中断初始化函数- j  o7 m- D) v0 B
  17. }
      G! {; d  ~' R) e3 G2 ]8 y" l

  18. ' n% {- z; A  Q- i
复制代码

' x/ T6 k+ T$ _  @* N/ T
除了中断线的配置,我们还要配置对应引脚
  1. void EXTI_Key_Config(void)& u/ |- B  K- u1 k( ?
  2. {  O" D  k" U) X7 M6 e  B* Z
  3.         GPIO_InitTypeDef GPIO_InitStructure;
    * k; n/ r3 P) z  F4 z8 L$ e
  4.         EXTI_InitTypeDef EXTI_InitStructure;4 k4 @2 K5 [* q! t# @1 X' y
  5. + C; b* @' U( @2 h
  6.         /*开启按键GPIO口的时钟*/
    1 B9 L9 J. I3 t& m; d: F; X
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
    1 U" E" F; F  P- j
  8.                                                                                                 / ?' w, ~  A  N5 p% m1 P
  9.         /* 配置 NVIC 中断*/
    % R% y; ~$ j" S, ?8 Y
  10.         NVIC_Configuration();
    3 i4 _/ f5 [9 I% t" o% m
  11. /*--------------------------KEY1配置-----------------------------*/. L$ X" j. Q  {9 i1 F
  12.         /* 选择按键用到的GPIO */       
    7 G0 _% E7 x6 L# X/ }  y
  13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    5 X( l: x; I5 `: x: F( h
  14.   /* 配置为浮空输入 */        - p3 Q9 F8 O* W- a; b/ K; ?
  15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;; u/ G7 m. @# p. S" }6 ?5 L
  16.   GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);2 v+ c/ l1 _" ~, d
  17. 3 w  H7 P$ Q4 N4 A
  18.         /* 选择EXTI的信号源 */
    & Y# ?4 k5 ?% |( I
  19.   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
    5 T, b! }: Y( R7 v  e
  20.   EXTI_InitStructure.EXTI_Line = EXTI_Line0;( @* P4 O# w& K" Q
  21.        
    5 X- g1 \0 {6 j9 O& |; k  [
  22.         /* EXTI为中断模式 */
    + n; X; D% w# a- |6 |& ~; G% y
  23.   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;% f$ Z1 ?" m/ M
  24.         /* 上升沿中断 */9 H3 r1 w1 \3 M( T# s* B! x; d
  25.   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;7 U1 G# [7 N3 J% z$ i  N; d5 C# d
  26.   /* 使能中断 */        ( p/ M% q5 @+ W5 I$ ~) S
  27.   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    ; `% {0 T1 _* I7 M9 L2 }. y
  28.   EXTI_Init(&EXTI_InitStructure);
    * F& S8 z" B3 _9 ?4 e9 y
  29. }- _' Z8 i; K$ E, p5 f
复制代码

# {5 M+ A5 P! d0 O
至此,中断的配置完毕。相信你已经看出来,上述代码是将PA0配置为上升沿中断。不过,现在只能够说该中断已经配置完毕,但我们还不能使用它。我们还缺少一个中断的执行函数。
当中断被触发后,程序要马上跳转到中断函数去执行中断操作,这个函数在工程创建时默认时没有的。需要你自己去添加。而且需要注意的是,中断函数的名称必须是由标准库提供的,否则无法识别。
我们打开startup_stm32f10x_hd.s这个文件,在里面能找到这么一段代码:
  1.                 ; External Interrupts
    . m' M! R- ^+ i6 X$ c% `9 Y
  2.                 DCD     WWDG_IRQHandler            ; Window Watchdog
    / s2 P2 Q) }; B6 F
  3.                 DCD     PVD_IRQHandler             ; PVD through EXTI Line detect! y/ {% {3 }, A4 q% N* B
  4.                 DCD     TAMPER_IRQHandler          ; Tamper
    3 N% [" x7 y/ o$ v1 `6 R
  5.                 DCD     RTC_IRQHandler             ; RTC
    * _; S* x6 h; C6 m, c; A8 z& i! z" a
  6.                 DCD     FLASH_IRQHandler           ; Flash
    : m' X! w+ F4 |: M4 r1 V. H
  7.                 DCD     RCC_IRQHandler             ; RCC
    " V# |( o, d. t. V! B0 u8 u
  8.                 DCD     EXTI0_IRQHandler           ; EXTI Line 0- w: z' I+ k# M
  9.                 DCD     EXTI1_IRQHandler           ; EXTI Line 11 e7 H! y4 y; a0 m9 L
  10.                 DCD     EXTI2_IRQHandler           ; EXTI Line 2
    6 y- y- H6 H( S
  11.                 DCD     EXTI3_IRQHandler           ; EXTI Line 3
    + d9 a+ Q* Z2 y0 `# G
  12.                 ...
    3 ^( s  l; f0 E
  13.                 ...
    " Z9 B; z) D0 T
  14.                 ...8 O. R' f8 _5 @' i( ^; z1 @" V
复制代码

  s4 p* V* C& O
不难看出,EXTI0_IRQHandler 就是中断线0的中断函数,所以,我们把这个函数添加到工程中即可。最好添加到stm32f10x_it.c 这个文件中,方便管理。
可以在这个函数中添加你想要的功能,代码如下:
  1. void EXTI0_IRQHandler(void)' @/ W! Z# \# h% \( Z
  2. {+ z! E1 M9 \+ }8 j& R
  3.   //确保是否产生了EXTI Line中断9 U# D' O. _" P( F) ]: j" j
  4.         if(EXTI_GetITStatus(EXTI_Line0) != RESET) 6 [) c+ @) z8 O$ c! B% j
  5.         {
    4 d( x8 `. B/ v3 t
  6.                 /******/& }2 b0 O5 ~# X, ]$ K$ ^) b- M; m
  7.          //LED闪烁相关代码
    1 Z: J  W& w& f9 y/ o  h/ p
  8.                 /******/, O" m  l- i; c' R- {# r
  9.     //清除中断标志位3 ]6 K. H. R+ x" ]' G: u' R
  10.                 EXTI_ClearITPendingBit(EXTI_Line0);     
    0 b2 R5 @6 B7 \' s0 Z
  11.         }  8 d: _( \. N0 g. ]
  12. }# u  N+ V* t7 x, L: i' R! A1 i
复制代码

3 c1 d9 ^4 C1 ?2 b
至此,整个中断的流程梳理完毕

' Y; h, s4 z. V9 M5 _) I
收藏 评论0 发布时间:2022-1-17 21:33

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版