请选择 进入手机版 | 继续访问电脑版

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

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

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

" j, [) G4 r5 ?( D6 I/ t, G
1097927-20180814123948507-6094837.png
0 o% ]# D" [: R7 ]& q* v. X
上图-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();
复制代码

( X' ?, C, W3 t; a3 S$ {
其中括号内可以输入以下一个参数,代表不同的分配方式:
NVIC_PriorityGroup_0
NVIC_PriorityGroup_1
NVIC_PriorityGroup_2
NVIC_PriorityGroup_3
NVIC_PriorityGroup_4
% k. |3 \7 W" d- u
EXTI外部中断
STM32的所有GPIO都引入到了EXTI外部中断线上,也就是说,所有的IO口经过配置后都能够触发中断。下图就是GPIO和EXTI的连接方式:
从上图我们可以看出,一共有16个中断线: EXTI0到EXTI15.
每个中断线都对应了从PAx到PGx一共7个GPIO。也就是说,在同一时刻每个中断线只能相应一个GPIO端口的中断,不能够同时相应所有端口的中断事件,但是可以分时复用,在程序执行过程中,这个不需要我们太多的去关心。我们关心最多的是中断触发的方式:

, N8 j% H& G: p# b) E
1097927-20180814124003510-425482330.png

5 `! ]* v  L5 c# U
在EXTI中,有三种触发中断的方式:上升沿触发,下降沿触发,双边沿触发。根据不同的电路,我们选择不同的触发方式,以确保中断能够被正常触发。
  d* H* I5 Z$ J' |: u0 `2 ~
实例
为了便于理解,这里我们将中断配置代码贴上来。
  1. void NVIC_Configuration(void)" s/ r: h$ |( z9 g* K2 A
  2. {
    6 O1 C# Q6 V' }9 P
  3.   NVIC_InitTypeDef NVIC_InitStructure;
      N1 m/ g! ^5 C) G# U
  4.   
    - p+ ^8 ]7 o" I% T) c& P
  5.   /* 配置NVIC为优先级组1 */, h0 C+ Q6 A: v5 k& D3 B: ~* f
  6.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);" e3 j% `; R  a6 A8 W+ l& y
  7.   7 G7 g" _* ]# t* C
  8.   /* 配置中断源:按键1 */
    ( e7 j% C6 d3 d) f0 {3 ?
  9.   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;  //配置为EXTI0通道
    ! R. h1 d4 l# R5 K" Z" m4 `
  10.   /* 配置抢占优先级 */( g4 i0 ?6 P! [9 a: e
  11.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;1 N" s+ X+ i! p; |9 u' q8 Y, O, @
  12.   /* 配置子优先级 */
    * _4 F; c# o  l4 p( L! R5 x# J
  13.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    3 t5 c2 p7 M$ G8 Y( c
  14.   /* 使能中断通道 */
    + S5 o# d, M; u1 ]7 ?
  15.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;& [4 n8 F9 S) A
  16.   NVIC_Init(&NVIC_InitStructure); //将上述配置参数传入中断初始化函数1 H! X4 g9 G0 h/ a# z6 k% s& H
  17. }
    ! f/ S; k. A7 p3 v+ x

  18. 6 _1 |# X: `% N
复制代码
7 Y7 ?7 J( p8 Q+ C, @, P: e% Z3 I
除了中断线的配置,我们还要配置对应引脚
  1. void EXTI_Key_Config(void)
    7 Z0 a0 m3 K8 F# @
  2. {. c' o& N& z" {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
    - j& m: p( T* W
  4.         EXTI_InitTypeDef EXTI_InitStructure;
    ! ?5 Q; C( N" u: d

  5. ' T! A. ?& V& [4 ]6 i3 t- ]
  6.         /*开启按键GPIO口的时钟*/. O" A% s% x' }
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);! A: `6 i3 L. D8 f. F0 E7 F, |
  8.                                                                                                
    1 v7 g0 S, Z; }' u; D
  9.         /* 配置 NVIC 中断*/$ B& o8 j* G1 n1 x6 K2 r& |$ a
  10.         NVIC_Configuration();3 N* m/ F( t3 \: T4 h9 q
  11. /*--------------------------KEY1配置-----------------------------*/
    6 s2 C# N, P5 R7 g- }; j+ V! c# u
  12.         /* 选择按键用到的GPIO */       
    4 t  d3 F, r2 B1 j) v9 w  ]
  13.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;/ i9 a. ]' r9 \7 x2 E
  14.   /* 配置为浮空输入 */        / X8 M; v4 W9 z# z
  15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    , S6 t& o9 s5 @' A( X
  16.   GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
    4 D; A7 f) H& u0 A, y

  17. - Q/ M/ ~" n7 _- }( S5 H) |
  18.         /* 选择EXTI的信号源 */
    / z; E* l  r6 O+ m% A! S
  19.   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); 8 T1 F  R/ P+ H
  20.   EXTI_InitStructure.EXTI_Line = EXTI_Line0;6 U% A$ G; J0 D
  21.         # I2 D' b( v4 P) B' @0 e1 n
  22.         /* EXTI为中断模式 */
    * @( w- G- X8 z! n
  23.   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    9 Y; f$ y6 p7 b9 N9 L
  24.         /* 上升沿中断 */( E: O+ g! B+ k6 S* L
  25.   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    + K  [! U# V% L6 Z
  26.   /* 使能中断 */       
    2 Z& H. ~, U' z. @
  27.   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    6 m# j- {0 w+ o4 S/ W, r6 _7 }7 o0 H
  28.   EXTI_Init(&EXTI_InitStructure);; Z! Z% D; m% r
  29. }) Q! G8 j& b9 [1 T' `
复制代码

8 Q9 X3 v9 B. R0 Z+ Y
至此,中断的配置完毕。相信你已经看出来,上述代码是将PA0配置为上升沿中断。不过,现在只能够说该中断已经配置完毕,但我们还不能使用它。我们还缺少一个中断的执行函数。
当中断被触发后,程序要马上跳转到中断函数去执行中断操作,这个函数在工程创建时默认时没有的。需要你自己去添加。而且需要注意的是,中断函数的名称必须是由标准库提供的,否则无法识别。
我们打开startup_stm32f10x_hd.s这个文件,在里面能找到这么一段代码:
  1.                 ; External Interrupts8 }0 j0 U7 i. k8 Y9 s
  2.                 DCD     WWDG_IRQHandler            ; Window Watchdog
    / I; p! P  k8 i3 P; R2 i
  3.                 DCD     PVD_IRQHandler             ; PVD through EXTI Line detect; U) z, n6 v# P9 ]: e
  4.                 DCD     TAMPER_IRQHandler          ; Tamper9 ~- ]3 y% s3 E2 j  Y& u
  5.                 DCD     RTC_IRQHandler             ; RTC9 {4 l  p2 j* I
  6.                 DCD     FLASH_IRQHandler           ; Flash
    * @% L2 _. g* U6 P
  7.                 DCD     RCC_IRQHandler             ; RCC
    - {  c. m9 t. U% B+ W- @
  8.                 DCD     EXTI0_IRQHandler           ; EXTI Line 0# E2 q4 D6 ^0 X0 s
  9.                 DCD     EXTI1_IRQHandler           ; EXTI Line 1
    ) u2 L+ v$ E+ L3 z/ y1 q" l
  10.                 DCD     EXTI2_IRQHandler           ; EXTI Line 2
    : O7 A( S' ~, x7 ~0 v8 T( G4 M
  11.                 DCD     EXTI3_IRQHandler           ; EXTI Line 3
    & Z# H6 m, x4 t# P2 D2 N& A& C7 s
  12.                 ...7 `6 D3 l) G+ P9 x& V. D$ M( e" Q
  13.                 ...2 t) Z0 G+ H- G  k- \
  14.                 ...+ }  k% m4 D/ G# S  l. d! R5 t
复制代码

# C" C- u& O" b$ V. g; ?
不难看出,EXTI0_IRQHandler 就是中断线0的中断函数,所以,我们把这个函数添加到工程中即可。最好添加到stm32f10x_it.c 这个文件中,方便管理。
可以在这个函数中添加你想要的功能,代码如下:
  1. void EXTI0_IRQHandler(void)5 H: g* N9 j5 `. E& C- p9 G
  2. {
    ; b2 l: [$ H4 g" _0 y4 b
  3.   //确保是否产生了EXTI Line中断
    . {& k0 L5 v" v/ c7 ?, a
  4.         if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    $ k' S2 d8 r0 `3 @$ s  ]& m
  5.         {
    ' D% o# Q$ X* f' c) N: ~" M$ n; l+ k
  6.                 /******/
    ( ]* l  x; `* _  y: L9 w$ @5 t
  7.          //LED闪烁相关代码0 G9 F4 E! J: _
  8.                 /******/+ l8 M5 L6 A  [: G" @* v
  9.     //清除中断标志位
    # i. b3 m; U8 f* Q& N( `; x' |3 Q1 x
  10.                 EXTI_ClearITPendingBit(EXTI_Line0);     
      T7 a, \$ L; i7 G- c, A6 x0 W
  11.         }  & Q  Y- i' q" M& W7 y* E0 d4 [
  12. }
    ! _4 J) O5 s' f* ~* D
复制代码
  O3 j5 }- v' W  M. g/ [9 E# N1 W
至此,整个中断的流程梳理完毕
3 T8 ^) ~( B& [& G
收藏 评论0 发布时间:2022-1-17 21:33

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版