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

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

[复制链接]
STMCU小助手 发布时间:2022-1-17 21:33
STM32具有十分强大的中断系统,将中断分为了两个类型:内核异常和外部中断。并将所有中断通过一个表编排起来,下面是stm32中断向量表的部分内容:
& d; f# t  X/ ?! t
1097927-20180814123940440-1953049551.png

% I) a: }( X* x) g9 s
1097927-20180814123948507-6094837.png

) g4 M2 i: g; x' k" D
上图-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();
复制代码
5 T& @( [1 }$ \% m- {
其中括号内可以输入以下一个参数,代表不同的分配方式:
NVIC_PriorityGroup_0
NVIC_PriorityGroup_1
NVIC_PriorityGroup_2
NVIC_PriorityGroup_3
NVIC_PriorityGroup_4

- @  Z) \4 E) {- J7 d
EXTI外部中断
STM32的所有GPIO都引入到了EXTI外部中断线上,也就是说,所有的IO口经过配置后都能够触发中断。下图就是GPIO和EXTI的连接方式:
从上图我们可以看出,一共有16个中断线: EXTI0到EXTI15.
每个中断线都对应了从PAx到PGx一共7个GPIO。也就是说,在同一时刻每个中断线只能相应一个GPIO端口的中断,不能够同时相应所有端口的中断事件,但是可以分时复用,在程序执行过程中,这个不需要我们太多的去关心。我们关心最多的是中断触发的方式:
. @" |( ?- E7 U5 t" C
1097927-20180814124003510-425482330.png

% X, e& x$ j7 V; ~; E; U
在EXTI中,有三种触发中断的方式:上升沿触发,下降沿触发,双边沿触发。根据不同的电路,我们选择不同的触发方式,以确保中断能够被正常触发。
9 G4 B5 H! f4 j) v' f
实例
为了便于理解,这里我们将中断配置代码贴上来。
  1. void NVIC_Configuration(void)9 L7 @& Y9 D; l: z( I+ M
  2. {% u& z8 V% \; _6 m! @+ e9 A
  3.   NVIC_InitTypeDef NVIC_InitStructure;
    6 `! F& m9 x9 D: n+ N# }, \
  4.   ; Y7 T: K  }5 f8 V+ X9 j
  5.   /* 配置NVIC为优先级组1 */
    % M' I) \: z  \7 M% F' b6 f
  6.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);4 u5 n; c' o2 D; P' g6 n7 z
  7.   
    - b4 q; c  ^) m! ^) h
  8.   /* 配置中断源:按键1 */; O# k" F1 k, d4 |) C  i! g
  9.   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;  //配置为EXTI0通道/ {' |! s! E; n, n# g
  10.   /* 配置抢占优先级 */
    % I3 G4 [5 N* U9 w
  11.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;0 a3 ?# k; ~3 B/ g3 j! i
  12.   /* 配置子优先级 */
    % N$ \$ i' x* M' F. O- z' F3 k$ l
  13.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    9 p' G9 o. E$ X4 c" T
  14.   /* 使能中断通道 */
    " @8 C# X; l- s* A% F
  15.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    2 }: D4 h. _! w! Y* b5 [# C3 O7 W
  16.   NVIC_Init(&NVIC_InitStructure); //将上述配置参数传入中断初始化函数$ U9 a! L( A( B$ ?
  17. }
    % ]2 \! k8 T: I
  18. - B, W7 o. @6 y2 K/ e$ P
复制代码

; a# N8 Q; R1 _2 ^: H5 Z
除了中断线的配置,我们还要配置对应引脚
  1. void EXTI_Key_Config(void)
    4 @  s4 ?) w1 L7 a  e* `
  2. {
    ! x0 r' U0 c/ J. J3 b) v7 {7 ?, b4 w
  3.         GPIO_InitTypeDef GPIO_InitStructure; ( I* I1 w% O, z1 j9 g$ S# O4 H* u
  4.         EXTI_InitTypeDef EXTI_InitStructure;6 M! D5 J, h5 y- S( Z( X

  5. $ }  A" J+ b# C% A
  6.         /*开启按键GPIO口的时钟*/
    3 R: H/ x) p, a* v* Z
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);; M5 I' ~1 T8 L0 Y: G$ ]
  8.                                                                                                
    ! C- a8 u3 N% k' _. v
  9.         /* 配置 NVIC 中断*/
    + M$ g* h( z8 {& c: K- p
  10.         NVIC_Configuration();
    & {3 j1 J9 x4 k4 u
  11. /*--------------------------KEY1配置-----------------------------*/& \4 K0 _7 w% G8 e2 a( I
  12.         /* 选择按键用到的GPIO */        , B/ A* s6 c5 d$ c$ F+ B' \
  13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;: z$ S6 u2 w- }/ L; b
  14.   /* 配置为浮空输入 */        - J9 F" `' G( W; y) [
  15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    4 \% Y6 `2 P4 u0 r1 u& C
  16.   GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);+ e$ C0 I; m! J, S  R8 r# F

  17. * d8 n8 M) J9 D, ~, W0 H1 ]/ g  y
  18.         /* 选择EXTI的信号源 */
    . I6 O! p/ w0 r9 T9 c2 w
  19.   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); * V  m$ M1 q0 K; _9 Z: m
  20.   EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    * B. X5 u9 k4 ^+ {9 f
  21.         , k& F( r* @4 c5 L  W9 X' v6 t& L
  22.         /* EXTI为中断模式 */3 N( ~/ ~0 y+ w# o2 W0 ?
  23.   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;# d1 _" p5 m- b6 O4 Y4 ^' j$ ?, N
  24.         /* 上升沿中断 */
    ( P8 R; w/ L' |
  25.   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    4 W; Q$ b5 M) h6 O  ?& d. w( C
  26.   /* 使能中断 */          o# C- \8 t$ i6 P6 `! |6 l! U
  27.   EXTI_InitStructure.EXTI_LineCmd = ENABLE;& i: V$ c1 X% \! l3 D
  28.   EXTI_Init(&EXTI_InitStructure);
    % V) s0 a* D  I( c$ z$ }& J$ u
  29. }( z- A2 r3 t! n+ ]( _( f
复制代码
$ U. e: u: T2 w: H% R1 O# e( U
至此,中断的配置完毕。相信你已经看出来,上述代码是将PA0配置为上升沿中断。不过,现在只能够说该中断已经配置完毕,但我们还不能使用它。我们还缺少一个中断的执行函数。
当中断被触发后,程序要马上跳转到中断函数去执行中断操作,这个函数在工程创建时默认时没有的。需要你自己去添加。而且需要注意的是,中断函数的名称必须是由标准库提供的,否则无法识别。
我们打开startup_stm32f10x_hd.s这个文件,在里面能找到这么一段代码:
  1.                 ; External Interrupts
    9 _% H; o. G& Z, @; {, W7 v0 P- N
  2.                 DCD     WWDG_IRQHandler            ; Window Watchdog* }! o" m. @7 t; ]* G" `, q/ @, }
  3.                 DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
    7 M9 X4 U9 |$ T/ u" n0 e) Z
  4.                 DCD     TAMPER_IRQHandler          ; Tamper6 Z% E" u$ `$ x( ]; t
  5.                 DCD     RTC_IRQHandler             ; RTC. J/ k) g  O4 `  e, r& Q
  6.                 DCD     FLASH_IRQHandler           ; Flash5 ?  v; E' `% L/ p' g
  7.                 DCD     RCC_IRQHandler             ; RCC* `. u5 ]" ]& e2 x/ m+ r" ?
  8.                 DCD     EXTI0_IRQHandler           ; EXTI Line 0, r+ m  I1 {: K( R
  9.                 DCD     EXTI1_IRQHandler           ; EXTI Line 12 s* E6 H" g/ e5 p0 ]9 w
  10.                 DCD     EXTI2_IRQHandler           ; EXTI Line 2- r0 Q7 h0 ]' q: H
  11.                 DCD     EXTI3_IRQHandler           ; EXTI Line 39 Y  {' `7 O- D; |$ x
  12.                 ...0 P7 b$ s" e* ?9 ]2 s( I5 {' u7 N/ k
  13.                 ...+ ]" I; `# D2 `2 V/ q' E- f) K" L
  14.                 ...
    & a, N1 \$ _2 r0 P0 f8 h
复制代码
9 M) }4 q0 v- C9 L6 P- E8 l: ?
不难看出,EXTI0_IRQHandler 就是中断线0的中断函数,所以,我们把这个函数添加到工程中即可。最好添加到stm32f10x_it.c 这个文件中,方便管理。
可以在这个函数中添加你想要的功能,代码如下:
  1. void EXTI0_IRQHandler(void)- i( u- u0 T1 J7 S) N% ~2 N
  2. {& e# b% B6 f9 |5 }/ E3 R$ c4 j5 Q
  3.   //确保是否产生了EXTI Line中断
    6 U$ \+ f2 x! F9 y4 i. z! r. \' _
  4.         if(EXTI_GetITStatus(EXTI_Line0) != RESET) 8 I: T, @" f8 l( o9 J
  5.         {2 l. N. N9 t# l! H7 l& p
  6.                 /******/
    % C3 ?- P: L) E. d; A2 }7 z
  7.          //LED闪烁相关代码
    5 w6 ~& X- V2 n$ C' o2 F* o: d- Z) L
  8.                 /******/, v$ B( y6 ?% Z2 A
  9.     //清除中断标志位
    ! R- f0 F4 x' }0 h7 t+ b2 d
  10.                 EXTI_ClearITPendingBit(EXTI_Line0);     ( c' V- g: R$ ~. k/ B
  11.         }  
    0 M+ K2 k; Z% P. I0 Z6 c( W
  12. }7 T) {( v; M6 j+ i, R- v
复制代码

: w8 M: v6 y* N1 R% M  y
至此,整个中断的流程梳理完毕

: P- W; \$ |) ?
收藏 评论0 发布时间:2022-1-17 21:33

举报

0个回答

所属标签

相似技术帖

官网相关资源

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