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

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

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

% U* @) {# o# l8 X
1097927-20180814123940440-1953049551.png

) X, `# p% a2 u  D, e/ ~+ |% a& ]
1097927-20180814123948507-6094837.png

& \& ]! k; o( u
上图-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();
复制代码
+ p; |. N5 C/ J$ Y6 n6 N) U
其中括号内可以输入以下一个参数,代表不同的分配方式:
NVIC_PriorityGroup_0
NVIC_PriorityGroup_1
NVIC_PriorityGroup_2
NVIC_PriorityGroup_3
NVIC_PriorityGroup_4

' I1 u% N4 \& Q7 ^: _. e. d  A
EXTI外部中断
STM32的所有GPIO都引入到了EXTI外部中断线上,也就是说,所有的IO口经过配置后都能够触发中断。下图就是GPIO和EXTI的连接方式:
从上图我们可以看出,一共有16个中断线: EXTI0到EXTI15.
每个中断线都对应了从PAx到PGx一共7个GPIO。也就是说,在同一时刻每个中断线只能相应一个GPIO端口的中断,不能够同时相应所有端口的中断事件,但是可以分时复用,在程序执行过程中,这个不需要我们太多的去关心。我们关心最多的是中断触发的方式:

$ O1 O9 O# [% r' p& U
1097927-20180814124003510-425482330.png

5 _! V  P; b0 R1 S
在EXTI中,有三种触发中断的方式:上升沿触发,下降沿触发,双边沿触发。根据不同的电路,我们选择不同的触发方式,以确保中断能够被正常触发。
5 w4 x2 X1 |, n
实例
为了便于理解,这里我们将中断配置代码贴上来。
  1. void NVIC_Configuration(void)7 a) J/ S. t5 q  p! x* }
  2. {' \: x5 @0 [( k! \' N4 u
  3.   NVIC_InitTypeDef NVIC_InitStructure;
    " w. p7 o+ n1 l( k& L0 K
  4.   
    4 H6 `( H* R$ i) B& H) t; Q
  5.   /* 配置NVIC为优先级组1 */
    9 E! I9 U' {/ D1 L8 p* E
  6.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    $ l' f/ H3 b2 o/ H/ _1 ~' ~, P
  7.   ' N. |# c9 F- R. |; a) V: R  C3 i
  8.   /* 配置中断源:按键1 */( F1 C. D3 `' h8 |1 w
  9.   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;  //配置为EXTI0通道: M! C! r* C8 k9 q3 O& {
  10.   /* 配置抢占优先级 */. x/ B* J8 p1 B+ X% ^3 `% X" z
  11.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    - ]5 Z( ^' `: m. s* y4 d1 N
  12.   /* 配置子优先级 */
      N3 O& H9 _- E4 O" o
  13.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    2 {6 ~9 j) m# Q2 ^7 r
  14.   /* 使能中断通道 */
    5 r  y, l$ J, R. f( D
  15.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 }/ F: l6 `, F2 x& y
  16.   NVIC_Init(&NVIC_InitStructure); //将上述配置参数传入中断初始化函数
    % M2 F0 F+ U& ]0 H
  17. }4 M+ V  Z% [2 b4 x( h  e' _

  18. 4 M. n7 i  b! L9 ~) ~: \* |6 c7 S
复制代码
, n  o8 E5 j1 T: O3 e- m& V8 `
除了中断线的配置,我们还要配置对应引脚
  1. void EXTI_Key_Config(void)
    * ?, w1 p0 f1 r3 F
  2. {
    2 |" X. D+ U$ M
  3.         GPIO_InitTypeDef GPIO_InitStructure; " m5 q& _: U- i3 ~$ t3 {, Y
  4.         EXTI_InitTypeDef EXTI_InitStructure;
    ; F' p2 o8 ]4 t! [7 u' @$ F5 t% u& X$ ]
  5. * {1 h" z# s4 X2 A
  6.         /*开启按键GPIO口的时钟*/0 {0 O% k+ j4 }% U
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);1 c( J* A8 j- C- O" ]0 x8 T+ r
  8.                                                                                                 0 E- G+ x5 R) h3 E, C  Q6 p  o
  9.         /* 配置 NVIC 中断*/
    6 c5 `8 s7 O0 }1 t9 T+ R
  10.         NVIC_Configuration();. s( ~3 o$ g4 r
  11. /*--------------------------KEY1配置-----------------------------*/
    1 Z5 W' g2 Q9 \
  12.         /* 选择按键用到的GPIO */        5 V1 l: Z% d& Y* t
  13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;1 S' J* }7 U& r
  14.   /* 配置为浮空输入 */        ( W+ {& W# F  `# l: L2 R4 `0 M. V/ i
  15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;5 u& J+ K: P/ \: K3 C
  16.   GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
    4 i  m# C8 |# g& @
  17. / u' X8 Q9 ?, m( K! v. j
  18.         /* 选择EXTI的信号源 */
    7 z0 f! u( C* {, q' c  I! Z! \
  19.   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
    % T- F" m1 T* \. W) @8 }# h
  20.   EXTI_InitStructure.EXTI_Line = EXTI_Line0;  s- G# n4 ?4 X$ H) Q3 s! \8 W1 g: l
  21.        
    , X$ D! O; q; ~' @
  22.         /* EXTI为中断模式 */0 o# G& u9 P# h$ Y
  23.   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    + l# U5 y1 X4 C: S3 {# D
  24.         /* 上升沿中断 */9 w9 K7 P" u  l- C, \1 y
  25.   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;8 {6 D! b, j# P' B2 W
  26.   /* 使能中断 */        ; l# M3 `2 A# p8 S! e* s
  27.   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    ) g$ J0 ]1 _0 i/ X
  28.   EXTI_Init(&EXTI_InitStructure);
    ' J+ u5 R5 |7 m5 d
  29. }
    + V+ |2 ^+ A% S& Y5 T3 x. H
复制代码

' N8 |% w8 d. O2 b' z
至此,中断的配置完毕。相信你已经看出来,上述代码是将PA0配置为上升沿中断。不过,现在只能够说该中断已经配置完毕,但我们还不能使用它。我们还缺少一个中断的执行函数。
当中断被触发后,程序要马上跳转到中断函数去执行中断操作,这个函数在工程创建时默认时没有的。需要你自己去添加。而且需要注意的是,中断函数的名称必须是由标准库提供的,否则无法识别。
我们打开startup_stm32f10x_hd.s这个文件,在里面能找到这么一段代码:
  1.                 ; External Interrupts
    3 _$ k5 S0 [8 M- X
  2.                 DCD     WWDG_IRQHandler            ; Window Watchdog
    + F5 w- |" b& w9 d- V  E; g0 A
  3.                 DCD     PVD_IRQHandler             ; PVD through EXTI Line detect* e, O9 U* ]% F$ G: r6 V1 a' M
  4.                 DCD     TAMPER_IRQHandler          ; Tamper8 o5 i* n  M% I) H  W
  5.                 DCD     RTC_IRQHandler             ; RTC; z- }3 C. ?$ H( e
  6.                 DCD     FLASH_IRQHandler           ; Flash
    2 T2 `* C8 y% F. m9 ^8 _
  7.                 DCD     RCC_IRQHandler             ; RCC6 V/ C( Z5 J9 n3 O$ H! k3 y
  8.                 DCD     EXTI0_IRQHandler           ; EXTI Line 0; ^! z$ l/ Z2 F9 n- c
  9.                 DCD     EXTI1_IRQHandler           ; EXTI Line 1  M. s$ \) r) g" p6 H) r# h* C7 S
  10.                 DCD     EXTI2_IRQHandler           ; EXTI Line 2
    . {- v" M5 }% v& L! `8 F1 r
  11.                 DCD     EXTI3_IRQHandler           ; EXTI Line 3& ^. K- R: N( _/ u6 d
  12.                 ...
    ! Z& z; E7 R! ^
  13.                 ...
    # m' e$ W5 o/ L* r% R
  14.                 ...0 H& }7 }) L/ ~/ {
复制代码

2 q) t8 h" \: ?8 B
不难看出,EXTI0_IRQHandler 就是中断线0的中断函数,所以,我们把这个函数添加到工程中即可。最好添加到stm32f10x_it.c 这个文件中,方便管理。
可以在这个函数中添加你想要的功能,代码如下:
  1. void EXTI0_IRQHandler(void)) ]6 S  a. f' `( K) D3 Z" Q  E9 @
  2. {
    ) ~. G6 O% N+ x
  3.   //确保是否产生了EXTI Line中断
    3 I! |; C/ J4 S- c# f% R+ `& }
  4.         if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    ( Q( h5 z$ ]: m* D4 O! P
  5.         {
    , y4 S+ e% t+ h* _; ^4 R
  6.                 /******/2 g; \& U6 I3 }! S2 ~( E
  7.          //LED闪烁相关代码' w$ X7 a! `5 p! W4 A# J- K; H3 f
  8.                 /******/
    3 ^" ~3 P4 U- m& r
  9.     //清除中断标志位+ ]: g8 {; T, F4 M# u& z/ \
  10.                 EXTI_ClearITPendingBit(EXTI_Line0);     
    . P; W& M: W- k+ R. w3 r, O
  11.         }  ! Q( T! x- }7 }/ A4 y
  12. }
    - ^& u8 d% s- p$ ~& D
复制代码
' B7 |6 A6 w# a/ \/ e% i6 H
至此,整个中断的流程梳理完毕
  P- @+ D# T6 K! X# V. N9 c2 F8 N
收藏 评论0 发布时间:2022-1-17 21:33

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版