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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信
) s( _2 c" u0 t% H    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
/ W6 W" q5 d3 H; _( G+ E. I7 t% @$ c1 W$ |
微信图片_20240615192751.png 9 n( |0 Z% q& ?, K+ K/ j+ E
  }- K0 f  L) o1 _" }
    CAN协议是通过以下5种类型的帧进行的:- t* |( y/ E6 O
数据帧
9 f. q" k( g# f) m" o7 c7 V摇控帧" X+ P& @/ c4 c, c9 W6 `* X; Y
错误帧
( b! K6 h/ t3 R, S- [/ T过载帧
- ?; w" e1 r* f帧间隔! q+ I4 ~- T! R% {% D
* K# M$ c& w0 Z6 s4 g. A
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
1 [# ]5 }' w- t, B$ |) _& h' D! A3 {: {5 L: c# q
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。6 l7 F) m2 u! T, f7 Y9 l: ~+ K
    数据帧一般由7个段构成,即:
( s9 T7 @/ ]1 }+ [(1) 帧起始。表示数据帧开始的段。
- a  M" |, D+ V$ L3 q8 y& W& `+ Y(2) 仲裁段。表示该帧优先级的段。% S) I, t/ h: _3 F" m$ v- Y
(3) 控制段。表示数据的字节数及保留位的段。
& B- l9 `2 W2 J  v: j* [+ X(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。8 p+ v. X8 v! m$ S4 _0 J
(5) CRC段。检查帧的传输错误的段。
% a# @6 b! v1 L+ y% [2 T(6) ACK段。表示确认正常接收的段。* t( s$ Q4 Q2 [; y
(7) 帧结束。表示数据帧结束的段。$ }) k- C' Q! a" i7 z
8 ^( w+ _! C$ h. U: B8 u
    明确了数据帧概念,还需要理解一下过滤器的作用。" h* W1 P2 {/ G) |- }

% M: H" d! U: o5 P: n  b/ a1 L
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
5 J  h2 v. k, ~# ], R. O
; ~5 K1 r7 M, ^+ Q2 Q$ s
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:4 Y9 W, ]# j9 r+ e' H2 C! p
1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
, u2 M9 N, J. G3 i; B5 v2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
- d5 p& e! [( H: s1 q7 }6 J: D5 J  B/ `! B; ?# l; j) c" i
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。1 F+ N* Y  }$ ^' d3 V6 ]
; Q6 K# ^% V9 C) z9 f
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
! t; u5 e1 \9 T% p2 Z0 z3 e4 }" C! q: m) ?/ _6 T8 D& U; K) e5 N
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。
5 A; \6 x1 E* ?# Q  B9 E/ V/ N+ b  x
- ^; B" x8 s+ b7 ]  n" S
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
0 ~: o  k5 \3 L$ p  j% S
- T& Q& \9 a  Q9 F 微信图片_20240615192755.png 4 g. a; }9 U: ~3 n+ Z

