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

基于STM32F1的CAN通信之中断

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

$ K9 R1 e% v4 c9 f. G
微信图片_20231023163549.png
4 ?* L- e5 f9 f$ U) \- g
中断概念示意图
8 ?* L$ @' }; W: u
! M, C$ Y4 R1 n7 E0 u; y
根据中文参考手册的介绍,STM32F103ZET6除了一些特殊的中断外,常用的中断有60个,这些中断是通过中断控制器来有条不紊地分配执行的。8 t5 x) k8 n* n
2 j# |0 D: o  C
二、中断的相关概念! Z# v) ~6 }- P& y# l! u+ V
2.1 中断优先级
- U+ I8 ~( ~5 y. O) w) {. i1 Q4 c& W9 M
从字面意思来讲,优先级用来区分中断的响应顺序。当同时接收到多个中断请求时,中断控制器会根据中断优先级来决定中断处理的顺序,优先级高的会先被处理。如果在处理某个中断请求时又来了一个中断,这时会根据两个中断的中断优先级来确定处理方式。如果新来的中断优先级比当前中断的优先级高,则会停止对当前中断的处理,转而处理新的中断。反之,如果新来的中断优先级比当前中断的优先级低,则需要等到当前中断处理完成后,再去处理新来的中断。; w9 u' F. f& K% V! o! G, l

* c- t. l# x( V, q. B1 Z, g3 d中断优先级有两种,一种是抢占优先级,一种是响应优先级。响应优先级通常又被称为“亚优先级”或者“副优先级”。当两个中断的抢占优先级相同时,用相应优先级来决定中断的处理顺序。如果两个中断的抢占优先级和相应优先级相同,则根据芯片手册中的中断向量号来决定中断的处理顺序。比如同时来了两个中断请求,在抢占优先级和响应优先级均相同时,中断向量号为41的中断会比中断向量号为42的中断先被处理。, D  `3 o4 u5 a* k# ?/ s
9 h& ?/ V9 j  k* e& z. k

8 ^& b9 p8 U% z  i9 h" q7 tSTM32提供了16个可编程的优先等级(使用了4位中断优先级),优先级分组可以使用库函数提供的NVIC_PriorityGroupConfig()设置。& N- H. C4 e% X" E5 \/ y( e

0 z6 x7 x% I- }" V2.2 中断嵌套% d# m; W9 G1 C  y* }' d
一些低优先级的中断可以被高优先级中断打断,这种情况叫做中断嵌套。) F. p/ o% r3 A' E/ I! _9 v

9 {6 U: Q' a7 c3 x; q9 Q2.3 中断服务函数
1 v) u7 `+ O$ A' T: A中断服务函数就是在进入中断后需要执行的内容。
8 f. E: j6 ?& o$ u4 G' J
8 S. N" {/ Z/ I3 s中断服务函数有特定的函数名,可以在下图文件中搜索“IRQ”找到。) ~' J7 a( l/ U1 X: s
7 o- D0 O5 Z. w+ g, }
8 A, T( c6 `% ^/ u- i
微信图片_20231023163541.png

% n/ \% `/ P4 }% B$ D  X- C
中断服务函数名

  o* q6 N, t1 ~9 ~  q; `
