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

基于STM32F1的CAN通信之中断

[复制链接]
攻城狮Melo 发布时间:2023-10-23 16:35
一、什么是中断" ~& _5 Z: `' n  P' q4 v
首先介绍一下什么是中断。在实际开发过程中,中断是很有必要的。比如需要针对某种特殊情况进行快速响应,单纯的使用一个while轮询似乎并不能满足。中断的概念非常好理解,举个经典例子。比如你在家里看电视,忽然有人敲门,你临时把电视暂停了,转去开门。开完门之后再次回来继续看电视。中断也就是这种流程。看电视的行为就类似于程序中main函数的while,轮询执行业务。忽然有人敲门,对应程序运行过程中忽然产生了一个中断请求。此时暂停电视,对应于此时程序中断当前的业务,转而去处理中断业务(开门)。最后,中断业务处理完成后,再继续执行main函数while轮询中的业务。简单用一个图来表示一下
5 {( C7 w9 e! O
4 l4 v# H7 g5 w9 U
6 e/ b9 ?9 c( @; h5 i
微信图片_20231023163549.png

: j( J& t2 ~" C! R. x0 k4 S
中断概念示意图

" A6 B4 _) O# m: z5 ?) m/ F

& `& ^$ T; O+ S5 E, `1 G
根据中文参考手册的介绍,STM32F103ZET6除了一些特殊的中断外,常用的中断有60个,这些中断是通过中断控制器来有条不紊地分配执行的。
5 J: E" M- f% k6 Z9 h0 Y

+ K+ n8 p, {3 i二、中断的相关概念0 ^5 M# k( ?  [2 ^& e
2.1 中断优先级
4 u/ ]) v# `: p8 A; y
从字面意思来讲,优先级用来区分中断的响应顺序。当同时接收到多个中断请求时,中断控制器会根据中断优先级来决定中断处理的顺序,优先级高的会先被处理。如果在处理某个中断请求时又来了一个中断,这时会根据两个中断的中断优先级来确定处理方式。如果新来的中断优先级比当前中断的优先级高,则会停止对当前中断的处理,转而处理新的中断。反之,如果新来的中断优先级比当前中断的优先级低,则需要等到当前中断处理完成后,再去处理新来的中断。
2 A* i; W/ y* D/ F
5 H. G+ V3 ^/ a8 t9 d5 c
中断优先级有两种,一种是抢占优先级,一种是响应优先级。响应优先级通常又被称为“亚优先级”或者“副优先级”。当两个中断的抢占优先级相同时,用相应优先级来决定中断的处理顺序。如果两个中断的抢占优先级和相应优先级相同,则根据芯片手册中的中断向量号来决定中断的处理顺序。比如同时来了两个中断请求,在抢占优先级和响应优先级均相同时,中断向量号为41的中断会比中断向量号为42的中断先被处理。& Z7 I# m& e% Z  S/ Q- c- q
# }, a7 a% @* v3 y. J

' Q1 w9 U1 Y& E0 v5 G' L$ d! JSTM32提供了16个可编程的优先等级(使用了4位中断优先级),优先级分组可以使用库函数提供的NVIC_PriorityGroupConfig()设置。1 F, ^( l6 _  A" U7 m! j

  H5 F, c5 m/ J  Y0 e' Z: w9 \# m2.2 中断嵌套4 t' ?8 E2 \- B  o  e
一些低优先级的中断可以被高优先级中断打断,这种情况叫做中断嵌套。
; q3 a& h. A& ^! D1 N; O; c2 L
' Q% h9 q7 E1 ^2.3 中断服务函数+ n! m) V& s' O) y" e* S6 U
中断服务函数就是在进入中断后需要执行的内容。
( p! a0 j& N2 J/ M3 c- D, j$ b# T" R- f
中断服务函数有特定的函数名,可以在下图文件中搜索“IRQ”找到。1 F" T$ D1 j, A& V3 o/ z

' R/ J0 k$ u$ c/ e" W0 s( u1 X0 m' P3 L
6 f  o3 H1 e. ?( W  p1 c
微信图片_20231023163541.png

1 }' i5 c; R1 c
中断服务函数名
) h! H# n( v" K+ y- M

* O, f, z4 {: F
! E' }1 O5 R: T
2.4 中断标志位6 G1 U5 _4 R: W: Q1 |/ O
不同的中断会有对应的中断标志位,通常标志位默认值为0。当产生中断请求时,标志位被置1。比如设置一个串口接收完成中断,串口接收完成标志位初始值为0。当串口接收完成后对应的串口接收完成标志位会被置1。在中断服务函数中检测该标志位的值,来确定是否是串口接收完成中断产生了。每次中断服务函数执行结束后,需要清除一下对应的中断标志位。+ ~% \- `! @$ b5 i& }3 k. K4 _
: C# [4 c) D0 b  c  Q( f
1 V$ O" Y% F9 k3 C5 R
三、外部中断EXIT" E3 @% C$ X3 C2 M& v
STM32F103ZET6有一个外部中断控制器(EXIT),可以支持20个软件的中断/事件请求,其中外部中断的EXIT0~EXIT15同坐IO中断。
& B1 g$ P8 n) Q
# W4 B2 v! n: ~6 R4 b5 y  {
微信图片_20231023163536.png

4 W5 X1 |8 [. N
外部中断IO对应

0 Y& Y; @7 q( ~  r0 u9 F
0 \: o+ s& \' `6 r

$ |" A# ^, c% S& ?1 M% t
其他详细的介绍这里就不再说明。4 P# u, U2 ?% i' E

& t4 u$ m1 B1 i. B5 V( Y: A

) X' D; p  l& P四、中断程序配置
' a% }4 L% ]! V: [& l/ k3 V: J这里以配置PA0(按键WK UP)的外部中断为例,展示一下库函数开发时,外部中断的配置流程。关于其他中断的配置,后续使用其他外设时会单独介绍。
' v) A3 L7 ~6 D' i4 ]: I" r+ J! Y1 `; L9 q
) t' L, e' `9 O$ b1 q/ L, F想要实现的效果是,利用外部中断实现按下WK UP,LED1点亮。$ E2 i, z; a5 z: i/ f. Z

% r7 G% v- \% f# _. D4.1 设置中断分组并使能中断
7 u$ }! F+ t: u4 y' D: ?3 Q这里使用外部中断,需要开启AFIO时钟,设置IO与外部中断线的映射关系。; M& c" n$ S" O" u% A) C
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟
    - i' Z% ~7 O- E( k
  2. " @7 {# W, V( q( N' y, ~. T& T8 G
  3. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路
复制代码

% y% f- t; Y  A" [( x3 e( H! {设置中断分组并使能中断时,库函数提供了一个结构体,我们直接配置这个结构体就可以了。- ^2 A0 B# [/ n9 [, T* A
  1. //EXTI0 NVIC 配置) o7 G$ V( M6 A( k
  2.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道
    - j& g' }. g8 P' O1 G
  3.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级: u+ ^1 W# D! K  {
  4.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级
    : P* M6 |: \% V' w9 k. {$ @* @
  5.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能$ t6 H& T! z: {2 S
  6.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
    1 s/ x4 w+ @- @* P8 r0 ~
复制代码
+ v: e; o) g# I$ D$ I
需要注意的是,配置优先级时,数值越大,优先级越低。
6 z& r; a$ b( e3 D  G! d  b

2 U2 f+ y3 S) Z& e" x5 a6 J4.2 初始化EXIT

* L) S& g1 j% @; G# I" b0 B$ h初始化EXIT时,库函数也提供了一个结构体,其中包括中断线,EXIT模式,触发方式以及EXIT使能或者失能。由按键检测一节了解到,WK UP按下时,会产生一个上升沿。因此触发方式我们选择上升沿触发。
5 v+ F- j1 I, Y: S4 v
  1. EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT08 O& v/ E$ v# L8 d& {  ]6 Y* M
  2.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断& F  @# U5 ^+ \& B) ], o
  3.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发
    ! I0 I: o, ?+ w& I: X
  4.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能7 i3 t8 I$ E" z. O9 N
  5.     EXTI_Init(&EXTI_InitStructure);
复制代码
6 X# W% v  Z1 R: m6 h* D7 w6 A* B- _
整体配置函数如下$ B- F+ |- V9 a$ s
  1. /*5 A" |1 ?5 j- n. r3 v* R4 \. D4 d
  2. *==============================================================================
    # \7 [/ y2 W1 c" h2 J, I& B
  3. *函数名称:Exit_Init
    # E. n. j3 D3 B) H* @
  4. *函数功能:初始化外部中断
    " C8 l( b  D" S% ?
  5. *输入参数:无: S) @  M5 q, f7 j! G
  6. *返回值:无
    % `7 W: A1 `, I# g6 v: B! G# U
  7. *备  注:无  P+ `2 \. }7 J" Q
  8. *==============================================================================4 E3 b# K- m+ x2 j+ Q3 d$ A0 U
  9. */! x# S( Q% m+ p6 Q6 d2 W: }, _! N- Z
  10. void Exit_Init (void)
    # d' m: o6 G, o/ N: ]* p- M
  11. {7 G% }5 r- o% C+ l5 a) C- Y  q! W
  12.     NVIC_InitTypeDef NVIC_InitStructure;7 m- e- i' T$ \' {
  13.     EXTI_InitTypeDef  EXTI_InitStructure;
    5 h8 K* f; _! G
  14.    
    7 X( U2 K' K! |( H+ I( W9 o
  15.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   // 开启AFIO时钟1 {9 D! l' ^& }4 l7 w. O' j
  16. " c. m- s" y6 u, H% Y
  17.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);   //选择GPIO管脚用作外部中断线路
    - j8 P+ f' f4 u. i  _
  18.    
      p8 `: s: t# u2 U
  19.     //EXTI0 NVIC 配置
      ^+ B+ d/ I. b+ {' K! D
  20.     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //EXTI0中断通道
    8 m* T( T, i. v( W( W/ ~9 I
  21.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;   //抢占优先级4 T0 c2 {  ]; T* O; }8 v5 }3 A
  22.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;   //子优先级- M4 K8 e9 v0 j. E  E# x: o7 E# ~. B) y
  23.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能
    " u5 l, I* C4 a/ _4 V
  24.     NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器
    5 n7 P. w/ g4 J
  25.    
    4 Y1 \8 c# ?) O
  26.     EXTI_InitStructure.EXTI_Line=EXTI_Line0;   // EXIT0% h! n$ l) O% x% O( T2 p5 {8 x
  27.     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;   // 中断
    + j- N/ _; c( S; Y5 m7 S. u. v
  28.     EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;   // 上升沿触发
    & \" O  f+ U. L% E
  29.     EXTI_InitStructure.EXTI_LineCmd=ENABLE;   // 使能' P: Z1 b- r* q% l9 T' g
  30.     EXTI_Init(&EXTI_InitStructure);3 q' s9 R; `7 q. o
  31. }