6 e5 e- `3 @+ G4 N8 F; Y    在程序中就是:
# m' D1 O: r- X* \
  1. //要过滤的ID高位
    ) D) t3 R, I. s, m& C% k
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    ; j! n# I" p7 _. M$ ?& x
  3. //要过滤的ID低位                 
    : }& f2 A2 A" y! d
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    / Z( X5 G9 k* ?8 m8 B+ p5 u0 _, u- Z
  5. //过滤器屏蔽标识符的高16位值  y5 G' p% P, g5 j. h0 k& H. Z
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   $ }) J+ g2 v( i" E
  7. //过滤器屏蔽标识符的低16位值         
    0 u# @: t, s, z" N* J# q% ?
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

% W: b& C/ j% V. r9 l    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
/ n( O' s9 B( X1 [: @& E5 C; G$ E- E- V
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
: r7 ]% V8 I9 \# ^9 I$ I8 B- R; R6 p: D0 S3 l
程序思路
6 W9 @7 U. f  d# t8 y    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
+ Z3 ?4 {4 ^2 o主机:0x13141 R+ T- a$ G* T
从机:0x1311. c6 m2 L$ R3 C+ v8 \# m
6 I% R& R) w7 P  |4 K) X
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。3 K7 u$ c$ T& C2 e* k& {" F
3 Z' D- k1 X# j" F5 r
2 `, Q, E! [- `: N
相关代码
1 f# ^5 A3 a3 J: P* K    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
* q' s- ]( `. s6 I) c4 J6 S0 l; L; N% F+ U2 I, m) e
从机相关代码8 R  ?7 r' h, G
can.c文件:# o; U  l3 ^, P8 ?/ i3 e& U
  1. #include "can.h"$ B: J1 i; a7 b- r, C5 D

  2. 9 K$ |' K  O; D1 f6 V% Z$ F4 `. |

  3. 0 j  }( j: U( D6 S6 P( T

  4. . ]2 X4 R; F. Y% ?: ], D. H) }

  5. ( _5 h4 g4 O+ I2 F
  6. /* 在中断处理函数中返回 */
    5 X/ ^. _2 W" `- o" `3 m
  7. //__IO uint32_t ret = 0;9 ?9 [* u3 l! o1 Y- t5 |$ `: ~
  8. 3 O/ \& r% f; I* S9 h5 {2 D
  9. 4 v9 R" g4 h. c& V4 Z5 ]+ t! i

  10. 6 K  Y% c& H. s. [; O* ]2 {/ A
  11. ! }* P- j* b4 F) u! M
  12. //接收数据缓冲器0 E! d( l3 D* M4 Y1 q  `$ O
  13. u8 RxBuf[5];
    % E3 v: }7 p* R/ r& [0 j/ Q
  14. u8 Rx_flag=0;% G, J5 q: I0 a7 q  J1 W" F/ N
  15. 7 Y3 d# T- Q$ _0 i: E' n( B

  16. - Y$ y. h- a3 b0 V+ p, l
  17. ' P& k: {4 _& M$ w" K- Z  c) ?

  18. 0 D% Y/ f) I5 A6 f
  19. void CAN1_Init(void)9 V/ k4 C2 r3 m" T
  20. {
    1 l9 h  Z( q$ y) l
  21.     GPIO_InitTypeDef GPIO_InitStructure;
    ' [6 \/ H! q) G, S
  22.     NVIC_InitTypeDef NVIC_InitStructure;
    0 C3 a6 ]" z/ g5 x6 }
  23.     CAN_InitTypeDef        CAN_InitStructure;& A" |. }/ j; o
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    % r0 k8 B  V6 P7 D% x7 J

  25. 2 S, e' J: e. l! W" `( q# ?7 K

  26. ) y, I4 U/ w+ Z! Q( y  m* d

  27. . h* l) Q5 T( e8 L7 A) v

  28. ; C' ?  E+ w: A- }+ H
  29.     /* 复用功能和GPIOB端口时钟使能*/   7 R  X; V3 t5 n6 z4 @
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     % o6 ]: a& T; B: ^' Z2 `
  31. 5 B- L% k7 `1 f' I1 x8 f
  32. + I) S$ w* o! b. U( v3 t8 b
  33. , Q+ l, N* C+ }
  34. ( p4 }: g4 n, L( S
  35.     /* CAN1 模块时钟使能 */
    * {, c! }; k6 U6 \6 w; Z3 B, w
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    ( `9 r$ C# C9 b1 g# o: U" ]8 n6 ]

  37. 3 ?/ Q9 u( ^# h. D

  38. " N! g7 I4 \! B4 v
  39. 5 W/ M* V" z. ?. D& K; }5 Q
  40. ; y/ a0 g, r! \6 u3 I( {
  41.     /* Configure CAN pin: RX */  // PB8! j3 |/ f: p; }9 {  R5 D; h; J
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    8 v, i' _8 L7 y$ Z! @
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入5 X$ }1 O5 B5 x% i
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    / ~: S# M/ k- X- `

  45. $ n* @7 d2 n1 G

  46. % m" C2 L  g! \( A. `5 m
  47. * g$ Q) w: H& [, o0 K0 w
  48. % v1 ]& Z: W+ w  ]! M8 F  O
  49.     /* Configure CAN pin: TX */   // PB9$ d# ~  @2 X% L! P8 B- w% }
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;/ k9 ~0 B+ X5 D5 o
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出% B. d2 ]7 |- q! k- T3 M9 a
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);2 m: r0 f  x( F% M, T4 a
  53. ! G: g3 ]. P# B# h
  54. * W7 M' e  l* b; G( k3 P
  55. ( E- I/ N# ]1 y& E0 Z  @( _
  56. 3 t/ i7 T  A) V7 [, a
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    . ^' |6 y0 e) d' C
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);3 ]/ t3 P# D8 x/ Z: k
  59. 0 |% F# D3 R# i- Y7 n
  60. 6 K; \1 B0 `( `7 M

  61. : w3 F' w! L5 x7 h
  62. 2 O7 Q1 Q2 J0 w  h" a
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   2 p1 Z3 m3 ^& M+ z+ D
  64.     /* Configure the NVIC Preemption Priority Bits */  9 R" S( D& T5 V
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    9 C; f" y* Y4 [$ E8 I
  66. , L. l: P) Q( g1 G6 e; D" U! {% R
  67. ! w8 u& A' F! e

  68. " a( a! |1 k4 W9 z5 F

  69. ; r+ C  p. N7 F- C1 n3 p
  70.     #ifdef  VECT_TAB_RAM  
    . [% L; ^3 k  i$ R2 j: H
  71.       /* Set the Vector Table base location at 0x20000000 */; @+ U9 d6 r, d. V; U) J' M3 w
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);, c; E$ [; v3 E) e  }' M
  73.     #else  /* VECT_TAB_FLASH  */
    $ @9 k. W1 p3 C' \, H) f5 V
  74.       /* Set the Vector Table base location at 0x08000000 */
    ! ^% E% G. M/ K- D0 ^
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
      t5 _# W0 f9 ^2 h5 Z% ~* z$ \5 t9 S
  76.     #endif, z" L0 S) W5 Q8 B# ^
  77. ; ~, g3 v0 R7 n7 I/ {" S. g2 X8 D) I- J& X
  78. 3 b9 p. w3 f2 I2 m0 T5 N

  79. # b8 p9 F4 q1 d6 P, e! |) @; \

  80. " @4 `0 `4 m8 Q3 ?
  81.     /* enabling interrupt */- v% I; J2 L) |* X! |9 x1 `
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    # B. z5 |% M, B$ f
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;* A4 B4 Q' |( t1 L& k
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;- |* n( D9 L; p* A' E
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    . z$ q4 N" n8 i1 ^$ n1 X; O' M
  86.     NVIC_Init(&NVIC_InitStructure);+ G( N6 v( i/ Z+ D

  87. % m7 Z5 j' I' J8 g9 L  \* ~1 V8 I" \

  88. 5 m# e& `" o3 ^# H9 Q( o/ \
  89. / v, k  Q1 x* Y/ z! c" m2 Q
  90. + [/ h& K" \0 D3 z: d* L/ F  \
  91.     //CAN_INIT();//CA初始化N模块' Y2 p9 l3 T% G4 I' C
  92.     /* CAN register init */
    + R7 y$ U( y4 l- W
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
    # ?- ~! `; K* u0 h
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入( c* H1 L6 ^, I9 d! \

  95. # t: j" q6 k7 c' n' U# T: |

  96. $ V) J+ r" h$ ~" J  ^

  97. 5 J5 g+ K* R# @' h
  98. ! q2 K. `1 [2 T5 r4 j
  99.     /* CAN cell init */! h3 S+ u' A' r$ Y% q% l
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式7 t* W2 X0 Z, a3 W3 ]
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    & Z  E/ }' Y# D/ b- x4 G; D
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    ) m8 {8 r7 g3 f; Y+ @& }) E: J
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式9 Z- [0 }7 n. L. P7 T
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式6 g3 P' F" `6 ^$ G; Q2 Q  }
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
      @/ m9 C$ q; Z7 d% o3 X( U
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式: P0 L9 i6 s. a! m% Q9 R
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位3 A5 c2 X7 y' a* i# u. n
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    % U4 P& N3 i4 g1 P$ R2 I$ [; A
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位% C  T" E: M" K! j% ~  `) N3 j8 e, a9 _* R
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60# ~' Z  ?* P( f3 e, G
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs2 U. t+ o$ r" R: v
  112. " s& v3 U- J/ f( E6 c% O

  113.   @0 u' u/ M' k: u. n" P0 x$ m5 S# B  Y

  114. 4 e# n$ j+ ?+ P" ?
  115. , B# h, W/ Q. X" G
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
      W7 F& \6 X9 A$ b
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    6 m' x. [0 g8 r
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    9 M" t! W( p0 P! Y
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    . f& I# F* t0 \! b! f" \6 g. X

  120. # K$ ^2 H' v, H  g2 t+ K2 c! P- Z
  121. ' q, E! U7 t& t: `0 ]

  122. ( [9 F" I# }9 F1 I2 f# E% S; `) A' i
  123. 1 c9 o5 c- @4 b1 b8 M
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  4 ~! {6 E2 n) F) o' q* Y
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位1 H, o  Z1 }; X
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    ( p- h/ _4 N; x

  127. 4 j+ J1 J6 ^4 y# E) Q: G

  128. . |/ a! S9 Y* ^' ?

  129. # \" k9 I( T6 d- I: s9 \( u
  130. ; E- e7 ?. |+ @
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    9 H* P  a" v9 ~# X/ `! d* T' v- I
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    + I  w3 w+ E, O( M
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0+ `: ~4 [# _' i2 R( x" G
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    7 |8 t  ~2 O' X9 @% K
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器3 ]3 p* k( c1 K- z2 b8 }: O( a% {  y
  136. 3 ?) K$ |8 Y6 G. u! c, @
  137. 0 O, C6 `8 F" L$ ]! I3 n9 G) Q, g
  138. 3 M2 ~& A& R, ?

  139. & B# B  j1 ^4 u( g3 ^+ A. L# I
  140.     /* CAN FIFO0 message pending interrupt enable */
    & c. C. L3 |+ p9 V
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    & X. g. W- l, V  L2 N4 K" e! k
  142. }
    2 o6 m+ L! h! j7 H' Z
  143. . d4 i8 x* e; G% |% H& O, @" {

  144. ' |" w8 ?. I+ D2 q# A

  145. ' Q! }) N' D/ J; V  v! B

  146. " D6 f2 {# d8 G+ {7 L2 ~) e: s
  147. /* 发送两个字节的数据*/. N9 }3 W" ~/ y$ F$ j; s2 Y
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)- g  C. E5 A; K) G$ B# N
  149. {
    ) N3 |3 g, I5 r5 [
  150.     u8 mbox;( n5 m/ c  n3 s0 W* g
  151.     u16 i=0;8 Q% }, `) `- y" K
  152.     CanTxMsg TxMessage;  4 O' |- X) H) p2 L: X* Y
  153. 7 T9 r% r4 U( m6 ^2 u$ _' k) r
  154. 7 p! B* s. S0 D: }* c1 g& S& T
  155. 9 |) K( U. m: ]/ C, c6 q

  156. 4 \( }4 `& h$ m. h
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    . J, I6 t% |5 Q3 r+ H6 O
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    " {, A0 s7 n0 Z( U# E1 N- o- {
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    3 |, k% ?( Q. F& L) T! v
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧8 t; X1 e7 H/ f$ M
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    - U8 L& e7 b; ?
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据
    0 q) M- J# C0 X9 j0 ^# n
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据
    - X2 K+ l2 x  _1 X2 t& W

  164. 5 j* v7 u: v0 r5 p! x
  165. 8 O5 Z- h3 {$ j- l0 @

  166. 7 m2 E  D5 S- ?& E& s+ C1 V5 ^
  167. 1 O! f) V# ^; ]4 c" w& ]
  168.     //发送数据5 l. P- \6 D) h  `3 `$ d
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  / I/ X5 F8 V! ^( j. ?
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)): W& I+ ^0 }$ w8 D% Z
  171.         i++;    //等待发送结束, `7 F, x( x! `! u- c* o9 I  h
  172.     if(i>=0XFFF)
    ' a' ?1 G7 f3 N0 q
  173.         return 0;
    ' o% x; J0 E0 Z4 j
  174.     return 1;& E# d0 g, u- i& r: R, r
  175. }8 L( u, }. f8 I. z3 F8 E  Z
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    6 r* S& M2 B; y+ J) h& m
  177. {' P0 i& [9 w  N& @0 J; B3 D2 `
  178.     if(Rx_flag == 1)//发现数据4 q# E/ U" S) H  @) W% k7 M
  179.     {0 @; Q* k3 _) ]' C5 D; @
  180.         *msg1=RxBuf[0];- C, P- k0 a9 r. s- x0 r) _; _
  181.         *msg2=RxBuf[1];
    ' e- V+ u. F/ b0 _5 ?
  182.         Rx_flag=0;//数据已经取走,可以更新数据* E( T) F" p" J3 |4 d. n8 b
  183.         return 1;
    * _# E; f# o. {" \& Y+ ]
  184.     }else1 \3 M+ A3 }* V8 |6 N5 a: t
  185.         return 0;8 l# l0 k3 B7 {5 S. {
  186. }  a  Z; j( e* C; W7 ^2 U) a1 e3 }
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/4 C8 M6 L, Y4 G! y2 _8 q1 n+ D) U
  188. void USB_LP_CAN1_RX0_IRQHandler(void)8 u+ D* J% k( ~7 y( n) S
  189. {3 B2 L! I+ H, u5 L

  190. * r6 u) z, ~# `9 {

  191. ; x% Y& U3 b6 r3 ?" B

  192. " d. [! G1 E7 H1 Y! x* Z4 J' I

  193. + ?/ J6 p, o6 P2 ^7 \7 d
  194.   CanRxMsg RxMessage;
    ! n7 I) H& B3 ?1 u

  195. 3 I. l' A" w/ y* ~5 F

  196. ' N; W$ i! J! p) P. @
  197. 0 F4 t8 I0 b6 A" V+ A

  198. ' Q/ `2 s4 K/ R& ^2 J. }6 T; R3 b9 x
  199.   RxMessage.StdId=0x00;( a. B' n0 I6 ~. w
  200.   RxMessage.ExtId=0x00;
    % n) H; `( {4 k3 _6 Z1 X
  201.   RxMessage.IDE=0;3 i* Y: r4 ]) P/ y! }1 U- c# D8 |
  202.   RxMessage.DLC=0;
    + U. h4 `7 |# F2 |; C
  203.   RxMessage.FMI=0;: n3 E6 z7 S( B5 I: k+ |& M! q" R% x
  204.   RxMessage.Data[0]=0x00;7 u& X8 W" |" t, i& D9 B
  205.   RxMessage.Data[1]=0x00;   * ~# U" ?% K- E! L" j

  206. - o* M: j- o. ]* S5 C4 g

  207. 0 h, P8 B  j: |' V5 Z/ J# E6 y

  208. : ]8 w5 {. X' C4 Z+ W* m2 J

  209. & q7 U; }# t2 o: F$ p
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  6 B" j* k% I; U3 x1 \, y6 w

  211. ) R! N8 C; [8 g9 o

  212. " p" J! K7 U( Q8 t3 g$ W' u$ w
  213. ; {" ?) G8 O; Y$ V+ f: a9 Q. E5 d  X& ~

  214. / r7 e0 a. H( a: I. V
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空9 ~# z1 F2 T! {0 ]" g
  216.     {6 c4 G# {4 {. L; v2 U
  217.         RxBuf[0]=RxMessage.Data[0];* i2 ~# [- i6 |/ l1 G. N
  218.         RxBuf[1]=RxMessage.Data[1];
    ' J& _( z& [1 O, t6 X. W, h2 I4 g
  219.         Rx_flag=1;//数据已经备好,等待取走
    $ p. r. n" P) u4 ^( R+ b
  220.     }
    1 t; W. ^$ S- k; n
  221. & Q4 x7 D4 l0 d( {& B
  222. ! B/ G% f5 G0 Q! F) x$ H. }$ [
  223. . {# b6 G* f: Q; x3 O( @+ L+ `

  224. , T  g  h7 Y' }7 o
  225. }
复制代码

4 K5 R1 j/ e/ g# w' Dcan.h文件3 e. q! k9 B# G2 B* H" R
1 A8 u+ v3 @6 R  f+ \
微信图片_20240615192757.png ( ~8 E4 w+ w+ v5 U! c

' `4 S" |1 [' S4 l主机相关代码
! ^0 |  h' j+ y- {) k. Y6 v    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
$ `9 N3 L# p; P* x7 Acan.c文件:
: W: y" g" O( O+ ?. ~/ m% _( P
  1. #include "can.h"4 x7 x, n$ n# I$ \

  2. - q1 P; n& Y- b: l

  3. / s+ y) I$ ?9 H2 V/ W7 ~
  4. /* 在中断处理函数中返回 */
    ) C+ E. {4 @' u7 W4 s  i0 Q
  5. //__IO uint32_t ret = 0;: x( D0 z$ K+ d6 V) ]0 Q
  6. 7 w: [  m% r- C: Y
  7. 7 [) d. M: t2 o# u
  8. void CAN1_Init(void)
    0 D2 b5 e9 ?; c2 v8 P( G" Z
  9. {- [2 k0 a' C2 f. a6 X
  10.     ......//以上与从机部分相同
    ! z. p/ y, S0 _7 F0 H

  11. ) f' i. u  F/ e! l9 T& U) _
  12. + H7 ?$ m3 t+ t) ~+ t
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号! T; m- ]3 W! m- J; B$ j
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    - }8 ]. c9 b0 _% a
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    ; Z) Z7 E7 v7 O" L( g  A
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位* I! [, z# J8 {: Y& U5 n% Q+ h
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    / N9 j0 z! X9 p5 h
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值7 t9 h; j' v# ?% [0 Q& z1 f
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值& u+ V; d. E6 M. j: @
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    ; i# ?: O: W$ g! i
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0  p  X9 Y/ {9 a
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    5 P+ U. F3 W) x3 \( I
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    / P- a; ]7 |7 E) a- s

  24. , f9 C9 Q& v8 j; n
  25. 9 T* y: K" q/ O, q8 @& d7 {2 d
  26.     /* CAN FIFO0 message pending interrupt enable */' E4 l  h. ?# {) U5 p# q
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断$ W, d0 ?1 ~9 I8 P
  28. }
    + P3 g0 Y' J8 Y/ V' o

  29. 9 c0 A1 o- o6 y3 {

  30. " u+ M1 O7 v2 T( u3 }
  31. //接收数据缓冲器3 h6 N# }: j2 D+ H
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.5 o1 q  A5 Y0 ^$ G8 T9 {! C
  33. //接收标志位
    3 C! \4 t& z: m1 G, c( D. I2 k
  34. u8 Rx_flag=0;$ o( h" H6 d/ E) l
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    3 O; v! E+ E8 Q) H7 Y, T) e0 {
  36. void USB_LP_CAN1_RX0_IRQHandler(void)
    + i8 ]+ G5 f  _0 @5 k" O8 B
  37. {% a2 G1 K/ }* _. M; ~6 b! H
  38.     u8 i=0;2 k. p/ \2 s# f
  39.     CanRxMsg RxMessage;; D, \  g# b, j. W& P) |8 C! y

  40. % z* A( b1 @/ p' Y' R, s+ v0 F; E! Y
  41. 0 @' x& M" r! N1 m
  42.     RxMessage.StdId=0x00;
    , K9 N) K9 _- T* |% p  b
  43.     RxMessage.ExtId=0x00;6 |' ]( K) s8 M, S0 \# i& c+ d) n  a
  44.     RxMessage.IDE=0;+ l: ]4 d# D4 L" h' C
  45.     RxMessage.DLC=0;: e( a/ ?0 K) r7 \2 K8 R; n
  46.     RxMessage.FMI=0;  r' A! b& S7 }, F% \6 s

  47. 2 E, r; k: Y' z+ \. a1 r" }1 h: A
  48. 3 L" u1 H# B, s
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  0 V& s# T0 F. J( u* ?, W1 t
  50. . R& n0 ^8 o; R; z. Y
  51. - z5 p/ X) K2 t2 x9 M. r
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空$ T& b9 W+ q4 U3 W$ a# V
  53.     {
    # H! |5 @4 e0 ?$ S: `
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    0 E, X, G* Q( }5 @) K+ _
  55.         {5 f3 C1 g3 J1 U$ r$ j: z
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];
    ) R$ o$ c6 m; C
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     / I8 d  d0 G3 U/ t
  58.         }, m2 P5 H5 ^7 C
  59.     }/ Q' y" K* o" V* R

  60. ' U" c3 ?+ ^6 O; s+ Q" B6 S% u

  61. + m9 G5 d# I. w6 S/ X! B
  62. }6 H# h, M. z: ]* Z

  63. " l& b1 }! l6 d3 D, F
  64. 9 G1 Q( z5 ]& b
  65. /* 发送两个字节的数据*/' P5 d  X5 o3 l
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    ; o3 [9 A* s! d! i  x4 H" N8 Y
  67. {: W( w, p8 z5 O$ r
  68.     u8 mbox;' a% x: ?! o  e
  69.     u16 i=0;4 {, U+ ^  l; z* a2 `
  70.     CanTxMsg TxMessage;  % T/ u! ~: i; ]% B/ s$ e5 y+ U1 G& t9 g
  71. ; h1 R" q: T% k( |- j9 f" G. P% d+ h" @
  72. 8 D3 d' d! g  l- N
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    # e9 v0 N0 \) H! E4 V
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    0 N: ^: s  ]. a; j" N9 v# ^
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    0 B& R$ V' J* ?& m0 E
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    8 v( C/ K& s' }* x. b% H1 C
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    , D& T1 U/ \" o3 G, `6 f" t
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据9 }- r4 I+ C9 T: y& Y
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据: ^7 ?- }$ P. s$ l8 }6 v

  80. ) w: e9 g1 v: s, |9 j. N' e$ S

  81. . [' ~/ w3 j/ _  m$ ^
  82.     //发送数据% M* L) Y; B! D
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  + B8 V4 w1 u# f8 F, c: S  B
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    0 f* v1 [; ]7 z- ~0 V, t/ f
  85.         i++;    //等待发送结束
    5 Z6 c" y* J& `/ x' Y* G
  86.     if(i>=0XFFF)
    : M7 e6 o/ V) r* s; H4 D& y3 q
  87.         return 0;//发送失败1 l# [; {% o0 O# @3 Z3 I
  88.     return 1;//发送成功
    0 W3 q" B) M- y1 n3 I
  89. }, [7 K& E3 p% F
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    : G; w; W+ V0 K; |2 ^% q* w) i$ r
  91. {
    % ^7 ^1 f6 b" d/ i9 `: m. o
  92.     if(Rx_flag == 1)//发现数据
    - s' F+ t: G* n) S6 C
  93.     {
      m: M: j3 [" C, U& @6 y$ q
  94.         *msg1=CAN_RX_BUF[0];, w& [5 M4 b& q6 Z6 c: ]
  95.         *msg2=CAN_RX_BUF[1];
    9 F1 z/ k+ p, L7 r' z
  96.         Rx_flag=0;//数据已经取走,可以更新数据5 e/ H) a% n9 e: u% H/ h$ R
  97.         return 1;$ U, c0 ~. S! i- J' v8 K  q! F
  98.     }else
    & m. B2 b, ?$ X: a  ?. J
  99.         return 0;
    6 j, L& a# P2 Z; H7 Q8 u
  100. }* |6 Y9 \! C/ m, U& r* `
  101. void Clear_canBuffer(void)2 ]$ @8 ^' M' X; P$ R  E
  102. {
    2 E1 i0 r8 i; M' r; k
  103.     Rx_flag=0;//清楚接收标志位6 f) [+ N: ?0 F0 Z% A" L
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    4 F4 L& c- m2 |& H# _
  105. }" U) y4 B4 `9 @9 V" f% b0 m$ a5 K
  106. u8 Check_canRX(void)
    / k( W: W6 d/ l3 ]. X+ d) f/ G
  107. {& ^; B6 s. a4 \+ q3 y# O# F  N, N
  108.     return (Rx_flag == 6);
    2 T- R+ E& l5 d6 s/ h1 ~8 l$ O
  109. }