; z: l/ x9 q9 q+ G5 m3 v- D) v
$ W8 F' Z0 Z( f
2.4 中断标志位- H8 W  _+ [7 A. z% [
不同的中断会有对应的中断标志位,通常标志位默认值为0。当产生中断请求时,标志位被置1。比如设置一个串口接收完成中断,串口接收完成标志位初始值为0。当串口接收完成后对应的串口接收完成标志位会被置1。在中断服务函数中检测该标志位的值,来确定是否是串口接收完成中断产生了。每次中断服务函数执行结束后,需要清除一下对应的中断标志位。; W! Q8 n) X8 Z1 L& {  C
! R! ~7 q5 {/ C& {' f

0 K; ^7 x! f0 v+ i三、外部中断EXIT
* t9 k, O8 i8 W* V3 vSTM32F103ZET6有一个外部中断控制器(EXIT),可以支持20个软件的中断/事件请求,其中外部中断的EXIT0~EXIT15同坐IO中断。
( l; L" x; ~9 C- S8 h# t/ T8 K; s

6 x. P4 |- m* c1 v* K& m
微信图片_20231023163536.png

9 k" [5 ?! `( c7 d
外部中断IO对应
: Q0 A. W  \5 G# ^
" V+ u# O9 J0 t+ Z  @* S$ N! B

( M3 g# }. F& c) f! A6 \9 H
其他详细的介绍这里就不再说明。
/ c( c* R- D0 i4 {4 H: ?, }. \
( b8 c! T# t- D+ ~+ k2 K7 T6 I
9 y' j6 |- C7 M/ t3 d; W0 n: ^5 E" Q' P
四、中断程序配置* {: \8 F3 ?! F$ p+ A
这里以配置PA0(按键WK UP)的外部中断为例,展示一下库函数开发时,外部中断的配置流程。关于其他中断的配置,后续使用其他外设时会单独介绍。7 |  c/ \1 \8 q- H: M- s0 s8 h6 g7 p

+ x$ m' m7 W  R: q$ [1 z5 x) X想要实现的效果是,利用外部中断实现按下WK UP,LED1点亮。' e% I5 A$ Q+ l& `* i

& |+ v6 t' j6 F; Z3 ^4.1 设置中断分组并使能中断
0 q) A- K  R+ H! j这里使用外部中断,需要开启AFIO时钟,设置IO与外部中断线的映射关系。
: E* I% R& O% F" O. j
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟
    % c" _, P+ `* I9 c8 w1 X. U7 z

  2.   v+ K2 u9 b. z0 S
  3. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路
复制代码
+ G8 W! J1 g" @0 H& n+ @! K
设置中断分组并使能中断时,库函数提供了一个结构体,我们直接配置这个结构体就可以了。5 J7 Y( t3 V3 i+ ~
  1. //EXTI0 NVIC 配置
    ' S" Y& W* A; \
  2.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道
    + Y/ n0 w! Q( t, h9 J' f$ _  N
  3.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级
    8 |( F. D: [6 W- G" b. C
  4.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级) N7 d3 b# S) E" }
  5.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能/ @" d+ n* n" O
  6.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器0 X6 p( r2 S4 v
复制代码
# `4 Y3 i; A4 e  b: I/ B
需要注意的是,配置优先级时,数值越大,优先级越低。. \9 R  @+ A/ G) r+ L% d& l

( j/ h" u' G! ~9 m" l  k4 m( ^- I4.2 初始化EXIT

: f* D( I* B5 u7 I" {* _7 _初始化EXIT时,库函数也提供了一个结构体,其中包括中断线,EXIT模式,触发方式以及EXIT使能或者失能。由按键检测一节了解到,WK UP按下时,会产生一个上升沿。因此触发方式我们选择上升沿触发。
! {; x- w* H0 e
  1. EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0
    $ s! j7 L8 e) M( D4 ~
  2.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断9 F2 L  T4 T; n; q
  3.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发
    % g6 a% D5 J5 a- l
  4.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能7 }# t! r, b$ W' S  I- s- N" h$ r
  5.     EXTI_Init(&EXTI_InitStructure);
复制代码

6 l5 H- B2 ^' V0 [- Y, j" S5 P整体配置函数如下0 o( c% {; k8 s, c  |  r" T- M( D3 f
  1. /*
    ( N  c1 w; f% z0 u: m; L
  2. *==============================================================================. e9 z2 D; _: C! h5 ^7 S6 N
  3. *函数名称:Exit_Init
    " `- B2 b) U  Y, q$ a
  4. *函数功能:初始化外部中断* s) I# ?# B$ {7 d; Z8 T
  5. *输入参数:无
    . r# i4 z* ^5 _9 q* c
  6. *返回值:无
    3 ^, ^; T8 @4 R4 m
  7. *备  注:无
    ! v  \+ V5 J8 }2 j4 X% F
  8. *==============================================================================6 `. f1 b, j. h! J. `2 j4 |4 v
  9. */
    4 K) v8 V8 {, ]: [* t
  10. void Exit_Init (void)
    ! k0 T' u  w$ s) D- I  A% k
  11. {
      ~7 a# u# c2 M$ v
  12.     NVIC_InitTypeDef NVIC_InitStructure;
    " R& ]* p: E- _9 f/ v( T6 r
  13.     EXTI_InitTypeDef  EXTI_InitStructure;( J1 t% Q- b9 I) I
  14.     # m5 x$ V2 D0 r. x) T4 T
  15.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟
    7 A4 i* @) k, I; q- U
  16. 9 O2 T+ V3 m$ B7 E& k  u" b* y
  17.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路
    7 L# n* `6 s. w  _0 _; [
  18.     ' }) s6 {- b: V9 \% @# c
  19.     //EXTI0 NVIC 配置5 u: p  _" m9 R1 C0 P) y
  20.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道
      R# e  V6 a0 Y5 g4 b. f1 n
  21.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级
    ; a$ i4 {2 W2 M4 [
  22.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级; ?% e/ E% H! w& |% T* g) G
  23.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能
    0 p6 h# k3 `) X' k# Z  [7 F
  24.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器1 {' Z; p8 s7 e. X  v* [5 u7 @
  25.    
    & B  |" v$ ]: L. N! ]* |* \
  26.     EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0
    ' S/ }0 _# X2 W9 i) ~+ E
  27.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断; Y" `& m) |& i  z- I/ v
  28.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发
    & U1 C# E" b8 g
  29.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能
    & C( u- G0 H( J
  30.     EXTI_Init(&EXTI_InitStructure);2 N; f8 I: J- T, {- W' i
  31. }
复制代码

: |' ]( p( m/ ?3 j2 @! b8 p4.3 编写中断服务函数
  a5 I5 P* Q/ h. O) Z  O' d
上面介绍了如何找中断服务函数的函数名,这里直接开始写中断服务函数。这里的中断服务函数比较简单,直接点亮LED1即可。- n8 G* b$ L' O" `/ \" x' G. ]# C
  1. /*, ]  ~6 S* B7 r6 A" O8 U
  2. *==============================================================================) S: @+ q, ?% ]5 h8 m
  3. *函数名称:EXTI0_IRQHandler
    9 w& x& I. R* K" S) s. U' {( [3 R
  4. *函数功能:外部中断0中断服务函数
    4 E3 q* o* @9 I& q& U3 @$ c% y% a
  5. *输入参数:无
    0 b7 V4 G6 o; C
  6. *返回值:无
    , Z: J: d; f8 N$ B, q6 V
  7. *备  注:无
    ( H7 T* m% _9 j! i1 m7 j# s
  8. *==============================================================================  f2 C3 X! a; K- ]
  9. */7 B- |- K! \" `( J: ~3 D3 [
  10. void EXTI0_IRQHandler(void)
    ! j) e% v( h& h
  11. {8 Y4 \4 W9 p! ^. r. ?
  12.     // 如果EXIT0中断标志位被置19 t% N  [! r$ j4 r! u
  13.     if(EXTI_GetITStatus (EXTI_Line0)==1)
    8 i6 S( I" J; y$ W) u& x" i
  14.     {
    6 V  Y3 ?1 M; i8 j
  15.         Med_Led_StateCtrl (LED1,LED_ON);   // 点亮LED1$ w' ~1 I$ I9 K/ ]. s
  16.     }
      s  o! H) v( D( M
  17.     EXTI_ClearITPendingBit (EXTI_Line0);   // 清除中断标志位
    3 c6 y; g) z1 Q' H1 j0 b
  18. }
复制代码

$ A9 ?$ S% }3 x) q/ O至此,按下WK UP后,LED1会点亮。这种方法与之前的按键点亮LED有什么区别?之前的按键点亮LED是在main函数的while中实现的,而利用外部中断的方法,是在外部中断的中断服务函数中实现的。即使main函数的while轮询业务中没有按键业务,按键依旧可以起作用。5 `8 g5 Q- U# {9 z
. M7 G7 s3 Y  H2 t

; x# ^4 ?4 ~. d5 |1 _五、注意事项

4 i% g% c( W3 `& \# v) u' h5 Z$ [• 中断服务函数无需在.h文件中声明
) o: f, p8 z1 T8 Z+ I• 中断服务函数中不要有过长的业务* H( A1 S0 P0 f$ x5 u1 y& ~- B5 M
• 中断服务函数最后需要清除中断标志位
, j0 G8 k  L, \6 t2 ?$ r7 Z6 C

: w6 r4 r* d% q9 R# O' D5 u# D- a转载自: 二土电子9 [5 c# |7 |6 k" N( `8 L' U  S
如有侵权请联系删除
5 f1 d0 {2 h/ a/ T) ^. ]8 {1 k5 g! D' d" S5 [- T/ D

! n: r; N# z! c% z) G7 H' P
赞 收藏 评论0 发布时间:2023-10-23 16:35

举报

0个回答

所属标签

相似技术帖

官网相关资源

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