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

【经验分享】STM32-外部中断详解

[复制链接]
STMCU小助手 发布时间:2022-5-6 11:14
前言7 I* I2 X% d  \+ r
本章讲解STM32的另一个重要的外设资源——外部中断;在前面已经讲过了NVIC中断优先级管理,相信大家对STM32的中断系统有了初步的了解,知道了如何给每一个内部的中断设置顺序,然而只有内部外设的中断信号还不够,有时候我们要监视外部的数据信号变化,这就需要外部中断了。
* x% j( a' {" x) r! }' ~0 c) @3 Z# N3 [- `" a
一、外部中断是什么?' X! b8 R+ k: N7 y7 V
首先我们要理解什么是中断。
( f1 Z7 K- ~7 O, h! Z% D* W- I4 A- P6 A& t+ e
想象一个场景:你在家里看书学习,这时候突然来电话了。你的做法是停止学习去接电话,电话打完再放下电话继续学习。这一个过程就体现了中断的思想。我们抽象一下,把自己想象成一个单片机系统,看书就是正在执行的主任务,如果没有外界干扰,这个系统会一直执行当前的主任务。而当外部有改变(电话响了)的时候,系统会第一时间响应,从主任务跳转到这个紧急任务中,这个突发的事件就是(外部)中断,而系统处理的紧急任务则是中断处理函数。当紧急任务(接电话)完毕之后,系统又会回到最初的主任务中。
$ B5 ]% j  W4 C% {  A8 n
, g  {/ [/ h1 G' x3 z: v) `1 E这就是MCU的外部中断过程。
2 e& [1 [9 Y) F5 B5 b$ l$ u
/ ^5 i& Z7 G! w二、STM32外部中断概述
8 o* [3 i" }' g: S' @% b6 z1. STM32的外部中断线
. v; a1 Q- }, U9 ]& S1 T
STM32的每个IO都可以作为外部中断输入。+ Y7 V) G: ?+ r2 p
STM32的中断控制器支持19个外部中断/事件请求:8 K! t  r' x2 n7 u; s$ e
线0~15:对应外部IO口的输入中断。
# |* c$ r' \# a: K4 ]
' G( |% x: v. z+ J6 u; ~: B线16:连接到PVD输出。& T1 h4 R1 }. C3 r: y  [& Q

" \8 A% a9 Y6 j; N( _线17:连接到RTC闹钟事件。
5 Z5 i3 x  v0 S/ L  t& s3 J) k8 n  W& b+ d( U* ]6 L% ~
线18:连接到USB唤醒事件。
# W( @" k5 O( Z( d/ F. R9 @4 g7 M. a- U6 c
每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。
- u9 }3 ]( P1 ~% d2 R' p2 r) D+ ^" R5 C% o8 z* ^: A& A
2. 外部中断线与IO引脚对应关系      
7 \2 I3 Z# g) f) c        这时候想必读者可能要问了,STM32供IO使用的中断线只有16个,但是STM32F10x系列的IO口多达上百个,STM32F103ZET6(112),STM32F103RCT6(51),那么中断线怎么跟IO口对应上呢?下图就是STM32的外部中断线和IO口的对应关系:
7 M4 F$ f1 z; B8 [3 L: [: w" `3 [) j
7 ?8 \& b) e; K- Z' v; _- c% a1 r NU8(QL}MD49`]QMQX}OI`YB.png
; t0 ~" s' B6 K; E& V* V
- m! j, ], ~4 Z3 L' u         对于每个中断线,我们可以设置相应的触发方式(上升沿触发,下降沿触发,边沿触发)以及使能。
0 @# O( j8 a, x+ o' K9 A6 P2 A* y% B4 y3 ]8 x& \
3. 中断向量与服务函数
' O; @) I1 A! J0 O
是不是16个中断线就可以分配16个中断服务函数呢?
9 V" {9 ?7 m6 o+ b5 Y
' c$ ]- n. Z# g* `1 gIO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数
- }' Y9 \' g0 [  c7 m* @+ r
9 @# y9 P: M& `0 P+ h( `5 H 0INPN35(%P{J]G73VLSZ(E0.png + C- H( r+ l$ ]" B+ i* H
  d$ {: O- h8 ~$ P9 q8 D$ J* E
从表中可以看出,外部中断线5~9分配一个中断向量,共用一个服务函数 外部中断线10~15分配一个中断向量,共用一个中断服务函数。
0 P4 z& {3 w6 i1 p+ y/ v$ X& o1 k下面是中断服务函数列表:
# h5 ?: U5 B( T9 y
; C  p2 M& h$ D  R& z6 sEXTI0_IRQHandler         
' `! o! b0 J9 `  }7 h5 n) D7 f6 _0 \# O
EXTI1_IRQHandler- J" ]: m4 n: V; @; |) P

, `* ^  V% g7 b/ W" K/ QEXTI2_IRQHandler          7 _( i1 u. K8 u
3 s/ t+ W( K8 {
EXTI3_IRQHandler          / x) Q* J) G. b1 g5 O

; J" s* \# D! Z# d2 ~EXTI4_IRQHandler         
0 o8 Y( I1 x: l' X% _, p2 H% P  P6 q3 q0 u
EXTI9_5_IRQHandler        ! t  c2 P5 W0 j) m4 j

( r4 y$ G) J  p: l% g6 a0 G/ vEXTI15_10_IRQHandler      
2 `3 }. ?' X/ A% x6 ^4 O7 v# l3 z% G1 R0 _0 @
三、STM32外部中断库函数配置
: h3 }+ D! u$ J1 c1. 常用库函数
$ ]0 w. a* C* m% V
①void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);) W8 e8 x- y$ z  q9 ~- @4 K4 U" ?

