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

基于STM32F1的CAN通信之中断

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

) X4 ^0 D' A/ n7 U9 m7 f
微信图片_20231023163549.png
# W( y$ ]+ V* h8 J6 D5 Z
中断概念示意图

) T, L) ^1 v( t9 y
3 I7 j8 C/ F5 |( X4 `5 r
根据中文参考手册的介绍,STM32F103ZET6除了一些特殊的中断外,常用的中断有60个,这些中断是通过中断控制器来有条不紊地分配执行的。
( H+ l4 k& i+ K/ U# P% m

* t6 a9 G; V; H. Y二、中断的相关概念
+ ~% k  j& Q! ?' b: L7 ?2 @2.1 中断优先级
/ W  }' s5 G' H, ?
从字面意思来讲,优先级用来区分中断的响应顺序。当同时接收到多个中断请求时,中断控制器会根据中断优先级来决定中断处理的顺序,优先级高的会先被处理。如果在处理某个中断请求时又来了一个中断,这时会根据两个中断的中断优先级来确定处理方式。如果新来的中断优先级比当前中断的优先级高,则会停止对当前中断的处理,转而处理新的中断。反之,如果新来的中断优先级比当前中断的优先级低,则需要等到当前中断处理完成后,再去处理新来的中断。  }  C  y2 ~" A
& `! ^  ?, F0 P$ r
中断优先级有两种,一种是抢占优先级,一种是响应优先级。响应优先级通常又被称为“亚优先级”或者“副优先级”。当两个中断的抢占优先级相同时,用相应优先级来决定中断的处理顺序。如果两个中断的抢占优先级和相应优先级相同,则根据芯片手册中的中断向量号来决定中断的处理顺序。比如同时来了两个中断请求,在抢占优先级和响应优先级均相同时,中断向量号为41的中断会比中断向量号为42的中断先被处理。) V# l: S; r% K! d. X

$ b5 L# s! R+ Y) R/ Q# _8 n

0 u% O3 g4 O* W! G: NSTM32提供了16个可编程的优先等级(使用了4位中断优先级),优先级分组可以使用库函数提供的NVIC_PriorityGroupConfig()设置。
. Q6 S) e- g  p  l

