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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信4 z8 V  _8 i  b
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
+ z  H; A  A  f& {* ?  f$ f" J& b" J8 f. o7 }7 O, J0 M" }
微信图片_20240615192751.png # a- T! b, I7 m4 ]3 m
) o( b+ M& k5 p" c7 i
    CAN协议是通过以下5种类型的帧进行的:' D2 U. w$ D4 |, W* E5 K
数据帧
1 p# X9 x6 V+ N( e摇控帧, f/ l( t& U( |+ b# w7 s. J
错误帧
' X/ T2 e  f6 R2 D8 p6 }1 H过载帧
" W  X% x% r! y" a  w7 w. e8 s9 r帧间隔9 d# |5 Q1 \& s0 F! g4 ^

  z$ |3 w( [: z6 ^7 q( d
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。8 c- L7 H, F: h5 ^4 j4 a: k
9 l6 m) H4 R1 Y  a
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
7 g0 D9 |1 Q* P/ v- w: L/ [    数据帧一般由7个段构成,即:" Q: r# B# c& q$ h$ e) @. y+ l
(1) 帧起始。表示数据帧开始的段。& B9 L2 D: }0 D+ X  B+ M  @4 q
(2) 仲裁段。表示该帧优先级的段。' h: f- [* c2 c! j& z" Y0 \
(3) 控制段。表示数据的字节数及保留位的段。- k4 C% g* }% S9 m
(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
0 r% G0 F; B" c& V6 b5 b(5) CRC段。检查帧的传输错误的段。1 O% N2 z* I* [# A% h+ V( K
(6) ACK段。表示确认正常接收的段。
4 G) x% H$ l% ^(7) 帧结束。表示数据帧结束的段。
3 P; `& i! C+ K: k2 i2 V: }5 H
& C) x5 A) J# _7 R! Q( B9 l! l
    明确了数据帧概念,还需要理解一下过滤器的作用。# w0 O: o3 g$ X2 u+ g
6 C1 ^/ Q. j& R! S. L
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。' X7 [4 e# @, k& h9 m
2 t& z6 K) T+ K3 L. b: \
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:6 `4 i* T) n/ E  y  X
1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
8 q$ Q. Z9 T: b8 K& O' P2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位2 h5 p1 }% I; d

/ e; o2 C  \- v$ Y% Q4 Y
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
: E, i9 n0 d# F9 g0 K. K
* t( N5 ~$ d& {5 G6 I5 g) D
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
; p' @- r# L3 R0 |
: x+ x6 B$ t4 R1 P& W0 r( T
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。5 _# m' I0 f) E: ?# r/ j
! g! t/ i# o8 ]' x; n' K
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:. a; c9 R( d3 d* I

3 F! Q! y/ C  f% X$ ^  I/ I 微信图片_20240615192755.png & V. O- ~3 E, p3 k3 g$ u6 ?6 i
  r* Z7 m: j: K9 J$ b6 K
    在程序中就是:
) T3 ]$ {# ?  @* |
  1. //要过滤的ID高位0 ]; K+ e+ O" e+ H0 _, Y
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    " p+ j2 Y. Q* {
  3. //要过滤的ID低位                 
    ( u+ l4 A2 e4 E9 G) ?
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    $ n( z! Z/ e# r
  5. //过滤器屏蔽标识符的高16位值
    & {3 Z; @& ]3 v& C" i; ~% n
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    3 `5 |- l% O2 C+ l% q* f2 x+ q" i' X
  7. //过滤器屏蔽标识符的低16位值         
    6 `) J) d; {! A9 g  `
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

; R& d% H) J0 q( D: D& \7 b' y2 R    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。. b6 D0 L" r% G0 K& A( T8 o

2 _. }2 M. g' H
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
, }$ z8 B  D$ {. A; K
* ^6 V1 F: j( j4 s, z) R  B
程序思路
( [* r4 f- I$ V2 I* ^+ P( U, m' w    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
$ I1 J% J! C/ D* Y- X5 i5 Q7 v7 f  o主机:0x13146 m9 n8 r! W9 h( c$ U2 o
从机:0x1311
# |5 P9 G) w8 I8 A/ n- @% [, J2 I6 F* D  V  R3 Z
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
8 V5 K1 o) V; f( Z$ V
/ U  H( X; ]; F) y! q
% o6 `3 y8 c* i
相关代码
9 U* E" |0 O9 s9 c  D  j    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
( D7 A  H& l8 k
% \5 {2 o5 j5 W% j  Q0 x: J3 G  `
从机相关代码
5 X5 T" V8 b  ?9 w& U9 rcan.c文件:0 ?6 T  G- }0 N, `9 J
  1. #include "can.h"
    - L- H3 A  T/ S+ S8 R% a3 y
  2. / a) q1 R1 d' u' N7 h9 S- S

  3. / i( e# g7 Y2 n1 t3 F

  4. ' ], a. N" ^+ `& b
  5. % D2 U! K# E) B; o- S. O
  6. /* 在中断处理函数中返回 */
    $ |  K( \+ ^. ]2 N% t
  7. //__IO uint32_t ret = 0;
    0 [! z6 Y. f/ M- U9 Q* H

  8. , _( v# i  x. _
  9. 9 h8 a& J( o/ K7 g) N2 T; {
  10. $ r3 |3 x. Y- O: J6 [
  11. ) v% X& g4 V5 W4 h" n# Z
  12. //接收数据缓冲器
    , A+ V/ z( d- ]9 p$ z
  13. u8 RxBuf[5];
    * ]7 }0 p. v! e5 M# a
  14. u8 Rx_flag=0;
    9 [0 h( e4 O% ~& A- H$ @, b

  15. , \9 e' ^  o: b7 ?* L) s
  16. % o+ i. x; v; U) J& m! {, Z

  17. / j: `9 G  [7 W9 b- G3 a
  18. ( x7 |5 i2 U; ~
  19. void CAN1_Init(void)
    0 @& e: W0 X" y
  20. {
    , e% u4 \/ ?) X# v0 d
  21.     GPIO_InitTypeDef GPIO_InitStructure;- U' m+ L5 K! w
  22.     NVIC_InitTypeDef NVIC_InitStructure;
    6 [! w: a9 E  S4 n8 |. L
  23.     CAN_InitTypeDef        CAN_InitStructure;
    . k! R5 c; j8 H/ A
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    2 P8 C5 |7 `( S! ]

  25. 9 G, P5 U; Y* ^9 J- c
  26. " R" s2 d: O' c; h

  27. 3 _& t4 X: ?# k4 R+ r. d0 B9 f6 F

  28. % B) ]6 l) ?. ^
  29.     /* 复用功能和GPIOB端口时钟使能*/   
    0 h7 |6 ^* s" I( g
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     ( L: k& Q, d' [

  31.   _4 R) L8 P: _5 p- X8 y
  32. + P% k, \0 s  r" N
  33. 9 ?. j- M; E8 ]$ C# q1 L1 r
  34. 0 O4 S- z- F# s1 L6 n
  35.     /* CAN1 模块时钟使能 */' e- q! I* p* P8 R2 T
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);) X8 |: j2 ~6 R7 ?
  37. 9 ^, D/ }1 M6 }* h1 N' R1 o
  38. , o  O2 N! w+ t5 a2 K( N0 f
  39. 3 ^- L% z  H4 d
  40. - k7 r$ C+ p* x8 U
  41.     /* Configure CAN pin: RX */  // PB8- ~( E' Y1 T  O! q
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;* K( p& h  g2 i  }
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入+ o6 S7 t3 g: m; G  @* k6 {
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    : ~1 ^# w. K2 C
  45. # o8 Y3 |# \- Y/ b' A  \  n

  46. $ J5 n+ [, d, L  C5 l: n& F
  47. 8 P7 E7 s4 N# g7 ]) i  E5 B
  48. $ [& Y) K9 q$ z  a5 r  W/ W2 e
  49.     /* Configure CAN pin: TX */   // PB9# k+ z& d) d7 b) I. {" z% i
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;+ E% D% ?+ h& j; P7 m7 r" j
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    : t% {; j2 _# _) \" f0 z8 _
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    $ e2 u! B6 Y0 o& p  f  n7 J
  53. & ^( S# g- Q& [' i8 R  ~

  54. ; _, g6 |* b' e! ~+ }

  55.   v* X% f! n) l8 a: n: u7 I
  56. $ ?) m+ `8 F2 G
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O$ l! I' L* e" [+ M4 ]; B
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    " a- p8 K0 L" ?- `5 j

  59. ; {- M; B; V& i: z  \2 t

  60. ! x% _  b$ {# d3 C5 }# H8 I

  61.   P% ]$ W' l7 _9 P4 m3 M
  62. # O) u$ \/ D9 A7 D( r% w% W
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    6 i7 V* P) i. s! b3 s
  64.     /* Configure the NVIC Preemption Priority Bits */  
    2 ]. _0 |7 c, x$ q
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    " h3 \  a* Z  `1 A% k& k$ o

  66. 1 U( h+ ^: C& {) h5 B2 g
  67. 2 T* P$ Z" F8 r9 y$ C5 t/ S. F: r% p

  68. " ~, S6 O8 X# U4 `5 h8 B) M
  69. ) d- Z" W5 E6 K8 S" p
  70.     #ifdef  VECT_TAB_RAM  $ F* o# F% L7 I- o9 t0 @6 `' u
  71.       /* Set the Vector Table base location at 0x20000000 */
    2 I! C8 ^% B$ n; [, S3 m
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);' L; h* j/ x' ?
  73.     #else  /* VECT_TAB_FLASH  */
    ( ~; E3 R9 H8 e( ?( F. N
  74.       /* Set the Vector Table base location at 0x08000000 */
    & @: ~6 O  Q, s. N: S" b4 a
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    . v/ D) b8 Y, M5 J: S; Y7 m5 G' t
  76.     #endif
    + W" Y  G3 e# L$ B1 y0 b! n
  77.   v5 n# i9 L5 O$ O5 v( S

  78. $ |) g& Q, ^5 x) Q6 t

  79. ) e+ H" S2 d/ \% [; m

  80. + n7 {3 _1 P# d- T) t4 H
  81.     /* enabling interrupt */
    , K, o  A  R% c( y1 i
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    * c% ~: e9 n) g4 s) ?
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    ! N/ c, y. ]  E2 {3 r) x9 H* i
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;& n9 L3 z( x% \2 e  S
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    ; L8 M9 i: X* Q  |
  86.     NVIC_Init(&NVIC_InitStructure);
    * ]: q3 f9 y3 y6 \/ D6 J# @
  87.   s% U3 q$ Y) k0 @* f, Y

  88. " c" I$ A9 I1 l7 y

  89. 9 R/ L8 N1 n6 o7 t0 q
  90. 1 y& `, J- k) d) }: Z
  91.     //CAN_INIT();//CA初始化N模块
    / J% z0 ^5 N* y; X8 u
  92.     /* CAN register init */5 d1 m4 _3 ?  v3 o0 M+ m
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
      J! F5 D0 l7 c5 L: L9 z& r
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入  d; H, j2 w* Y8 r( l" Q0 M

  95. 6 ~% @, l5 ]# U9 E) N) Y: R
  96. 1 ?2 P  Q1 @  l

  97. - ?# a4 K' |: B# Q- |) `
  98. 6 U% P3 u. g: x0 s6 o, {
  99.     /* CAN cell init */
    0 n4 |: l5 X. ?# Z; C
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式, D( t/ {0 w; Q1 J2 w1 z
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理8 E+ Y9 {# A' m+ v7 E
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式& p5 {$ G' n$ B2 }- e; I$ `
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    : r0 t) X! A3 J
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    ) z- ]6 X1 g- o( n
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级/ U! X$ ~" Y/ C1 U% [# `6 R
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    : F5 P7 N# M- X8 f5 W
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位" j3 i$ g, @% H% l* z
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    ' e6 D2 r2 _& m) @* f
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位
    - g; N9 I" a1 n0 J! J
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    7 O5 k6 w# z1 x/ g/ W1 |* r
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    0 B6 w! o: t. @; Q6 H
  112. & h3 O" d, J' m0 @% g
  113.   R6 l9 o& y6 c) k% w

  114. * b7 _! N8 w( N, N& J) ?, J
  115. 5 _7 Q+ o2 t  d. G0 }9 I: ^
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据& p" ]) _; A2 X, V7 I* B2 h8 S
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1/ D7 ~* ~1 F' S9 a& w/ T
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    ; m' O5 K4 b5 [0 F
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
      s: F2 f2 \5 o$ p

  120. 5 o( F$ p+ p! d; Y1 r: _: q1 I

  121. # \- a7 e9 u3 Y6 P2 a0 |( @3 P
  122. ; E* _; p% X8 C1 T  R7 S& G: Q
  123. * ~+ n9 R; l: ~+ x4 _2 S
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    9 Z4 {  i2 m- y8 G
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    ! P. W8 r& L  }6 e6 E
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位  D3 w- h. P' I2 |# y& r
  127. " g) d$ G2 S3 b' o/ a! ?6 I
  128. & U; x; t7 z: H/ L3 Z

  129. & {9 \, A- }$ D% X. `, h

  130.   w* T% x- c5 e0 r( Y
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    9 B# e4 C6 \" x* \9 E* p
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值/ K0 n% i, [8 o1 D) y! ?/ @3 [
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    ! ^( s9 s- Z/ h
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    ' ?6 Z% V' {& ?
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器  L2 a! g8 `: |# u! o

  136. 0 Z% e' J3 r  |# }2 j* i: J
  137. % j3 P2 k- f4 P8 [. [
  138. # y# |- D& Q7 }' k# C9 V# g2 |

  139. 4 c7 Y! \& G  z0 h3 }3 T, z
  140.     /* CAN FIFO0 message pending interrupt enable */3 s. d& {8 K: h% t9 p$ U3 A
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    5 y6 ^# n3 Z+ C6 L& V4 t- f
  142. }  @" f% z4 e& n0 L; ~: D7 X2 E2 ~- C
  143. ) @7 g4 o1 F* i% N: ^2 e" a

  144. ) Q& U* B( F% F- S, [2 O

  145. , W5 |- A5 f  C
  146. 1 {4 E& i& |) z; ]& F* W; x+ s
  147. /* 发送两个字节的数据*/0 w5 n7 k! U% @/ ?; q9 v
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2); ]3 \; V* n5 m. \1 A0 Y
  149. {. g. [/ r( |8 Y
  150.     u8 mbox;
    8 p& @5 E4 o, B4 g2 X" D
  151.     u16 i=0;
      g9 Q0 G/ W1 m5 C! C
  152.     CanTxMsg TxMessage;  
    ; \, d0 W/ z1 t

  153. ! v7 ^  Z9 L- p& h3 h3 D' s

  154. ! k* w1 F8 s- j- G+ J

  155. $ }  A& e- ?2 H

  156. * K; |. u8 N& h; a. U: J3 ^
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x00; y- S3 T( }$ v& m; ?* X1 j
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    ( F6 i0 q9 N: |1 S5 N( h  e% M
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符. N/ T2 {9 z% q* ?+ K
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧6 [, J. u/ q2 x* R2 _
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    8 w  g1 ~) a( O# v7 u
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据( e8 K$ M' I! W" p& Q$ g
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据) \9 ~) l- P7 w! A

  164. 5 Q2 U0 e4 b$ e3 J3 b1 r4 o: H

  165. : j+ Y9 \; n, @9 @, u# y

  166. 0 D& s0 O- B5 r5 v$ D! l

  167. 5 P  o/ o9 i5 O; p# f
  168.     //发送数据1 v( n) f6 ~, O/ z7 `
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    . ^& u, @% c: `, T$ `
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))) [6 h. j+ Z* }' g3 x
  171.         i++;    //等待发送结束6 r: I$ u1 L) k
  172.     if(i>=0XFFF)
    . |$ m$ h9 J7 \8 d6 o
  173.         return 0;
    , K$ z* I7 R* T1 F  X/ k* P& `
  174.     return 1;
    , K# X/ D8 E$ K) h
  175. }
    ; v# o% q" D7 W  |
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)  C& C" y/ `. j: ?
  177. {% l1 m: j) ]( K% \2 r/ \
  178.     if(Rx_flag == 1)//发现数据
    & a& S0 j& {: L) M4 d, s. H
  179.     {
    2 K2 o9 X/ l" N: e* g
  180.         *msg1=RxBuf[0];
    5 }" a' h  C5 I0 \6 Y% T* j
  181.         *msg2=RxBuf[1];0 D8 v6 h  y+ P! y6 R, o
  182.         Rx_flag=0;//数据已经取走,可以更新数据
    2 e3 E# z" @3 n! Z; j- |
  183.         return 1;
      i! G" b; }0 ~/ P" Q
  184.     }else6 c, O! |' B0 c
  185.         return 0;. O/ M# v$ g$ X9 H* ~7 G7 l: q
  186. }7 z7 X  y7 A$ E( j9 |
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/
    0 s( h. h6 r" e# E# V1 Q0 {
  188. void USB_LP_CAN1_RX0_IRQHandler(void)
    $ |7 f. w9 z& w2 K: h
  189. {3 I- J5 v/ q) y8 v

  190. / O- G$ a3 j; J7 i8 u% j# y, ^
  191. * c' U) N4 j; n$ J+ [# {! E( c

  192. : U5 S7 h, u5 v" j1 I' n4 w2 L

  193. 2 @2 ]. Q) c' ^2 Z# V
  194.   CanRxMsg RxMessage;
    ) _9 x& k5 r" J5 M5 H

  195. # a7 e' ^. s% r' U3 F2 x; p% l
  196. % l8 d; V; B* O* j: z8 z/ b
  197. ( m+ r" P# b+ t; Q, E' J

  198. ) ]  o! c7 {: `7 w- P8 y3 \! ?0 {* N
  199.   RxMessage.StdId=0x00;2 n; D8 h- N8 l* E- j& Z; d- e8 x
  200.   RxMessage.ExtId=0x00;! D9 y+ l. u4 [0 ?
  201.   RxMessage.IDE=0;
    9 l: i- o: ^# l0 e( H) m
  202.   RxMessage.DLC=0;* n9 r* f2 T+ ^# u8 a( Z& U4 @
  203.   RxMessage.FMI=0;
    7 C- a' Y) m8 q3 H: v8 S
  204.   RxMessage.Data[0]=0x00;* x- w: N" P2 ?
  205.   RxMessage.Data[1]=0x00;   
    4 B3 T8 y0 C: O$ }; `; ~+ k/ W" J  h

  206. % E, J( ?, o) u) J* i
  207.   h0 P7 e* W0 r, ]
  208. ' x) H* z( p& f( x# _/ w
  209. 1 t1 ]+ d  C  g* N
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    ( n  o/ ?, I7 s4 ?

  211. $ [) Y, M7 r  i2 R% m7 u& S$ ]

  212. # I: v1 @  Y- T

  213. + \4 o* J6 l# S2 W
  214. . z* [8 n: g5 ?& Y+ x2 T- i# `6 o/ R
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    # I- o) W' C5 a/ }1 {
  216.     {
    ) D1 M2 L* @3 E
  217.         RxBuf[0]=RxMessage.Data[0];
    1 ~0 P. Q) {& a) g6 V
  218.         RxBuf[1]=RxMessage.Data[1];* P6 c& p( j( o/ w4 c
  219.         Rx_flag=1;//数据已经备好,等待取走& A( k6 C2 c1 _+ [
  220.     }
    , z, ]3 k  ]6 ?' Z8 _
  221. 6 C" m3 v' F3 p; B

  222. 3 @# r. n5 e  {$ d* f& h( T; s

  223.   [% P* [2 P3 ?. O0 s4 m9 d: ?

  224. 3 Y7 e! X, G" _( o  f
  225. }
复制代码
6 X: c8 J* V0 c. V& @% P
can.h文件; G9 D+ C6 _4 v8 G: X+ s2 y# ]
+ q3 U; g2 d3 a+ g& c' D
微信图片_20240615192757.png
2 d3 F$ j* H: f4 z4 ~2 H, X7 |" P7 P" Y9 i) J
主机相关代码
7 I# o, x3 r4 w6 Q' f% I    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。- S* `/ U$ Q0 {% t" F$ e
can.c文件:
% x, _6 q3 d& p& O% i
  1. #include "can.h"1 \4 j) ^& U6 l' _$ B4 V+ |9 q
  2. . C$ V3 |# J0 f. c
  3. * }5 ?3 c/ k6 H3 l  J7 T
  4. /* 在中断处理函数中返回 */) r; |! @# E5 z; K* j8 ?- W
  5. //__IO uint32_t ret = 0;
    / o3 c+ D9 f4 h! \0 c
  6. , j0 {7 h0 l+ y. P5 Q
  7. 0 S% g$ I& F3 C0 D# g
  8. void CAN1_Init(void)) r" m  M5 [; n: X( N% ]5 a. k7 A
  9. {, ~1 c1 v8 u) Q
  10.     ......//以上与从机部分相同0 p( s0 v4 V5 w% V+ u% G

  11. : _8 @6 n5 M; @# }% F7 V

  12. : V, `" T- E# l
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    . p2 |9 M) G# E) c: a
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为12 e8 Z% S- d) @1 A& |
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式" i0 O. M: f( i) r- b' ]$ G: o) ~
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位0 f9 P1 Y5 T& M, d* }. H6 Z# s/ I
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值  @1 O1 d# h7 S, Q# d& ?( S8 k
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    ' B- j3 v: p' c8 L
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值' L! r* L1 ~* z6 L8 P
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值! P! Q# e1 L: z' e- v
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0' U* i$ H3 A6 P1 S3 J% d& c. F+ d8 R
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器- B7 f6 u' d9 T  A! G  `& \/ Y
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器8 u# R  q8 {- a0 ?

  24. % v- g' k% z. W9 g+ _
  25. 1 f& R1 [' F. l* L. \( O; P6 @
  26.     /* CAN FIFO0 message pending interrupt enable */
    $ ?8 ?+ g- \6 X- G9 {$ F8 ~
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断, }( R5 F( j# T- H9 F* k1 p3 C
  28. }6 `$ H( f) @# x" m

  29. " v* t/ T' k5 \

  30. ' ?* ^- \7 x+ Y) x; w
  31. //接收数据缓冲器. R1 o8 m+ T- O
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    * \6 w" M3 Z# ~  [8 ?9 X+ u4 O
  33. //接收标志位9 ?- t" Z1 C: X- @: I
  34. u8 Rx_flag=0;! q9 \- g% f1 r. H" z7 q
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */* J1 I6 \6 M7 q1 Q5 H0 Q/ K
  36. void USB_LP_CAN1_RX0_IRQHandler(void)3 r! a) j* o; L# q# t" Y
  37. {* o: Y$ ~" S& F2 \+ P
  38.     u8 i=0;5 R4 e" E6 ^) c. K
  39.     CanRxMsg RxMessage;
    7 R9 s3 N3 D1 w

  40. 0 M+ `: W; Q- A$ w* n( t
  41. 0 o/ r# J8 I1 B' i/ R) O2 n
  42.     RxMessage.StdId=0x00;
    , `, T4 b0 N7 ~! Q, \' ?3 c
  43.     RxMessage.ExtId=0x00;, \9 ]+ X! I& k2 N) q; u
  44.     RxMessage.IDE=0;2 u$ Q# D# ^9 T: T0 }
  45.     RxMessage.DLC=0;1 k5 k8 f$ ~. S; G% e. @' ~
  46.     RxMessage.FMI=0;, R: I' z7 z5 \8 C
  47. . w; d. v) ^8 O( |

  48. + r+ M: P% p. R% e' f3 O* i
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    * E% c( E- y" `- R1 o

  50. / s) z" v5 W2 a

  51. : H  y; z: m6 f+ y3 a9 a) ?; g
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空
    $ V! A9 L" Z5 N" Q
  53.     {
      A( W$ ?/ A' |: e6 ]& `5 L$ u+ Y
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    9 Q  A% J4 m. |+ q/ M  v2 `
  55.         {
    3 e- Y2 C* C, d& c. @
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];
    ; o  l" X, X- T3 |3 D1 Z" q
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     ) h, G; w8 Y- n
  58.         }
    * U4 G5 e: o  i% n& d
  59.     }* U( J1 D* u7 M& O' Q
  60. : A0 Y3 p1 z8 L  s! O9 _

  61. 6 g: `- c- ]0 N  \
  62. }5 z/ Z9 K0 {& S. _/ m0 q

  63. $ c) I4 j; h9 A

  64. * X" W0 u4 I/ `. U  x
  65. /* 发送两个字节的数据*/
    0 Y+ p9 o2 ~) K) p; ?
  66. u8 CAN_SendMsg(u8* data1, u8* data2)" q3 ^$ K9 w0 N3 c; M8 Z
  67. {
    4 l8 p$ e# k' X% J
  68.     u8 mbox;2 N# x# n8 f' a$ J5 h5 K" e& F
  69.     u16 i=0;
    / ]" v9 ?/ H2 {. g( O) b0 `
  70.     CanTxMsg TxMessage;  6 L- k$ E. f) B5 q' m

  71. + {) P. R7 P. p5 {2 D

  72. " X# d. v# q* u
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    : T5 X3 @! n/ w' v* X; ^5 @! u
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    % j$ C  c0 X' ^  ?
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符% C1 l9 D+ A+ Q1 `5 q3 D/ \; R
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    * k+ u# p$ H2 @5 j2 U
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    # W1 C) }; i/ K+ E5 N3 T) `% l7 J1 w4 K
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据8 T3 M! x2 {4 x# H6 k
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据1 G' }7 e7 Z7 V: g

  80. % k8 _2 Z- F% v' Y& Z" T
  81. " C: G1 f$ g) K% \
  82.     //发送数据
    ! @, y8 T9 T6 j1 t: N
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  * O& v" A( b" l# c) Y& o+ \3 @
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))& N+ _, h+ o+ s9 N% M5 m
  85.         i++;    //等待发送结束
    8 K6 P9 ?& E6 K& `( D
  86.     if(i>=0XFFF)
    ) X0 v3 l& p9 k9 O
  87.         return 0;//发送失败* N" Y- p" {$ u" N! h! ^5 \
  88.     return 1;//发送成功
    ; m9 [2 x6 d  ?* s, a3 y  J
  89. }
    & ~* X# v+ I5 O( u* a
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    6 u" q3 K2 L4 i! _$ o( D
  91. {$ x& V3 F7 _& b# Y! t8 D5 M
  92.     if(Rx_flag == 1)//发现数据% }3 ~7 C' n# f* D1 B) u* q
  93.     {
    & ~$ v; S0 |0 |1 R* J
  94.         *msg1=CAN_RX_BUF[0];% K0 n2 l1 e7 Y; D: d
  95.         *msg2=CAN_RX_BUF[1];" L" e" @8 ]2 F; v: M6 x- d
  96.         Rx_flag=0;//数据已经取走,可以更新数据) G& r3 \+ s0 k
  97.         return 1;& t% q  i7 G- |& i1 ]
  98.     }else
    + M; L/ v9 g% G/ o- l$ e
  99.         return 0;, P8 A4 q) [8 i+ I! \/ D' Z
  100. }" v2 o, f! s0 J7 K- @$ P  f
  101. void Clear_canBuffer(void)
    1 q: T9 o! K! ]
  102. {
    2 \  U' A  K. F& F, l. j
  103.     Rx_flag=0;//清楚接收标志位
    , h) C5 D) ~! ?
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    5 }5 l' _. k5 h
  105. }
    . u" x% A& I5 N* F# O$ i: K
  106. u8 Check_canRX(void)
    / ^4 U% D+ j: g2 e
  107. {4 Z+ d; M3 S) M+ c% ^: N
  108.     return (Rx_flag == 6);4 W$ {0 B! j* c) q
  109. }
复制代码
. V0 ?8 D/ ~# s- P& r; K
/ h' ]' \5 r1 E7 j+ I. b
can.h文件:! r5 Y" V" Z, u( X+ `/ C
  1. #ifndef __CAN_H6 z; d  H) r; @; m  i. U$ F( x
  2. #define __CAN_H
    5 ~3 ^+ u! O$ V+ L9 a+ e
  3. 7 N  P5 i- _$ C+ x& d2 f

  4. % k2 G7 v/ n3 \/ A; k% d% x
  5. #include "sys.h"1 H+ x! u( m2 S3 P1 y( S/ c
  6. #include "string.h"
    + u5 |/ y0 H7 H6 W4 R, Y
  7.   ], l' i% r& Y+ x2 b) Q

  8. ( q! {8 p8 W+ X% q! l( Q
  9. #define CAN_RX_LEN          30          //定义最大接收字节数( D1 m6 n6 Y6 ^6 U2 Q

  10. . ^  t9 S( b9 F+ u' `

  11. ) p' ^' t. A/ P5 z
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    $ X" R9 B8 F& g* l4 _4 q! t6 x
  13. + U( O' s5 g" z
  14. ) U9 F3 T7 d- S. {) T
  15. void CAN1_Init(void);6 }- Y1 q5 t( [
  16. u8 CAN_SendMsg(u8* data1, u8* data2);5 {0 Y9 n5 X1 f
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    " I6 D) J; \' J' F! F6 ^/ Y6 _5 R

  18. 2 f  T5 z1 V/ C: o+ I
  19. 6 |+ Z5 `* x  C) f3 a
  20. #endif /* __CAN_H */* b. t5 y: R; M/ I4 U
复制代码

- I! i. C$ U* K$ I& A5 T/ R% ?! P& q2 q' s
转载自:单片机与嵌入式5 g" p$ x8 @' j" `3 I
7 W) z0 t2 j& B$ b
如有侵权请联系删除
7 X& y' U* ~  v$ U6 n, V2 Y' G6 e4 j5 m3 P0 W9 z6 ~1 P
% j" w( R; T5 z" l! w$ g
' n% I( m- R8 H( G

! Z* d* m% s0 s7 p
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似技术帖

官网相关资源

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