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

基于STM32F1的CAN通信之中断

[复制链接]
攻城狮Melo 发布时间:2023-10-23 16:35
一、什么是中断" \/ H7 z7 z6 ^( d3 E) T
首先介绍一下什么是中断。在实际开发过程中,中断是很有必要的。比如需要针对某种特殊情况进行快速响应,单纯的使用一个while轮询似乎并不能满足。中断的概念非常好理解,举个经典例子。比如你在家里看电视,忽然有人敲门,你临时把电视暂停了,转去开门。开完门之后再次回来继续看电视。中断也就是这种流程。看电视的行为就类似于程序中main函数的while,轮询执行业务。忽然有人敲门,对应程序运行过程中忽然产生了一个中断请求。此时暂停电视,对应于此时程序中断当前的业务,转而去处理中断业务(开门)。最后,中断业务处理完成后,再继续执行main函数while轮询中的业务。简单用一个图来表示一下. G: I1 }1 A$ H* s) F+ T

- L" m5 Z, {$ ^8 L, _
5 x) q4 D5 Y1 z6 j" g! N  t  t# A
微信图片_20231023163549.png
8 U3 F- P& m/ M4 a0 D" x
中断概念示意图

2 z/ I3 F1 d1 n" h, f
! D3 H& D/ w! h) W
根据中文参考手册的介绍,STM32F103ZET6除了一些特殊的中断外,常用的中断有60个,这些中断是通过中断控制器来有条不紊地分配执行的。
( h2 s  @! ~+ E8 n. w: x

8 k0 K( v3 K( K* f/ B二、中断的相关概念
1 y& O7 ?" w/ Z. p2.1 中断优先级
3 g: F1 U2 n. ~: d1 x
从字面意思来讲,优先级用来区分中断的响应顺序。当同时接收到多个中断请求时,中断控制器会根据中断优先级来决定中断处理的顺序,优先级高的会先被处理。如果在处理某个中断请求时又来了一个中断,这时会根据两个中断的中断优先级来确定处理方式。如果新来的中断优先级比当前中断的优先级高,则会停止对当前中断的处理,转而处理新的中断。反之,如果新来的中断优先级比当前中断的优先级低,则需要等到当前中断处理完成后,再去处理新来的中断。9 z# z1 V5 G, L9 @1 L2 [, z
2 T: h, i* ^/ Q. v! w
中断优先级有两种,一种是抢占优先级,一种是响应优先级。响应优先级通常又被称为“亚优先级”或者“副优先级”。当两个中断的抢占优先级相同时,用相应优先级来决定中断的处理顺序。如果两个中断的抢占优先级和相应优先级相同,则根据芯片手册中的中断向量号来决定中断的处理顺序。比如同时来了两个中断请求,在抢占优先级和响应优先级均相同时,中断向量号为41的中断会比中断向量号为42的中断先被处理。6 h% n( y+ u: F9 K# W( \' t, D

; v$ s+ h. D3 [* T) j' h) e
# }1 b) |/ X7 G8 Z% K' G( n. [' }
STM32提供了16个可编程的优先等级(使用了4位中断优先级),优先级分组可以使用库函数提供的NVIC_PriorityGroupConfig()设置。+ C5 V5 u' G4 V2 T
3 F9 r* e/ T- P0 E9 o
2.2 中断嵌套
: `3 o2 ]4 G4 x( {0 g# x8 D# v一些低优先级的中断可以被高优先级中断打断,这种情况叫做中断嵌套。
" }& H2 d8 n, m6 |& D$ G  v/ M6 |$ _" b
$ g8 h1 L2 a( `$ s, a) _2.3 中断服务函数0 X0 C/ x5 J3 O$ P5 C
中断服务函数就是在进入中断后需要执行的内容。
, |% e9 V8 Q$ A) n
& I4 g: n  u) D5 @中断服务函数有特定的函数名,可以在下图文件中搜索“IRQ”找到。
1 M: b' D7 }3 X. O/ K9 _" \8 x/ N4 b1 ~7 ?+ [4 ^

% k# k; ^) Y% S# h
微信图片_20231023163541.png

) {6 Z: L2 w( w( A
中断服务函数名
4 e* r# K7 n2 B% g' b. ^

/ C8 z/ s+ ?2 ~- S+ O. T+ P
2 ?( y& i" C9 Q  `$ ^
2.4 中断标志位, Q: ]3 Z) B1 b) a% z: U
不同的中断会有对应的中断标志位,通常标志位默认值为0。当产生中断请求时,标志位被置1。比如设置一个串口接收完成中断,串口接收完成标志位初始值为0。当串口接收完成后对应的串口接收完成标志位会被置1。在中断服务函数中检测该标志位的值,来确定是否是串口接收完成中断产生了。每次中断服务函数执行结束后,需要清除一下对应的中断标志位。5 Y1 I: k+ S( c9 o- p
8 O" [8 b. H8 J

! G* W4 J# U# }3 f三、外部中断EXIT
4 x$ u0 i3 V$ t* I1 aSTM32F103ZET6有一个外部中断控制器(EXIT),可以支持20个软件的中断/事件请求,其中外部中断的EXIT0~EXIT15同坐IO中断。2 z7 D! Y: X, b# V! _
/ j2 h/ n$ ^4 l, a3 M
微信图片_20231023163536.png
3 T1 n0 x+ o4 Z2 ?
外部中断IO对应

( b1 x4 `, ]  Z3 V9 l5 X
* W4 X( O9 c+ X% M/ s: g4 @

1 C/ W3 F8 f" U; G& `, d9 K; d
其他详细的介绍这里就不再说明。
* E  ]2 |% g* D# d; Z* G, |$ }$ ]0 S1 m  ?6 \
, `6 [) F0 G8 |: U9 `
四、中断程序配置! ]$ m9 T1 y, N$ C* g
这里以配置PA0(按键WK UP)的外部中断为例,展示一下库函数开发时,外部中断的配置流程。关于其他中断的配置,后续使用其他外设时会单独介绍。/ E6 b2 h  ?" a5 C
/ M$ }$ Q' d' y! d7 P
想要实现的效果是,利用外部中断实现按下WK UP,LED1点亮。
( c4 C/ K1 t1 ]5 a1 q$ f! B
- o2 J" |8 c+ W. @! P4.1 设置中断分组并使能中断" W* Q! a" O# q6 u1 M; g
这里使用外部中断,需要开启AFIO时钟,设置IO与外部中断线的映射关系。0 S2 G1 T8 u) [! X2 d4 Y5 m
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟: _$ d/ ^" D, ]0 F9 }
  2. ! D: C3 Z2 B& B  i. ]
  3. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路