复制代码
9 h' N0 O/ I( K2 O+ I* G- U" {
4.3 编写中断服务函数

. Y+ p- j- L- O8 E- Z7 [上面介绍了如何找中断服务函数的函数名,这里直接开始写中断服务函数。这里的中断服务函数比较简单,直接点亮LED1即可。9 o8 n+ K2 [! n( e
  1. /*
    # p3 k: c, P, a1 f$ X( H
  2. *==============================================================================
    ) G1 d* m! ^8 o% e+ \
  3. *函数名称:EXTI0_IRQHandler3 o5 Y8 _7 c* w
  4. *函数功能:外部中断0中断服务函数
      R  _3 R. M/ [5 _
  5. *输入参数:无
    & w: p$ m+ |: L7 j! p! R
  6. *返回值:无8 x4 @% _2 J% ~9 D. X- [* d
  7. *备  注:无
    $ s0 r" I5 y5 R" G
  8. *==============================================================================, ~3 O8 c& W/ l8 t: o6 l# N$ R0 q
  9. */! r0 C; g' P. X- ?1 @. T5 \- C6 `2 e; T
  10. void EXTI0_IRQHandler(void)" ^# E7 t6 J9 Y  X
  11. {
    * o5 [" C. J, B8 y3 U
  12.     // 如果EXIT0中断标志位被置11 U$ X) z1 _) o; x* p. L( m
  13.     if(EXTI_GetITStatus (EXTI_Line0)==1)
    - r* ^0 c. E5 g: q1 t( ?3 z
  14.     {
    $ p# O9 o4 H) n3 i7 D4 d! m
  15.         Med_Led_StateCtrl (LED1,LED_ON);   // 点亮LED1, D( V( S8 f, t4 N4 R2 ?
  16.     }! [( _4 Q! Q2 U+ A/ @
  17.     EXTI_ClearITPendingBit (EXTI_Line0);   // 清除中断标志位
    + V6 ^& i( D) }. l
  18. }
复制代码

6 ?7 E6 ?. ?3 L8 Q9 q至此,按下WK UP后,LED1会点亮。这种方法与之前的按键点亮LED有什么区别?之前的按键点亮LED是在main函数的while中实现的,而利用外部中断的方法,是在外部中断的中断服务函数中实现的。即使main函数的while轮询业务中没有按键业务,按键依旧可以起作用。- Z1 Y8 Z/ H. j+ H
2 ?/ F5 V3 J; V8 ]0 |

6 {6 F; E9 W9 t五、注意事项

/ ?, a, U! e$ m( i7 o; P% }% Y% l; m• 中断服务函数无需在.h文件中声明
' b8 i$ G. I1 x1 J  }• 中断服务函数中不要有过长的业务
, C0 ^7 K: [9 N) l8 s) x. `: ?, t• 中断服务函数最后需要清除中断标志位4 v0 _0 y8 A# [9 v' o0 y. w

# J  c% D' n+ X+ s$ O

: a2 q; }' B$ Q* H7 g/ N$ x9 Y转载自: 二土电子
3 _9 ]% l7 p% W: s/ {  a如有侵权请联系删除/ e- D! i' o! E/ M

! t! i  E( y* C  n+ w) M
/ C  S% Z4 a* s# w9 S
赞 收藏 评论0 发布时间:2023-10-23 16:35

举报

0个回答

所属标签

相似技术帖

官网相关资源

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