复制代码
  h: K, ?* h7 E% s3 x% q- r
/ F+ U, B% B* s/ T( I
can.h文件:8 d8 Q/ @& P; _
  1. #ifndef __CAN_H; B/ x& y9 ]* x
  2. #define __CAN_H7 i7 h# \- V( H5 Q0 S( A

  3. ( s8 B/ c; l/ f# x. f8 k* [6 y6 Y
  4. 6 U* S. y6 d0 r: m1 |3 V- ^/ u0 z' Y+ m
  5. #include "sys.h"7 d- Y( Z9 V  F! {
  6. #include "string.h"
    1 W8 Z: {6 \. h7 L2 \+ w- A

  7. / J! }' F: s1 b; b
  8. 8 `: Z* J% D) z2 J: D
  9. #define CAN_RX_LEN          30          //定义最大接收字节数
    / }' L2 D6 I8 n5 e2 U) M3 q
  10. - @$ G' ?' T5 B3 K

  11. - g7 Q3 u; z8 N; A6 n3 l
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符& N% ~8 u/ j2 X& D8 `& U6 b
  13. ) @9 |4 ~( ]  h5 O
  14. ' T3 `! W, ~' v0 W9 A  V
  15. void CAN1_Init(void);: [% ~* l2 }% x, ]5 G
  16. u8 CAN_SendMsg(u8* data1, u8* data2);
    7 ^8 ~3 f6 z8 F4 a" H8 Z- M" }' L
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);6 B8 \2 ~4 m0 Y
  18. % o) ?( N9 {: K1 a
  19. 4 w8 e. R! W1 i& X: G
  20. #endif /* __CAN_H *// x/ J* z  @" B6 `
复制代码
4 t( K9 L0 ^4 h# @

: Y& p. E# N/ i* }4 c& n' f转载自:单片机与嵌入式
7 _$ g9 t7 `6 G+ a/ h) f3 @+ ?  x4 R& }4 D7 X* r: S
如有侵权请联系删除
  A& I+ D6 G' p& V+ Y! d
# _( s( r1 f8 ~2 \9 Y" h- b: s, a' D0 h& H! u

+ f# X7 y: m/ n0 y/ C% Y! S
" _* f' h, @5 J, C, V
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似技术帖

官网相关资源

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