复制代码

1 b: y; ~( C/ o: G. b. M- N$ t设置中断分组并使能中断时,库函数提供了一个结构体,我们直接配置这个结构体就可以了。  S# k' K+ T4 |4 w7 l9 h
  1. //EXTI0 NVIC 配置
    1 x& [0 H) I) R" b* M
  2.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道4 V+ w. j& _5 w
  3.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级
    : t# w9 j# c1 N9 e. ]0 F- I
  4.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级
    8 t  N/ ~7 C: f7 q# p. U
  5.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能( i) |+ V  x/ G2 x
  6.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器2 k9 }( y: Y6 m$ p  T, K
复制代码
: Q. m5 y3 d( s/ H, H, ?% _$ F1 @
需要注意的是,配置优先级时,数值越大,优先级越低。
1 C4 l- q5 z7 ^$ K: @, L% n# f

4 @& Q4 B+ K; S8 f, N4.2 初始化EXIT

# n  }* z* `7 G1 v初始化EXIT时,库函数也提供了一个结构体,其中包括中断线,EXIT模式,触发方式以及EXIT使能或者失能。由按键检测一节了解到,WK UP按下时,会产生一个上升沿。因此触发方式我们选择上升沿触发。# I$ m1 ?+ ]: F9 }
  1. EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0* `9 k6 [; \1 X7 \% ]& F
  2.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断
    7 {# ~3 K5 p2 Q$ ?
  3.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发$ P/ d. a9 p' G) Z( H0 j$ I7 j" B; w2 n4 L2 Z
  4.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能7 C; `' l% n8 n1 {5 ~
  5.     EXTI_Init(&EXTI_InitStructure);
复制代码
7 v# c* Q% l9 {4 u1 W4 ]3 v) n
整体配置函数如下
" b) S) Q& [, Z% F) V
  1. /*& z+ X( G3 e7 r+ U! T3 T
  2. *==============================================================================2 d! I4 q8 A, D# m, T
  3. *函数名称:Exit_Init
    ! W% D: B( h& V" Q: T8 {+ R
  4. *函数功能:初始化外部中断# _* M. l- V* G; Q
  5. *输入参数:无+ s3 q  l. q/ j. e
  6. *返回值:无, u. y4 S7 w4 s$ I" k% h1 g$ b9 H$ {
  7. *备  注:无
    ) ~' P$ N9 ]; t: ]
  8. *==============================================================================1 b2 |$ W3 k" k4 X/ h. @
  9. */3 K- y1 e. f3 ]" n, s% }
  10. void Exit_Init (void)
    5 m* h% L% p; d* P& g7 I
  11. {, S4 V4 g2 S* ^' o# \% [
  12.     NVIC_InitTypeDef NVIC_InitStructure;# T" C, p, U% w5 e& M, t) B# H
  13.     EXTI_InitTypeDef  EXTI_InitStructure;
    - R$ c$ U2 v5 _" K8 d# Y6 Z
  14.     % w$ G& q/ S1 y
  15.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟* W. P2 \5 l" P5 A. z
  16. 4 d9 s2 N; Q( p+ w" R( Q$ C( w* e; U5 p
  17.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路9 N, C$ p! x! e7 U& h/ Y) y
  18.     ' D1 s) _2 u5 I: |; {9 a, J0 Z/ ^
  19.     //EXTI0 NVIC 配置+ z4 h0 U7 Y7 Y6 d
  20.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道
    3 m- Q3 d3 K) \( A" q
  21.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级
    5 E% @  t4 n2 |& r
  22.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级# T% a+ r! `" a
  23.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能3 R4 ^: q, l4 L& Y+ r+ G
  24.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器+ L1 n, O  l+ P: P+ Z  c  n; b0 b! k
  25.     % [0 F9 l" O5 U* ]7 q  o
  26.     EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0
    8 m8 c, U+ x, Y/ K8 d- c: R
  27.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断
    " `$ G5 m; x3 ^5 ?) c) Z
  28.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发
    % F9 H. [& H0 t! L  k/ H
  29.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能
      d4 F. Q. \5 p& V, i
  30.     EXTI_Init(&EXTI_InitStructure);& m3 B9 v  \% `9 u' |7 O4 S# H" K
  31. }
复制代码

, i0 R/ F" M9 J( J4.3 编写中断服务函数

6 E) L5 y* N; h. S$ k上面介绍了如何找中断服务函数的函数名,这里直接开始写中断服务函数。这里的中断服务函数比较简单,直接点亮LED1即可。) a( U% K2 e$ C) A( m
  1. /*" ~/ q9 s7 y" k  i
  2. *==============================================================================5 A2 l( z5 h- g6 h- E( k
  3. *函数名称:EXTI0_IRQHandler
    . D* _/ z! y2 g* E8 ~1 x
  4. *函数功能:外部中断0中断服务函数
    $ [  m6 n( z9 b& o
  5. *输入参数:无
    4 R) W& W/ P4 ]4 f* A
  6. *返回值:无3 x% B) _0 K& S4 |( ?
  7. *备  注:无
    2 F$ v2 x+ O% `  o
  8. *==============================================================================8 l. s* C- ^/ j; o; B' Y5 s, {3 B
  9. */& v4 f8 D6 ~* J
  10. void EXTI0_IRQHandler(void)- |$ I; m& F( u( y; Z
  11. {2 U: f2 i- y! W# R
  12.     // 如果EXIT0中断标志位被置13 G' X) D( U* y6 G6 h7 a
  13.     if(EXTI_GetITStatus (EXTI_Line0)==1)
    - V5 D+ {9 U4 D1 c; h' H8 v
  14.     {
    $ ?/ Z4 |* Z1 X8 J
  15.         Med_Led_StateCtrl (LED1,LED_ON);   // 点亮LED1) ]! Z' e" j( t" v1 v
  16.     }
    5 x3 H9 K9 u. I5 M' t
  17.     EXTI_ClearITPendingBit (EXTI_Line0);   // 清除中断标志位
    1 V% `, p" z% O- S
  18. }
复制代码
. c$ \- A& o2 g
至此,按下WK UP后,LED1会点亮。这种方法与之前的按键点亮LED有什么区别?之前的按键点亮LED是在main函数的while中实现的,而利用外部中断的方法,是在外部中断的中断服务函数中实现的。即使main函数的while轮询业务中没有按键业务,按键依旧可以起作用。
6 Q& ]0 z- P4 F4 d8 H, S  n- K- d- m; J2 W: A
8 ]- n: S* ~3 l$ W0 j
五、注意事项

2 B9 \! _" {7 m- I0 T5 x• 中断服务函数无需在.h文件中声明
4 p' \6 V2 I& B8 D$ c• 中断服务函数中不要有过长的业务1 S( |3 m7 Z2 ]/ D& f* v4 y
• 中断服务函数最后需要清除中断标志位
5 F6 D& G. f. u, @2 ]% Z
6 U! g& v" p: ?& S% M7 U4 i, M) D
. {  V4 Z! _/ X* M9 E
转载自: 二土电子
$ V" }7 W6 `* n$ d  ?0 d如有侵权请联系删除
, J5 ^6 l& n7 m0 @$ [$ W/ }& O; n! Z. p9 t3 T; G" w

3 T: U# C! X* u2 Q# @/ }
收藏 评论0 发布时间:2023-10-23 16:35

举报

0个回答

所属标签

相似分享

官网相关资源

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