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

基于STM32F103做CAN的收发通信经验分享

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信
+ G: O9 `3 z- k5 k& }' x$ {; k    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
8 Q4 P; U5 f% `  Y
9 K$ {% \5 \- o 微信图片_20240615192751.png
/ I& {$ S  y8 {, W* o! F5 u
, U2 K; D. T# }% T    CAN协议是通过以下5种类型的帧进行的:4 W- g9 ~+ `, w9 \4 W
数据帧
+ X2 P8 J* I& e摇控帧
7 b; Z1 u: z" {7 N  H7 h错误帧$ }2 ~7 C8 n0 q% F1 u9 |
过载帧  W4 [/ B; p+ Q+ L6 s$ u/ i( o
帧间隔% E5 x3 P0 I% a% k  l: m
* l4 h9 D* r4 A" i5 b/ L& p- e
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。* s. J# O. ^4 J7 x% e

# N( A7 i' `$ B- f- s' q
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。: ?/ @9 ^- r8 c' a; E3 V
    数据帧一般由7个段构成,即:5 R7 w) C8 m6 k# N% ?3 g
(1) 帧起始。表示数据帧开始的段。" |7 k, I- T9 `7 I: ?5 `
(2) 仲裁段。表示该帧优先级的段。
: b  M) b6 k- K! L(3) 控制段。表示数据的字节数及保留位的段。
1 A+ K) O0 V1 ^6 f' M$ o( L(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。& _0 u: M& ?3 _8 F6 Z
(5) CRC段。检查帧的传输错误的段。
$ ^' R, o# S: a3 P(6) ACK段。表示确认正常接收的段。" Y+ X: c" a) _$ v8 b
(7) 帧结束。表示数据帧结束的段。- |4 R3 z8 P. f9 ]1 {( b. V9 H

# C) M' i  q3 j  l' {3 l
    明确了数据帧概念,还需要理解一下过滤器的作用。
/ F% E; D1 R: k5 Y; m# r
8 N/ \( c' G/ q9 g
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。1 Y% ~; z; v' r2 C8 I
8 @0 e% N; U) s4 f& O) O! p
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
0 L2 ?: J2 Q- k. Y; i/ C1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
: J  C0 b- `# H" K1 b  J) S2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
; M" }' a. U5 v) f
! i9 V' k* \! q* p
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。1 W3 B( o" F2 w- ~

8 \+ I  T8 O7 S6 o$ X: g$ [; ^
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。2 o3 Z2 Z) o* W8 R' P

1 b# q# ]8 L6 c2 {, w% p' p
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。/ Q3 e/ X0 e1 g1 V" }6 r

; v8 e/ A; ~- C- K( Y3 d$ k
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:  p, q. G* z: g9 Q

' y0 ^: ~% _5 [, x 微信图片_20240615192755.png * Q6 S9 ?, j5 V  C+ L
( _4 F6 G7 Z9 x& y2 M
    在程序中就是:) _4 h1 L/ [6 N: r8 Y7 Z
  1. //要过滤的ID高位- S- a) k9 K3 A% n
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    - M. j, Q  T/ \8 y* b! |. V" x
  3. //要过滤的ID低位                 % ^( m$ h* |' ~: ]" T
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;9 L. ~5 \; E9 t* D& G
  5. //过滤器屏蔽标识符的高16位值
    ) `, d1 {3 Z2 O: r
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    0 K2 @3 r1 d5 y  j
  7. //过滤器屏蔽标识符的低16位值         4 S( C5 I1 }( _; |, ^6 [6 {" R) @
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
. p* V' q1 u! s) p  n  C
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
5 O3 n( T4 y1 Z" p2 S0 O
# g) y! |/ l% i, v, [% ~
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。; E1 {& _/ S1 q
( A/ M3 `8 F& Q( E9 Z* C8 h4 Z
程序思路
$ t, F' r6 G* p1 d* f    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
/ \: f& K) r, p+ N$ h主机:0x1314
+ K# W# v8 H& \9 n! O$ p从机:0x1311
  _% L* z0 t; I$ [' y. Z
" O7 i& }: P% P6 i$ x. `
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。  J6 q2 W" B5 E2 x8 W; Z1 ?
8 `% e- @5 d4 F1 c: {3 W7 E( z3 D. z
$ p! W2 l' {, g+ b+ M! v7 n
相关代码
1 M' ]; g- L1 p, \3 r    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
' ^0 I6 ?/ r5 C& `8 s; F$ f3 ]; d, h# r$ x! g7 T  H$ H/ w5 |
从机相关代码
3 w( [! ]: a0 E# d  |( R! Lcan.c文件:  F0 ^4 z- w' U3 `1 k* V& e5 |
  1. #include "can.h"# P5 Z) T0 x$ r7 m& s2 U0 r  I

  2. 6 B( x0 V; d: \" m+ S

  3. ) g1 t8 x  v" c# O! W- }4 s% b
  4. ! `. I9 u& \% K! I6 x5 R

  5. 5 V: B/ p, ~5 D8 u) O4 Z
  6. /* 在中断处理函数中返回 */& t! g- p/ a% ?% }) m) b' j
  7. //__IO uint32_t ret = 0;! f3 ^7 Y, E2 Q
  8. : P) c+ _. \6 F( g
  9. : k5 E; J6 x; |. Y

  10. 4 L! O) Z7 F) w
  11. 0 |( i+ ^5 W' ^
  12. //接收数据缓冲器
    % \  g0 \, a! T. e
  13. u8 RxBuf[5];, W& `! B1 X- G* f0 E
  14. u8 Rx_flag=0;
    6 \! {$ ~' V2 K* h) O* t, r
  15. & X; ~6 x( X& P4 W" L' u2 O% q* m3 u

  16. ! A+ n3 _/ f  H( K: q/ t: x
  17. 4 b  h+ R$ h( ~, n9 i

  18.   s0 h8 l7 t' O, B/ \9 F, S
  19. void CAN1_Init(void)
    . H  w2 e4 U1 B  Z/ U1 X
  20. {( h$ ^$ @3 ?5 O: F: H  O# v( S3 {
  21.     GPIO_InitTypeDef GPIO_InitStructure;3 F7 w8 D: l# q5 V3 Y
  22.     NVIC_InitTypeDef NVIC_InitStructure;
    ) n2 }6 N- w9 r2 l- S
  23.     CAN_InitTypeDef        CAN_InitStructure;
    $ R$ \& H* ^0 P
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;4 D( B  p* N9 A6 [* m

  25. ; P1 r3 h6 V( S1 C7 N4 i
  26. 8 Q& t4 ^  a3 W

  27.   V. p# n2 [5 w) g! A  w
  28. # h! l- G% B0 O3 \/ K6 d2 {! G
  29.     /* 复用功能和GPIOB端口时钟使能*/   ! M( ^7 O( `$ p4 ~& v' R
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     
    - I+ W5 g& r0 @) m# F9 t4 r
  31. 7 t) ]2 A5 q! A! T( N' F% n

  32. ( L1 V# T4 U! G4 q1 |

  33. ( z2 x+ u5 J% |6 c6 m  I
  34. : E; u' U. v2 w: Y; g: x* a
  35.     /* CAN1 模块时钟使能 */( m$ q# u- D: n: i
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);. ^3 _) t: M2 J& \  o8 K

  37. 2 k% v4 q  X. I% d  x1 C

  38. # X; T  K, s5 F3 o

  39. 7 v. ?: b( i. M9 k$ |0 `  L

  40. / M' A8 Z4 k4 ~# c
  41.     /* Configure CAN pin: RX */  // PB88 C4 {* l, ~  n; G- E
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;5 S. E8 x( @9 f2 V4 P9 n% V
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
    ' K# {, c' S/ W3 V. R$ w5 C
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    1 v7 K( w% o/ f- ?) ~6 g/ \
  45. + |; O3 P' d. J$ \5 W" \5 }7 m8 d
  46. ' [1 Q9 d3 U6 N, ?& ~

  47.   r1 E" G5 k( n" c2 F) w" t$ f
  48. ( w. I% ~8 ^# j- K7 u; g  ?6 L) R3 K
  49.     /* Configure CAN pin: TX */   // PB9  N1 c0 }; e( A$ e" j- W: ~
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;0 D# O, `1 h  u4 X, }
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    ( F, T$ V' ?2 F( ?( Z( t
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    8 |" U! F$ R, y0 @

  53. . z# s7 n% `8 Y! q; e# ]: y
  54. , L# M9 h' A* z" o9 \- v) x

  55. ) o6 g* v$ n$ d- k. d1 L
  56. : m( Z" t9 ]  V0 t6 k
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    1 r) n; a8 A- v# e+ p: N; V* ?
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    . e9 F! B7 u3 T, ]
  59. 6 w* e) u6 ?& F( f, s, [

  60. * N+ {: y  e3 c; G8 ^6 V
  61. 6 s, I0 d- b+ U2 E5 ^5 Z2 W" U
  62. 2 }- f  Q% Q# j8 k) S9 i
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   ) Z, P/ ]+ C4 F+ x. }6 c
  64.     /* Configure the NVIC Preemption Priority Bits */  4 e8 I( z5 H/ }: K7 a7 v
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);) F( `  k: T1 i4 W/ L

  66. 3 w1 g$ G  R9 y% J7 z5 i5 C
  67. " `  w8 S8 P7 Q/ V1 f1 X* }

  68. 4 }) F, v0 x: X  S. Z/ E
  69. * v' E" @0 E0 G7 M
  70.     #ifdef  VECT_TAB_RAM  ) Y# ]/ L; s: @5 M8 \
  71.       /* Set the Vector Table base location at 0x20000000 */
    7 |7 V' a: y( T) |: L/ ~0 d- I
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    5 V! b' G5 d2 f' W6 |
  73.     #else  /* VECT_TAB_FLASH  */
    4 B4 h* L5 i% b- N" f0 u& t
  74.       /* Set the Vector Table base location at 0x08000000 */# H1 L& M# K4 V6 i+ g4 C
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    1 `% g. h/ Z+ c+ N
  76.     #endif. d8 n; m1 X" G* U
  77. " E& R1 y: Y1 n; x+ ~% d
  78. ' U0 A5 O# [, v' L5 p

  79. 1 J' k- U9 w) s2 o) b

  80. 7 K( N: V+ i: y$ z
  81.     /* enabling interrupt */
    ( Y4 Q" r4 E8 h# g& g; B2 `
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    ( B# w" m2 }/ ~4 _( D
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    - j5 ^; g0 H5 V( R8 y- v
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;. J; T' z# d& {# U! Z9 E5 u
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    2 k1 t) Z6 m# z! ^. \1 W
  86.     NVIC_Init(&NVIC_InitStructure);
    : ^! R6 r: a6 o5 u- P, N  ~
  87. 3 M' y4 G- U7 q* z5 w  n

  88. # e. g& |# a2 R8 F6 |
  89. 6 Y' @1 i+ _7 H- L- \9 f8 P

  90. 7 R6 Z1 _% X  [' q
  91.     //CAN_INIT();//CA初始化N模块
    , {3 e/ Q9 g& ?
  92.     /* CAN register init */2 f  |) B) S4 A& e: e, l) b
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值& t  y5 l! ]2 d: I! a
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    ) k3 L' x5 b' g5 M
  95. ) c% I4 S# _$ Z" g( B8 K

  96. 5 y8 A; ^  l1 v( U4 C/ I. y

  97.   [' N* M* L' q$ w
  98. ) \( H  h4 ~7 l
  99.     /* CAN cell init */, P" C( U' z1 S" j- Q7 T  i9 q
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    , a) {( Q. F" x! D0 C+ A# T: E% c. p3 R
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理5 R' J8 d4 \1 W# f
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    3 G0 s  M9 M% m5 X5 p5 }: d
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式; b. F: B& J; V
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式: H6 {, I5 r; C" ^9 Z
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级  x( z- S% Z7 b+ ^, C4 `, s
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    3 c7 ^) ?9 }& w# B
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位2 i: o7 E/ Q2 Y1 C0 p
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    / e0 X) c: V3 o1 V: L" U
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位
    2 h- A# }/ l, }& C
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为608 [$ g% H) q: P3 p
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    5 L' r  s* Z4 ]- @" q( |

  112. # q  B) w3 e" T" v( p

  113. . B1 J6 B, w" b, g5 p4 C3 Y

  114. * X: s  t6 a$ [+ q  ]

  115. , A0 z& _, z7 F3 F' y! @  `1 G
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    + l6 d& \8 i& ]1 U
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为18 O1 x6 N# f7 \' o
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式% k. s" M, K+ j( K# h. r" F0 ~. b
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    ! H" V: m5 ]  v1 P- _* Y1 o6 U

  120. 2 J; B' b6 J5 j! b: U4 _: M4 s2 r

  121. 0 [+ O9 b" ^  t$ h5 F+ l# E5 Y
  122. . M$ X9 `/ ^7 O6 h9 G
  123. 6 e! b' J. Z. @% M
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    ) G: I/ J4 }2 b. I( c( X, n4 b
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位7 I0 s, m4 n, c5 i
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位2 Z; l& ^- A6 S5 r: M# }

  127. 8 p5 t$ t1 f3 O8 O
  128. & W" S' S0 q5 L" p5 `& L+ I
  129. 5 b: I0 ^, r( v4 `4 W6 Q
  130. 2 l" C6 R* w9 h9 H. u
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    6 m3 f4 G, Q5 e
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    , I, i( p5 V2 f* Z" @. |( o4 E
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为08 o4 U" @, E, H" D
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    0 ?3 q  V/ f& b0 L0 [4 _
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器9 i% r# f4 p4 D# |! O, j
  136. ; q4 b5 Y- Q" [1 B6 K
  137. 5 z/ K- ~$ M7 g6 `6 b# K6 ]6 g

  138. 8 X4 b: E! i. A, r: t' i$ P# N

  139. 0 X# [7 s' O8 _" D2 C  T8 x" c
  140.     /* CAN FIFO0 message pending interrupt enable */: R8 G) B* W, K+ {5 M* a' Z, |8 Z
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    . X5 Y2 I5 j# E! P8 [6 t0 f
  142. }
      N* t& k1 h4 b3 d" c; \# c

  143. & H3 J+ n  F0 r! a
  144. 7 N. w) {% e0 ~, A8 s( ~7 X) @

  145. , L6 o; r+ u4 m' J) ^
  146. & b5 t" s# y' ^$ x8 }) S; h
  147. /* 发送两个字节的数据*/6 ~7 k; c$ ?0 q5 O$ k) p- Z
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    + ~/ X+ C" T. L& ~
  149. {6 ~0 e9 G6 S2 `$ C9 V
  150.     u8 mbox;! o; ?! O2 i% h0 ~
  151.     u16 i=0;+ ?* l' {* `6 J$ r; U7 G8 ], s
  152.     CanTxMsg TxMessage;  . n) u$ L4 }4 n, l' n
  153. 7 _5 k4 D/ P" d7 E8 z* s

  154. ) ?2 E6 m& X, Y2 j( g6 h  Y! k
  155. ; x  f. N% g6 w* m+ p" s9 C
  156. . C. ^% {+ M* S( \( B
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x008 W/ E0 k% p3 Z% [. \. y
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    5 u7 P% }( Q" d# c* a) V: p
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符$ b9 k% f+ J: Z" P. L( C! j9 X
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    / O& c; E% n: R
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    ; S8 g& o, K- O6 P- B& q
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据3 ?( n  B* w% X9 @: O* S! b2 m! \
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据( n4 u% i8 ^. {

  164. $ U, ~6 J: s. D+ |

  165. . S1 H/ Q  A  |5 I( h7 N2 o
  166. , O$ x8 C) I( I/ f  R+ ]) X

  167. 0 X) C! m3 h! k2 T+ u
  168.     //发送数据
    & w8 m2 H$ I9 G9 }: l& v% p( h# e
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  ) f& F7 i8 S* W9 @1 K
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))4 ?4 K& ]+ l/ U  O2 s+ l
  171.         i++;    //等待发送结束
    / p( `1 \, o4 A7 ^+ v
  172.     if(i>=0XFFF)
    . B- {& i- V4 r0 z
  173.         return 0;& ]; l4 L3 n" u- N& E
  174.     return 1;
      |* Z& C$ K6 E$ U
  175. }# J( ^3 X( P1 ^# x5 _" v
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    9 z, r5 X4 {: }- J' i, H+ [
  177. {
    4 J4 L5 ~- l0 k( G# v! l
  178.     if(Rx_flag == 1)//发现数据( d: L5 ?% C9 f/ C4 F4 |  @) s5 n
  179.     {1 X" Q. W* _' U# N
  180.         *msg1=RxBuf[0];( {7 L) Y1 w+ ]6 B9 o3 ?# S
  181.         *msg2=RxBuf[1];
    ; x0 N- \" @+ }  T4 N
  182.         Rx_flag=0;//数据已经取走,可以更新数据. Y9 ]  N( G8 k" ~* ?
  183.         return 1;
    3 Q# F7 Z7 }$ V% x9 k) [: g
  184.     }else6 s) J% D6 ^' q; s
  185.         return 0;
    + d& b/ j$ a* h8 B- c. t
  186. }
    2 v( i- F( F1 ]+ S9 r' Y
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/9 T% K2 p  T* |4 h, v
  188. void USB_LP_CAN1_RX0_IRQHandler(void)
    1 n  y/ u! J/ U( Z8 D0 B
  189. {
    ; x, F/ s( H$ K3 ]. W
  190. 1 s) A7 v( |, a% u: @
  191. 0 L; D+ s: r. Y$ Y' V) t
  192. 4 W8 A+ G( U" t- F* u
  193. : y" ~: X+ D: S; m$ x
  194.   CanRxMsg RxMessage;
    # O) ~9 r! |; @5 g
  195. ' a4 Z5 O: B. I7 _6 }

  196. 7 i5 [8 e3 W, S7 @

  197. - ^/ ~+ B& P# _$ P5 H$ _

  198. / v9 H7 o9 ^5 t. A9 }+ v4 _
  199.   RxMessage.StdId=0x00;
    9 n& V8 T) h1 f5 s) C
  200.   RxMessage.ExtId=0x00;& m( ^/ g; _  U( ^
  201.   RxMessage.IDE=0;3 j! \4 {9 M' m2 T, S; G
  202.   RxMessage.DLC=0;# ~8 q. L( `- z
  203.   RxMessage.FMI=0;
    2 x+ Z( O# t! ?; |, R6 v2 y2 u
  204.   RxMessage.Data[0]=0x00;
    , b* S9 a7 Z! X# m
  205.   RxMessage.Data[1]=0x00;   
      C4 p' k" f4 X. M( \, W. u9 D

  206. 0 Y% R4 B( o: \& Q3 O$ `

  207. 1 }# m8 F# g. ~% b' }: g2 M7 \  S5 E( M

  208. * r! `+ s/ \0 t4 M9 p$ n

  209. + ~! h. a9 r. C1 h4 G- f! N, \
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    2 r$ i7 q' [; I; N2 G% H8 w: e0 s8 p" j
  211. ) {& K6 o; [) L* |% _6 }# s1 _
  212. 4 _' U" K) b. a" Y' V6 D% ?
  213. & A0 m  }6 t) A% V( T7 R5 ^; T

  214. ! H+ f* o; L- n7 V1 y  p. ^
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    : n' g  w" P) _7 `. `: e6 ]/ ^7 B% p
  216.     {
    9 h8 J- s/ S7 _& e1 e# E% O7 y
  217.         RxBuf[0]=RxMessage.Data[0];
    0 ^3 w$ K6 d5 e) y  x
  218.         RxBuf[1]=RxMessage.Data[1];% O  n% u& ~/ e: w! X" j  s7 I
  219.         Rx_flag=1;//数据已经备好,等待取走: V4 L  A. H% g# S
  220.     }
    , K. @  @- R8 P* e

  221. ' c+ @8 z0 D( B: J9 W( m8 D
  222. 4 F6 i* G% |) c: g. m$ P: z$ T* n# b

  223. 4 u4 E- B: n7 y0 U1 M% W  E5 V
  224. 3 Q2 Q+ I  s, a  Z7 g
  225. }
复制代码

  M7 q2 T/ ~# lcan.h文件
  [5 e% a* L# q( Z, |/ |, U5 [8 L% o& N
微信图片_20240615192757.png
! T/ N( i3 |7 v, T: A4 w+ T, f- J
主机相关代码
! L. ~$ Z) M* c. f) q2 r    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。, r9 ^( k3 y* e( n5 A6 T
can.c文件:
  W* L9 ^- @" E/ ?  n; J6 b
  1. #include "can.h"
    4 a( r0 K) Y1 e

  2. * c- E+ F0 M* j# j- c; _

  3. : g; L9 Y9 E4 Q: _  U1 o6 f% |
  4. /* 在中断处理函数中返回 */
    ( m  \3 t8 _% |" y6 }/ i% R0 A' e
  5. //__IO uint32_t ret = 0;9 L) g0 D. h: E* p& W% M; U" ^, |
  6. 0 J) L. x. V& `  D1 r
  7. # g, i. H/ m- |  q6 ~3 Y
  8. void CAN1_Init(void)
    ) y, P. K6 T5 ^+ J  q
  9. {+ Q% I4 w. o9 O
  10.     ......//以上与从机部分相同
    - U0 H+ h8 |1 M: V

  11. : h4 H9 c. H0 i1 F2 x5 F) c) t

  12. ; d( s9 ^# H8 t
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号) A, c6 w4 |* j0 @0 D; p) {; x
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    3 E; w# }) v/ I' G! v+ G, c  j) i
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    ! C( S4 F  r6 J, D9 C
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    9 `4 c, Y, T# m3 n2 f8 \
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值, @1 W$ v9 U2 s) U" M' j" K* ?, a5 t
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值0 f9 X% V/ m; K( L  A2 F
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    " k) f& E, ^$ ?/ l
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值5 M0 W6 o! z+ j  }! x* S8 z+ o6 g" P
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为06 T0 e" f$ H. {5 _0 l
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    # M8 D; b0 l3 C* X/ j1 F& g
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    1 u9 y: Z( g* c- N

  24. 5 G) y" q; \7 x9 S' u- m

  25. - \' A; k7 z( b
  26.     /* CAN FIFO0 message pending interrupt enable */
    * S' i! {  Z; C4 s
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    2 b* B$ r3 E) _  ^' Z4 G
  28. }
    % w) w/ x9 ]0 ?9 a) M

  29. ' U" |" [/ O, a) {0 F

  30. $ |$ ?1 h  }, c& {, f2 T
  31. //接收数据缓冲器; o+ A# b* t% f' g8 Q* t  z
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.' E* B9 D+ A$ w/ F4 ^
  33. //接收标志位
    0 L6 w3 h+ n% b$ i
  34. u8 Rx_flag=0;
    $ e6 n5 p- v+ v! u" c
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */- P% A; J, n! D5 K
  36. void USB_LP_CAN1_RX0_IRQHandler(void)  y5 k% g- k8 r2 C% }& m0 k
  37. {/ l( u  C5 q( k( _5 ^0 c
  38.     u8 i=0;
    " ^1 M8 Q/ Q4 T: X! a1 E: q
  39.     CanRxMsg RxMessage;
    0 E( x. |& ^2 P5 q+ K+ N
  40. 8 A' w9 _: j$ n4 P& _: f# L4 |; v! w& q$ |

  41.   u$ M; p$ ~/ `9 s0 Z
  42.     RxMessage.StdId=0x00;! Y4 r/ {* ^2 }" W- E/ i/ Q! L
  43.     RxMessage.ExtId=0x00;* }' _% X+ h  `; p
  44.     RxMessage.IDE=0;; ]5 N* q; x4 r8 O
  45.     RxMessage.DLC=0;% x8 e5 |$ m7 w: z8 J% E$ K( ]
  46.     RxMessage.FMI=0;
    9 }  }( X" ?) F. e* X* V9 E) o

  47. ' ~) B' A8 y2 Q: u
  48. ; v. `" ~; K. ^% E! h4 s! G
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  8 R) K, u$ h/ ?. U3 v
  50. 5 h5 j3 Q7 e7 y+ g9 x3 S
  51. 2 x/ T) h% F7 E8 s- Q4 I7 o' a8 `
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空
    1 L- @' w) |) d  z4 P. f
  53.     {
    8 V8 B+ n3 T6 a  h. B) y9 S. D9 q
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据1 H+ V! J' A) U9 c$ ?
  55.         {
    * E1 s: [+ S/ ^3 X+ x2 T' E
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];- m9 b! b, q6 o( k6 `- c
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    8 ?2 |+ M! r& T8 i6 {
  58.         }
    5 i, G) J+ ]  g/ p
  59.     }  Z3 q9 p% b; \, o# v

  60. & P  ~; M; f1 I$ K  A
  61. " B: l# _4 N% \* J5 d5 x) Q9 Q
  62. }- g' ?' Z8 p  o1 C1 s6 d
  63. # `5 j4 {& N4 n( x; ?

  64. 4 ]3 q0 C5 r' W9 N: ~+ G8 T+ |
  65. /* 发送两个字节的数据*/
    + j+ J1 h" W, o& i, f& R
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    1 ?. a  C9 o, w; @! z
  67. {( d7 p1 a* b- D( O+ h
  68.     u8 mbox;; R/ {( U9 c  V5 c. r9 Z9 G2 a
  69.     u16 i=0;, f8 }$ D* P/ ?1 C
  70.     CanTxMsg TxMessage;  5 B8 Q1 @3 G& U1 g1 c: H
  71. , D* R4 T* O& G( A  w& R

  72. , A1 q- t6 L: [. j7 s- q# E" X6 u1 B
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    2 M* Q7 S) A# _9 O% p  j4 h: c4 [2 [# q  ?3 ]
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    " E4 W) N4 N  ~
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    1 I4 F, O7 F- W9 m* D7 Y
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧0 a# A, S8 N* S4 \! x' H* S
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    ' w5 V4 ?& T. ^' d
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据) U  }' j0 Z& _
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据( ]% a$ N5 s) W3 U
  80. ! D1 J" R* T, c% p+ m+ g. w' U
  81. 0 z2 S) c5 R4 w9 q* ]
  82.     //发送数据
    ! Y) [$ H3 Q4 d5 N
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  % |6 J6 M7 {( S3 E. t
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    ! J0 [; `, L( L+ D# O
  85.         i++;    //等待发送结束
    5 X5 q7 ~# Q1 G- E6 w. l& h
  86.     if(i>=0XFFF)
      D8 [( C: N! u  K
  87.         return 0;//发送失败/ G. J0 I" H" c/ \& ~) ?) e
  88.     return 1;//发送成功
    # _, T% F8 f5 P% z6 X
  89. }
    5 W" z& M) f3 V/ P0 [
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)2 K( S" e* [, Q0 F- G( Q) h5 d
  91. {$ i2 E/ `  o+ x% r( b( i
  92.     if(Rx_flag == 1)//发现数据% I/ w) E4 T# ~3 y- M$ D+ M: a
  93.     {) s: Y3 N. V1 ~6 @. \6 T! v* S+ V
  94.         *msg1=CAN_RX_BUF[0];1 q  y9 N. x. Y: z* Y' ?
  95.         *msg2=CAN_RX_BUF[1];
    : ]5 b( O9 {3 Z+ ^7 Z% C7 M$ @
  96.         Rx_flag=0;//数据已经取走,可以更新数据
    " ~+ D$ t( B: U  G1 z2 Y% [4 T+ m
  97.         return 1;
    % U% ]" n( z7 Z. q# a5 ]7 _9 z' c4 m
  98.     }else2 J* M2 d% T7 n5 c5 G
  99.         return 0;, f( ^# R# Q+ n% T7 U2 J% Q
  100. }
    5 }1 e# ?/ V# ^. O3 B4 {' J* z
  101. void Clear_canBuffer(void)
    8 ?) U+ l1 E+ b2 q# s
  102. {
    $ z: Y" J' R9 ]  }* V( |  r
  103.     Rx_flag=0;//清楚接收标志位
    3 u& G+ Q4 H0 u2 \( X0 {: `
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    3 k! T6 @$ j' a& W8 V# t0 c
  105. }
    ; ?8 z4 H. `: G( K6 n  Y/ E
  106. u8 Check_canRX(void)  G5 V! H. ^3 }2 N1 ^5 v
  107. {
    # }  E( h" \7 X, _5 a: g5 L6 w
  108.     return (Rx_flag == 6);; N  ]  X. Y" M+ i. M$ q3 z
  109. }
复制代码

$ v0 V! M2 o1 f8 H$ g3 T+ T) b0 I6 ^8 \8 }* f0 G' G
can.h文件:
. w0 d; ~6 C& |- J/ |8 H: H( W
  1. #ifndef __CAN_H' M! _3 m4 p) z1 {" J& f2 B2 F
  2. #define __CAN_H
    ' ~3 T1 Y  ?7 m5 y. M. Y

  3. 8 U/ ?& Q% D4 W' e# d1 U( O
  4. 7 p6 O* `( b' p. h+ i2 F
  5. #include "sys.h"
    8 Z) d6 v9 Q' ?, v8 {( R
  6. #include "string.h"
    6 ~$ r' e  a- t
  7.   Y7 ?. A8 _$ n$ o$ {5 |4 u3 g" C
  8. / I+ H- e( g) ]' z  R
  9. #define CAN_RX_LEN          30          //定义最大接收字节数
    : E3 B3 [, A7 Y8 Q2 H; t, @
  10. ! U4 d0 S6 _5 J0 M" N  p

  11. ( P+ q$ V' r, t0 T. @
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符4 ?- j  [. n( y1 s4 z) b
  13. 8 ~' N+ R4 K$ q3 B+ s, M# f2 E% K* O+ O- }

  14. + P) K- \; }( K1 k$ L, ~# j
  15. void CAN1_Init(void);
    ) |+ k- h2 _  P* ^3 s2 j+ [
  16. u8 CAN_SendMsg(u8* data1, u8* data2);1 ]; B- V$ s) O/ {* U
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    7 d7 L( ?4 N2 ^1 [
  18. 8 ~! N6 P6 E% M* o
  19. 0 o0 x; A1 F( Y! }+ B* l( L
  20. #endif /* __CAN_H */% Q  C; T, j% _. G/ g8 g; o
复制代码
5 `7 d( ?8 ?* a5 H! m) y: A
; Q# M# O; ?( u$ P; w4 I
转载自:单片机与嵌入式
  x( \* g$ ]4 @* i+ d3 V+ r3 c, N9 C9 @1 d2 N
如有侵权请联系删除
' E) P0 k$ k& [0 N+ c7 F
7 l  r3 V+ @3 R& D
0 |9 S. s* r, t$ w  e& X( V" M' o9 i* Y. \0 l

- `7 m2 |& D% H$ v) a. G% v
赞 收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似技术帖

官网相关资源

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