& i! g1 F4 Y9 E3 s6 \   //设置IO口与中断线的映射关系
  j$ t% t  Z7 _; R  x) X( M
8 X8 e! M+ Z3 G0 [% s4 h+ `3 J0 e   exp:  GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);' U% h2 w2 c' ~* v5 ^' B7 E

$ \+ p; [4 h( j②void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
- o1 P; j$ ~5 R, w0 k- w
# k' {! s* p9 S* o; a //初始化中断线:触发方式等
/ p( D; ^: A, n3 i) o% L% q: X) n5 ?: R/ g' q
③ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);' L0 P# U$ \- z6 L) h, x* q
$ k$ z; F) j  C1 |; T/ d
//判断中断线中断状态,是否发生
! W! W/ F) C3 ?8 c! T& T) }9 O; J
④void EXTI_ClearITPendingBit(uint32_t EXTI_Line);" p' u0 }2 a# R$ n8 v" u8 c% d& L

' S/ E0 w" ~/ j6 n: x3 r% N0 \//清除中断线上的中断标志位7 h# z  I7 W; N( I! y: i
0 G: T% l8 {, A; y+ Z
以上这四个函数是配置外部中断常用的库函数,第一个函数很好理解,就是配置IO口与中断线的映射关系的。我们重点讲解第二个函数:
" n! i# w6 T$ _$ p5 s$ L6 Q& K1 Q2 `
EXTI_Init函数:
+ P- D" C7 h- @0 U2 A4 Nvoid EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
) m( {  I2 C7 S, f/ H" I# V
7 U2 I  F3 x4 P) B" ?( K; \其结构体成员变量如下:
" o9 H$ @; l8 d6 L9 _
7 [: }* L  t( {, u
  1. typedef struct
    " h7 k9 d3 A% i# f) w" J
  2. {
    5 X, S+ G6 Q; e4 E: q
  3.   uint32_t EXTI_Line;   //指定要配置的中断线           
    / z3 s+ D) U) f: X/ T9 W4 l
  4.   EXTIMode_TypeDef EXTI_Mode;   //模式:事件 OR中断
    ! \" l3 r$ C2 Q# p2 u% u7 M
  5.   EXTITrigger_TypeDef EXTI_Trigger;//触发方式:上升沿/下降沿/双沿触发
    5 w# F  h- T! B6 b: \& @
  6.   FunctionalState EXTI_LineCmd;  //使能 OR失能6 J7 j2 ^7 }% C  f
  7. }EXTI_InitTypeDef;
    , U/ B& h+ S3 C* R) v

  8. & ?" |2 a8 \* j% x3 I* @5 F& E# p
  9. //实例:
    & K8 l; S5 J5 A" L! n0 s
  10. // EXTI_InitStructure.EXTI_Line=EXTI_Line2;         
    - y) N& g9 D) i* N; K6 O
  11. // EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;        
    # P' B  V! ~3 M
  12. // EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;# w8 R% w0 {1 }& ^* R  |
  13. // EXTI_InitStructure.EXTI_LineCmd = ENABLE;
      s/ O( F$ w3 \/ l
  14. // EXTI_Init(&EXTI_InitStructure);
复制代码
2 E% u9 I  ?( }4 v# G  m; a$ y
可见由四部分组成,分别是中短线、中断模式(事件或者中断)、触发方式(上升沿、下降沿或者双边沿触发)以及使能位。3 W6 T. d7 _/ S/ z
+ @  o' j, U2 V2 w* t8 |
2. 库函数配置一般步骤9 P3 Z( N, o2 N- j5 A6 F6 {( K
①初始化IO口为输入。2 w1 ^. a( t2 [: ?# @. Y! X
       GPIO_Init();0 u2 _, z' n" ?3 d% \0 t$ q

( I! t6 d8 C2 ~- `5 e②开启IO口复用时钟。
: s) C% n: M/ M, \$ g1 ]# F
+ h0 ^( R/ Z4 m, e% u' ^  o8 K       RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  q5 Z6 r- I( a7 `7 i8 v- }0 Z! ^; M# l5 r7 G
③设置IO口与中断线的映射关系。
8 p9 q" k, o& K9 d        void GPIO_EXTILineConfig();
; R4 ?: Z% G4 n! M7 t/ Q8 l  ]1 ~! [* b' Y. O2 @$ e" M
④初始化线上中断,设置触发条件等。
$ ]0 v) t* y# D8 \7 `; v       EXTI_Init();
/ B# F6 L0 G# [+ l2 p9 F$ y  g! Q+ U' \/ N/ s* g6 }! F- F. Z
⑤配置中断分组(NVIC),并使能中断。
0 r# D1 h3 e' y; d       NVIC_Init();
* q4 S( `5 _2 f" O5 E
: o7 E# j- W. ?6 k2 m% F; m) p⑥编写中断服务函数。
& j/ ]% x6 z. f* g7 t: D+ y! J5 j" k* u. Z3 |6 l) k4 _2 Y+ m0 o: h
      EXTIx_IRQHandler();. L  o- z2 h8 z: Z

9 A0 @0 J6 [5 ?  e2 t⑦清除中断标志位/ s4 k  O4 g# j3 R% }* c/ K
      EXTI_ClearITPendingBit();
2 w; z/ C8 w/ `( K# X  X
7 e1 E: T  K7 S4 Y+ p  R$ K7 B下面是配置外部中断的代码,其实现的功能是通过STM32单片机的外部中断0来捕获按键的电平变化,使按键按下时LED灯反转,按键和LED的源文件在前面的GPIO那一章有讲解。
+ x# ]8 U1 b7 B3 k4 j. R0 a8 C; x5 v
  1. //exti.c源文件  a, t" d# S% ]8 E' K
  2. #include "exti.h"
    0 M! o6 y! _+ _2 f- Z; p: T2 M0 H
  3. #include "led.h"
    / Y7 ~* M( S, ~( J* c1 h9 u/ G
  4. #include "key.h"
    * ^6 Y, w3 H. Y. w) J7 P; b
  5. #include "delay.h"& k  d' g: m9 h& \, n3 {

  6. : v4 N& w# Z* d
  7. //外部中断0服务程序
    9 v: T. G0 N( u; s* g
  8. void EXTIX_Init(void)2 p; m1 }( T! D% [- H: ?" L' z
  9. {3 ?, g$ U$ Z& u+ N; p
  10.         EXTI_InitTypeDef EXTI_InitStruct;
    & m6 b% t  y5 ^7 @8 G
  11.         NVIC_InitTypeDef NVIC_InitStruct;
    6 Q$ Q% k1 ^( a, w/ H9 q, V6 b- ~
  12.         
    3 l. G0 h3 h" s8 h( B
  13.   KEY_Init();! T) b# |$ b4 e
  14.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    ) H6 c7 x/ M. D& B& q
  15.         
    " e* h  q# u( @  m
  16.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);9 a1 B: j( t8 b* ?
  17.         % Y/ z4 @  e$ o# t8 e! p5 R. d
  18.         EXTI_InitStruct.EXTI_Line=EXTI_Line4;* @0 U$ p4 M7 G" n, P; k7 I
  19.         EXTI_InitStruct.EXTI_LineCmd=ENABLE;; p; k, {& U8 S4 c' r
  20.         EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;6 V1 g& ]  b: t4 L
  21.         EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
    1 ]. e  I, l$ z: _& z
  22.         ; F# l' F% Q# m- x  w, ?
  23.         EXTI_Init(&EXTI_InitStruct);& }# {! w: f, ?& \: _7 F0 V6 [
  24.         / L# e; m7 w7 C- q- N# P3 j
  25.         NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn;
    4 e. W1 i" ?: }; D3 A. j% g
  26.         NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
    - g# `$ v% z* I& P4 F
  27.         NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =2;& }, I9 T8 s* x5 ?" {8 u8 _. Z
  28.         NVIC_InitStruct.NVIC_IRQChannelSubPriority =2;" O8 P8 J+ I# O9 d
  29.         
    " l8 h! J. o4 f8 t- b: V! D0 J: {# v9 {
  30.         NVIC_Init(&NVIC_InitStruct);3 c) B$ R* c* y) w4 z
  31. }5 H& t+ s7 Y" h/ x  Z
  32. void EXTI4_IRQHandler(void)
    ; E4 K( }4 @; j1 \( O
  33. {; E/ P3 z7 Z! z9 G5 _+ e
  34.         delay_ms(10);1 X9 f) v3 U" L- J1 n- p6 m
  35.         if(KEY0){6 d- q' T  v- r# {/ ~3 n8 e6 J
  36.                 LED0=!LED0;7 _, M% Z6 T* }: j. I! y
  37.                 LED1=!LED1;/ @' Y: _& p4 y/ ]. o
  38.         }% K2 R, |2 x$ f2 H
  39.         EXTI_ClearFlag(EXTI_Line4);
    * w# A' Z3 O+ @. j( v! f& r5 q8 @% y
  40. }
复制代码
  1. //exti.h头文件+ @: s" C5 Q! t) I8 `/ D
  2. 7 j3 q0 [  B8 _
  3. #ifndef __EXTI_H
    & n! i8 f) x, h7 x
  4. #define __EXIT_H         ) O2 @  R- }1 O' _6 j
  5. #include "sys.h"
    ! l& C  [# X- F' Y0 t
  6. ! z( X4 z: t5 |0 F
  7. void EXTIX_Init(void);//外部中断初始化                                                             % I+ _* _; ]6 ^9 m
  8. #endif
复制代码
  1. //main.c源文件
    2 v  l5 q1 f2 ^9 ~; c

  2. * @; T3 J) a8 R9 i0 F
  3. #include "led.h"2 n; a, \6 j! I- h  @) p) w( t& X
  4. #include "delay.h"
    ' r/ B6 l+ o% b0 Q9 z2 R- I
  5. #include "key.h"! [  @  |6 @/ B" ~5 G
  6. #include "sys.h"
    $ o, W" M  O6 _& O
  7. #include "usart.h"
    & |1 q# u7 f* f) t& g$ A2 d
  8. #include "exti.h"
    : {* t2 O; v2 X7 w# j

  9. - ]2 B) H; ^% b  G% z8 s* @
  10. int main(void): x; M2 |' n; h: i0 `; D( q
  11. {                1 O' g) m5 i' ^7 u
  12.   int i=0;" X/ d* n2 C1 {; x8 p
  13.         delay_init();                     //延时函数初始化          ! h8 z9 _  W- F% r
  14.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级4 P) K8 s: }4 j2 M" t- l
  15.         uart_init(115200);         //串口初始化为115200
      ?4 M; |* J( H! i& H
  16.          LED_Init();                                  //初始化与LED连接的硬件接口/ e( e* P2 G% Z6 @& Z6 Z! b: t
  17.         KEY_Init();                 //初始化与按键连接的硬件接口3 M3 G6 V* a- H, D* D4 B# O
  18.         EXTIX_Init();                         //外部中断初始化0 N* L, {, T$ q! E- ^
  19.         LED0=0;                                        //点亮LED0( F0 V. c, U' T; o9 n
  20.         while(1). {+ u6 H& c  D
  21.         {            4 y) A1 J7 H6 H6 [
  22.                 printf("%d\r\n",i);        
    " o; e- ^+ e6 d* c. ?! e
  23.                 delay_ms(5000);        
    : n2 w' R, D* W% L6 [/ p
  24.     i++;                ; k; Y  g* v* H
  25.         }% S2 y" G6 N' v4 v
  26. }, N3 T& s) @" H# y+ c. m- v! u

  27. & O0 d3 r5 J4 A) L, W! y! T+ U

  28. 0 P, A% j: r5 f, m

  29. + U% q% [. x9 T/ w/ h1 ]
  30. / g- }. F) I1 W1 F% z4 @  o) c4 T" _) n, z# G
复制代码

' J1 [8 W" a" k5 k/ y总结
. g; s* M; W" ?1 ^. g5 I% s2 r! V本章讲解的是STM32的外部中断,通过外部中断的原理、STM32外部中断概述以及外部中断库函数配置流程来详细讲述了STM32的外部中断这一外设,希望读者能够认真学习。, W( h5 Y- z2 W  A' ~/ Q
赞 收藏 评论0 发布时间:2022-5-6 11:14

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版