7 j  Q  \% n! a$ W- x2.2 中断嵌套: Z3 _+ g: B5 P, X0 M2 Y3 u
一些低优先级的中断可以被高优先级中断打断,这种情况叫做中断嵌套。& `; C+ j+ G! N9 L$ }! o0 [

" ?9 a- {3 c# ?; `+ w2.3 中断服务函数! p7 I. M& g0 X5 Y, ]* U1 n: D% _
中断服务函数就是在进入中断后需要执行的内容。- W  X) V- \1 i* w! g5 v
, h8 J. z$ F$ u$ r
中断服务函数有特定的函数名,可以在下图文件中搜索“IRQ”找到。
, L  l9 p8 {" Q) m8 ^( {6 L7 |$ K" j* M" ~+ X* G# h: o  Z# d

& R* P* f* T5 J/ g" A, @: w% {
微信图片_20231023163541.png

7 I* \7 S4 i' l0 d; j5 T' n
中断服务函数名

8 O& {! j6 P9 ^& j
2 ?% r$ `; m0 V: \' e1 ?- p
6 s5 p5 b" l6 ~6 j. ]
2.4 中断标志位3 g; D6 |/ O( ?, z. p2 x3 |# D8 l
不同的中断会有对应的中断标志位,通常标志位默认值为0。当产生中断请求时,标志位被置1。比如设置一个串口接收完成中断,串口接收完成标志位初始值为0。当串口接收完成后对应的串口接收完成标志位会被置1。在中断服务函数中检测该标志位的值,来确定是否是串口接收完成中断产生了。每次中断服务函数执行结束后,需要清除一下对应的中断标志位。9 I& Q/ e8 \) n6 c+ h9 r5 Q" F- o

4 W; {, A/ h# d( H7 u
3 Y& V1 ^7 {2 w5 a
三、外部中断EXIT/ B; P& M6 I$ v. |' ~
STM32F103ZET6有一个外部中断控制器(EXIT),可以支持20个软件的中断/事件请求,其中外部中断的EXIT0~EXIT15同坐IO中断。' o$ T% V5 V& A1 _7 X

9 r$ Q( h2 |4 h- _# j6 _  u" @  c
微信图片_20231023163536.png
9 p3 S, t) u( X) ^" O; p1 Z  K
外部中断IO对应
/ H- m# h; Z0 V  Q9 `! N
- L  e9 D' r8 F/ D8 o* c# m
) s- F# t& e9 y( k5 i
其他详细的介绍这里就不再说明。
% U1 U. j3 L9 Z  \1 C, M$ D# }/ u6 c+ X% v( ~3 i
0 {9 k3 g6 P2 I' q# O' U
四、中断程序配置# T5 W9 {+ X% A1 p4 K$ w( W, J
这里以配置PA0(按键WK UP)的外部中断为例,展示一下库函数开发时,外部中断的配置流程。关于其他中断的配置,后续使用其他外设时会单独介绍。: M( T9 N( b0 C, y) Q- l+ @. M

5 I" I3 A& w' {想要实现的效果是,利用外部中断实现按下WK UP,LED1点亮。. E7 m3 q3 _$ e9 h5 \

4 Y3 M6 {4 |2 ^8 x2 V$ Y4.1 设置中断分组并使能中断
# ]( X- W  A6 ]) v/ g$ h* E这里使用外部中断,需要开启AFIO时钟,设置IO与外部中断线的映射关系。
5 q5 j% R1 d; D  Y) }5 b
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟
    " E8 Z6 H  a- d0 f4 N

  2. 8 F4 x, r" V% Z1 |
  3. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路
复制代码
+ C/ {! r7 S0 b6 Z
设置中断分组并使能中断时,库函数提供了一个结构体,我们直接配置这个结构体就可以了。$ ^$ H6 X8 g# _4 C  z+ [" Z
  1. //EXTI0 NVIC 配置! {/ t3 z/ S7 z) Y
  2.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道
    5 d3 y, H: E! Q5 Q/ N5 s
  3.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级
    6 [2 Q* g3 M8 }; O; d+ q
  4.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级' r- n2 N/ `& d  M6 j
  5.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能8 U6 o: f9 ^/ c$ c7 c9 [
  6.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
    ) a$ e  y# o' u0 n# f8 T
复制代码
% G: ~$ R' M) p7 w
需要注意的是,配置优先级时,数值越大,优先级越低。
/ [2 \1 ]# i0 `/ B' B
8 [, G0 j  r; \3 E/ p
4.2 初始化EXIT

$ ?, j6 e6 ]7 o初始化EXIT时,库函数也提供了一个结构体,其中包括中断线,EXIT模式,触发方式以及EXIT使能或者失能。由按键检测一节了解到,WK UP按下时,会产生一个上升沿。因此触发方式我们选择上升沿触发。* y9 x3 ]* T" {4 a# x
  1. EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0
    # O2 [) n( X) _! {
  2.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断
    ( z" O3 W8 |8 I; O7 g; y: T( w; H2 y
  3.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发
    . V. }% i, I1 [" ^! F
  4.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能4 Y/ Z. E5 U% o" C7 C4 V3 a
  5.     EXTI_Init(&EXTI_InitStructure);
复制代码

; _) r. N  d9 O, L整体配置函数如下" }+ D- ~  h+ S
  1. /*
    ! |5 O/ Y/ u1 \, A! v1 I! w% Q
  2. *==============================================================================
    & ]5 T4 a: |) c8 `' V
  3. *函数名称:Exit_Init/ M5 \2 _: w* p5 i) A1 h6 G
  4. *函数功能:初始化外部中断
    3 B% u4 x4 j" o9 ~4 p+ k9 r& A4 ~
  5. *输入参数:无9 H. b( q+ F0 a
  6. *返回值:无
    9 x* v; B- G1 W$ U) |
  7. *备  注:无2 P9 {: ~3 Z) Q* {$ F, k+ ^
  8. *==============================================================================
    * m4 b( o; K: _: T5 H0 j
  9. */' @7 _5 N% A  T& G; n
  10. void Exit_Init (void)* ~0 l% [0 \  G+ J5 h3 E/ P6 @" B
  11. {
    " R  E$ O% O# @
  12.     NVIC_InitTypeDef NVIC_InitStructure;# R" J7 r# _" z
  13.     EXTI_InitTypeDef  EXTI_InitStructure;
    : P! R  n- y. H8 ]" ?# c1 i
  14.    
    . c2 R' m: d" n5 z8 N- j
  15.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟
    3 L2 j0 ^8 k/ H! q& L

  16. $ V. X$ A. ]  a( t  p
  17.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路
    1 ~& F0 F6 S1 V& {; T
  18.     9 k/ i/ O5 [# x/ a5 d
  19.     //EXTI0 NVIC 配置
    " l9 i: X% X4 D, Y( f
  20.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道& Q/ }4 K4 E2 Y; d/ P0 |0 \; `4 D! o
  21.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级! D: T7 Q. Q( P; X6 G$ Z) ^
  22.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级# F" b( u* s8 m9 K
  23.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能7 f  P2 k6 }' P7 Q' {
  24.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
    ! ^) ^( u- @4 K2 q7 S; v: X- m
  25.     6 ?$ b! d, j- Z6 C
  26.     EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0; k" m: V, v6 W' K8 H7 \# u
  27.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断) ?$ A3 Z% Q. T0 N# ~
  28.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发( S& b1 l7 e! F3 n: p, [" B
  29.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能
    2 s9 `1 I# W$ f* q. w3 y
  30.     EXTI_Init(&EXTI_InitStructure);
    ' [( ]) F# A4 O. [1 z& W
  31. }
复制代码
: v3 u2 c. f# h5 k4 l) W
4.3 编写中断服务函数

- ~. {! Y# n: u& ~) y上面介绍了如何找中断服务函数的函数名,这里直接开始写中断服务函数。这里的中断服务函数比较简单,直接点亮LED1即可。, H: l2 G; Q5 \
  1. /*4 v7 G+ X+ m3 r
  2. *==============================================================================
    ) E1 C- [" Z6 P4 `0 B
  3. *函数名称:EXTI0_IRQHandler
    ( t3 ^! r3 Z6 j$ k7 G) V  {+ ^
  4. *函数功能:外部中断0中断服务函数9 F; U4 h% s8 K( D/ v8 I% x
  5. *输入参数:无
    8 G. F0 d% R/ T9 x  l. E1 S: X
  6. *返回值:无
    6 n; |: S; M! V4 I3 t, R5 J* o& k
  7. *备  注:无9 y" w3 i! d: Z/ w' P) k$ t4 ]
  8. *==============================================================================
    9 ^% a5 s  X+ X) t- `  J
  9. */
    5 a, ~* N9 u# X  z; g/ I
  10. void EXTI0_IRQHandler(void)
    ( R$ m9 K5 B% {* T+ D  R8 R
  11. {, t/ ~4 f0 b  d
  12.     // 如果EXIT0中断标志位被置1
    - X- l( p) R) ~( j- g  t$ t
  13.     if(EXTI_GetITStatus (EXTI_Line0)==1)
    ! X- Y3 h- g2 m2 K/ c- ~+ i
  14.     {
    ) H5 B  ?: \0 s" K5 ]: [
  15.         Med_Led_StateCtrl (LED1,LED_ON);   // 点亮LED16 m8 f. F1 x% R9 `/ S/ u
  16.     }' b8 E  e* q* V, G- j
  17.     EXTI_ClearITPendingBit (EXTI_Line0);   // 清除中断标志位7 d* |5 e9 B3 r* X6 ]3 u! ~# e
  18. }
复制代码

! t1 j" T- ?8 ^$ k6 D/ H至此,按下WK UP后,LED1会点亮。这种方法与之前的按键点亮LED有什么区别?之前的按键点亮LED是在main函数的while中实现的,而利用外部中断的方法,是在外部中断的中断服务函数中实现的。即使main函数的while轮询业务中没有按键业务,按键依旧可以起作用。
- K1 V% S0 e* k0 A, Z6 }9 E' Y
8 d& l$ v: E+ n

  e+ k2 k9 v1 W. Y) a  t8 A) r五、注意事项

) p4 b3 x. @+ K, R4 J; k  G• 中断服务函数无需在.h文件中声明# G; V4 U( m) r" \; X" d# q) ^
• 中断服务函数中不要有过长的业务5 f6 M* ?: N* q  S' X
• 中断服务函数最后需要清除中断标志位
- i" U, d' b7 R# R. w& I$ @
5 r4 j! r6 ]/ r& s8 g6 F! _" y

0 \0 M( g) Q0 n8 `7 ]( [转载自: 二土电子
, C4 L/ V& A7 e+ z9 X; D8 M如有侵权请联系删除
: p. H  F8 e3 [: ?! v5 A0 x/ U9 u
3 A1 D" y! c7 e8 T; m8 q6 J% t0 D. O
收藏 评论0 发布时间:2023-10-23 16:35

举报

0个回答

所属标签

相似分享

官网相关资源

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