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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信5 M. m- h  O6 b$ Z/ z, e- \
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
2 `! L: s7 H2 ^. b$ e8 S: o6 F) |+ _% S
微信图片_20240615192751.png - T: g  J- i  B# V/ ]" J

& d0 N: {# b$ F    CAN协议是通过以下5种类型的帧进行的:
5 [  X# a" E' e# i+ H3 y4 a, @7 {数据帧, E1 D  f+ Y9 \6 Z1 K: w8 W
摇控帧! `: I1 z. \9 S% C( n
错误帧9 e/ L* |% a2 ~2 G- p& v* m, h
过载帧
8 S  X5 t' m. K# Q& A帧间隔* K/ ^# m9 h* V6 w: a
7 P- e; z7 l" ^
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
' K' J% E2 Q- J) i7 g9 ^2 X4 M# L
. ], C; L6 X0 F$ d( X0 s) a
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
9 T/ k5 R6 H* W) h; w$ M    数据帧一般由7个段构成,即:
( O# d+ n6 ]: D! }9 S( e(1) 帧起始。表示数据帧开始的段。4 F4 y9 P+ R5 z
(2) 仲裁段。表示该帧优先级的段。+ d! e3 @  |1 o3 }/ b# [
(3) 控制段。表示数据的字节数及保留位的段。
: m4 L( }, Y. e! e4 \- x8 Y(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
, R  o# V6 W7 V(5) CRC段。检查帧的传输错误的段。. b, u. L9 p# B8 V8 B* S! ~
(6) ACK段。表示确认正常接收的段。( {/ w( G+ V' w# `9 L( ?+ m
(7) 帧结束。表示数据帧结束的段。
" o. Z/ U! b  J: e' r; M8 Y- L' i7 Y6 \6 g, J
    明确了数据帧概念,还需要理解一下过滤器的作用。
& t( `/ A( w: H8 H$ h1 a1 m+ o0 j8 ?: M# g3 ^% z- f1 t/ d
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。5 y6 H$ i: U2 t8 p8 S9 l
; S5 z& I# Y0 Q1 I. S% B: C
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:( O; C( B2 j: B
1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位  `& T* V/ s1 t$ `6 v
2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
# _; ]6 b$ I' q4 h6 T4 L) K, `+ I& Y! ]% O
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。: k% J; U% v. X$ {

  C7 h6 K4 C9 d+ v' Q# g
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
( d$ R2 Y7 M$ C* x( T& f+ ^0 a7 R& P# a. ?7 H/ Y0 w
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。
/ V4 Q3 X- f# p# L9 c
9 Z  o, X2 V5 x' B% W! X
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:) S' G! x& z2 i/ {3 h# C& H4 [
5 ?% ?& D5 R3 b0 |
微信图片_20240615192755.png : |4 H2 T( h* B7 X

3 b% A7 E+ }/ u# o! J  s& V4 X3 i    在程序中就是:$ j1 ?4 u$ g# m5 i8 L
  1. //要过滤的ID高位
    $ ?" {( `! o2 W/ Z5 x8 [
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;    ~* j1 e5 @0 t/ G5 h
  3. //要过滤的ID低位                 
    2 D; A! Q* c# K
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    . D7 ^6 a4 f" w9 Z! S6 }
  5. //过滤器屏蔽标识符的高16位值# d& |0 ~6 ~' |- R3 p4 k/ e$ x
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   5 X( [8 D( u) }$ p0 |- F
  7. //过滤器屏蔽标识符的低16位值         . b9 z% [6 B- T( o# [
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
3 z7 f6 a6 G0 T4 M/ n
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。/ o; U6 b  a+ r4 i# ]* B
4 x# @& t7 {1 Q2 L4 l
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
3 E% V7 A  g9 |' A
5 u" Z$ i5 x1 W
程序思路1 {, t: P" i% V
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
8 g" ~; X6 Y1 R+ [主机:0x1314
. J: _8 X8 r; T, `) C! j; U从机:0x1311% s9 H0 B* k7 U( }2 T  ~; E# S& h

* m0 l/ ]& h* W# s2 s( t
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
/ o, H  o3 N6 _$ Y3 d* ~  M: t  f
" |% ^# v: E; A5 R  j
相关代码6 T# \* C6 h) g* G# W% ^
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
6 ^) j, l  H6 B0 H9 ?, b# m7 @8 m! F; L4 i+ ?
从机相关代码/ }$ S: r* e8 P0 y
can.c文件:1 F, j0 L% q- W( W
  1. #include "can.h"0 l$ o( _+ q0 T& x- V$ u0 T+ ?

  2. 0 [$ Z5 ^+ }& y" D3 v8 a

  3. , H4 C7 D$ [1 _! }
  4. 4 O! K1 l: ~% l' q$ f7 ~

  5. ! b, n; n, ]7 E7 ?: V; v, |- }
  6. /* 在中断处理函数中返回 */5 N# |5 R' r4 g7 d
  7. //__IO uint32_t ret = 0;
    - \5 f  N& E- f# I
  8. 0 G9 Z! S' G# Q$ b

  9. ' E9 k) X& S4 r4 z9 u
  10. 4 G3 h# L2 u- a  L: k2 K
  11. 6 k/ h! W: e) p8 K* g; W2 i1 j
  12. //接收数据缓冲器2 }( c' D6 Y; \- k
  13. u8 RxBuf[5];. u, @; F; {: R9 _# V" q
  14. u8 Rx_flag=0;4 f9 n) \2 V. k$ `- n: s
  15. 4 Z/ U/ U# `4 j6 _1 P+ E. J
  16. " G2 k  Q* l& v  _' r* m
  17. * K/ u9 S7 n; n% ^( Z: i8 |
  18. 4 ~4 U1 q5 z& M
  19. void CAN1_Init(void)
    + v" y- C2 `1 X' [
  20. {
    6 N; m+ W" d7 I2 A# C+ q! B, u
  21.     GPIO_InitTypeDef GPIO_InitStructure;
    & _1 M3 u' k- `
  22.     NVIC_InitTypeDef NVIC_InitStructure;
    $ v* ]  a# ]' b
  23.     CAN_InitTypeDef        CAN_InitStructure;4 \9 d- k+ ^1 ^$ U  x' `
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;/ G0 |3 ?# h7 o2 k# W& Q3 B
  25. / x* ~. o) S6 l7 h2 H9 M8 o

  26. * p+ H1 J8 b8 Z- k
  27. 2 A$ ?5 Z. C, r. p' l. P  I
  28. ; [+ |# ~* Q6 p" r, }3 O8 D+ }
  29.     /* 复用功能和GPIOB端口时钟使能*/   / F, A4 m7 P: M4 s% H/ F  E
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     ! D: C6 {# k; E

  31. ; b% ^2 [/ s7 q. E
  32. 9 z# o2 |5 v' E% f* a$ I) p+ \

  33. $ y0 }1 h7 }$ |0 f2 b) {0 |) ^

  34. ) ~5 H$ {: r  N& v) |- ?
  35.     /* CAN1 模块时钟使能 */
    ) ~7 b1 k( u  N7 j% s+ @
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);7 J- e: n- ^" i8 y0 t- P
  37. - H* A* |. [: f1 u/ E5 x4 D8 g: V
  38. . P. W; \! p. x, C6 o9 I7 s* m; Y$ z! I

  39. : A9 P* h! U9 W" S8 \4 [
  40. ) s0 y$ l7 x2 G0 ]3 H
  41.     /* Configure CAN pin: RX */  // PB8
    ' `# m4 c1 }8 @) V
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;* Q. j: C% H# m9 [7 t; u# \' n
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入- p8 }- Y4 B1 \
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);5 W$ @% f/ [" e* v$ m
  45. 3 V; y& w/ h+ K" X1 h; f! P
  46. 5 B; x+ ]. r3 l4 g  `: s8 g
  47. ; ]/ `# A) a9 B0 ^

  48. # N' K( N  N% Z
  49.     /* Configure CAN pin: TX */   // PB9) }" a5 ~3 g7 Z, Z. U0 n
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    ! {3 J& g$ X$ G* t) T) u5 @
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出! `- v; L; \( M7 m
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);. t9 J2 e# g( o4 e4 y% V, _8 y* {& M

  53. $ r* B9 u0 Q* _* B

  54. . f( N# S, U, d
  55. # |, X8 y1 [: q4 n. G8 n
  56. % X1 E7 }, P" P3 a5 K
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O; G$ a6 Z/ ~& @, {2 I) G; B
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    8 I& x( `2 R5 B9 x) q" w) O2 c6 a
  59. 5 q/ c! }- _3 s. ]% C( R1 E

  60. * f7 d% A5 q2 R
  61. 4 C% I( q, q! v

  62. 1 O7 t4 g, S: I# D9 ?4 g3 T
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    , }4 {/ ^. ^; g1 R- R' J
  64.     /* Configure the NVIC Preemption Priority Bits */  6 Q! a9 H; t, d$ |) N- q0 F0 t( u
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);0 n; ~* K. |9 y8 [  \* H

  66. : q5 _; c4 N! z* o) a

  67. % z* T4 G# }1 Q6 _7 u; O
  68. 0 L: A7 a  W8 u$ F: Y+ I

  69. ! ^2 u5 [2 e$ w+ o* `( a
  70.     #ifdef  VECT_TAB_RAM  
    ; J' @! D) L* E3 w) c
  71.       /* Set the Vector Table base location at 0x20000000 */
    ! L7 ^' o9 C" a$ V% I8 H  k# v
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    6 c8 ~" b/ c* Q! Z0 _
  73.     #else  /* VECT_TAB_FLASH  */$ F4 u9 ?2 N3 N
  74.       /* Set the Vector Table base location at 0x08000000 */
    ! V1 `- |" J0 p+ ?; S0 \
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   / M) k5 c5 K8 ^$ T" ~& L& R& o! I
  76.     #endif% f. s4 {' |( Z, R7 B

  77. 5 D% d) O: e9 w& K" N( H

  78.   L  e$ I, s9 x$ x
  79. 3 j$ g6 R0 g6 i$ r2 [: `
  80. " {0 A- M: D" |3 {
  81.     /* enabling interrupt */# ~. ^/ N/ h8 s3 c: f; t0 b
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    ' l( J  Z+ I# g+ F( z4 T
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    % Y) r7 C, |# z
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    ( t9 V! d" u, w; C# a! G
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    / _+ E# g3 h6 w* x" ?
  86.     NVIC_Init(&NVIC_InitStructure);. q6 o7 |: Y0 v9 o% y1 X- {

  87. 2 H7 @2 _# F; K. z; \

  88. : s! Y" \+ Z) I* c( Y+ \
  89. 6 P$ X4 G  S/ a

  90. 3 M. `( l" w6 h, v
  91.     //CAN_INIT();//CA初始化N模块
    " l5 T2 l3 N, u2 B7 T1 d) X5 U
  92.     /* CAN register init */
    3 g) x/ w. J1 q, \1 e- H
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值4 H# J. V5 i$ Z! s. v& g
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    9 P7 |* Y* A* B; `- y, ?

  95. . j. L* d& B" C& c% F

  96. / O/ }1 A1 S0 b5 |; }% f3 |% \
  97. . P3 ?1 f1 P0 D

  98. , _7 _6 E5 ?/ k- h
  99.     /* CAN cell init */4 M- g- c) m5 w2 a$ \
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    0 _# Z8 u9 _6 v8 h# U8 J& `
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    1 m- f9 d8 v0 \7 p. S. t+ d9 Y
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    ; H! X( Y9 n% @; j: a
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    ! A& @8 T/ `" X" y
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    3 \7 h4 W, O( Z9 ~
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级; X( v2 ?& [: X. o# x0 R
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    , A9 W0 B/ H4 ]5 m% X5 k" h
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    6 P1 Z5 S8 i+ o5 \8 n
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    + e  V, F! p  C. E( T
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位
    * a* V( A/ j3 k. b  n  B. Q5 q
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    ! f3 w9 z! _% h6 p
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs2 v5 v2 p7 K0 ?0 |% w+ s, p3 c: F. G

  112. # B  p# ]/ n: Z

  113. " f' f1 N* M1 W" U% s9 v1 G

  114. : c9 g$ w- d5 T# X- Z

  115.   d- V$ U' p. w' Y5 k5 E# I
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    ( d/ F+ D( `" X& k
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为15 ^- S2 n5 [+ N3 ~" F5 x1 H
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    & {% \# ^. o) o( U4 E
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    # _3 v7 M0 \5 L; a/ k7 P; y4 N* o+ j$ W

  120. / V+ T; ?+ i+ e* T4 n( }/ H3 h

  121. 3 W% W: g2 M3 v, x& W1 ]7 }! z4 \" W
  122. - t& N2 @* }' o) m% n  m
  123. 3 e$ |5 F# U- R' q" C; u4 o
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  ) s" j7 W0 U* F+ R* h/ J* R
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位3 H. e, L) i& X% r& _7 O
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    4 K) C+ O: J/ S/ a9 j

  127. ' O8 }. g  v, H8 {8 D+ A7 ]

  128. - r7 q6 F* Z' _8 V

  129. % l5 ^1 q" ?  V$ q; E
  130. 4 H- `0 p$ E" f/ ]5 t0 p
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
      {3 h$ o* r- H
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值, F! M: n; x! R+ w3 ~' J
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为07 O; B8 S; s, o+ s+ e) n/ {2 z
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    ) B$ I: v! `, y/ l$ y" j% q
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    " f3 u- R5 l$ n

  136. 8 F! ]8 n2 m( B2 m
  137. - X5 L" Y3 H3 r; w+ h

  138. : A$ f# A* I, Y& A5 w- {8 H, I1 A) Z
  139. ( f$ M6 \& h; S& @& G+ ?
  140.     /* CAN FIFO0 message pending interrupt enable */: F8 w0 R6 O- @2 ^' M) \/ C/ s
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    ; h5 J3 i1 K! z' x" r; a# b# f
  142. }4 N3 W) ?; w5 r
  143. 0 M; v( i: N; o1 H; U
  144. ' }& ~6 [' a$ R5 }- l

  145. & [$ b7 U8 ?0 B8 x
  146. , V# u4 v. H% Z3 j
  147. /* 发送两个字节的数据*/
    9 f9 f$ f* c4 s0 V+ k8 @. Y  J
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    ; Y% p9 [! n! F; J% U0 u
  149. {
    6 Z" U7 F7 K/ E' w; v6 |+ [9 X
  150.     u8 mbox;
      e% E2 w% E# ]1 g% |  z
  151.     u16 i=0;
    : ^, _- `" _6 g2 r) y: n
  152.     CanTxMsg TxMessage;  - U6 b( x8 U1 Z5 ~# c

  153. + z7 f" U; }: l7 x8 ~+ Q3 s
  154. 6 l" b% _) d1 f7 [

  155. - g, g* h* l) m9 S) R7 _4 \7 N

  156. ' [: U* w* k6 @! l
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x00: B, b) X$ J: m, \2 K
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机1 D0 t9 u, k/ b6 L
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    , U+ ~# y: i* x# |7 X+ q
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧; M" s4 y, N+ \$ C
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节' C/ C% r: x; U
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据: @! k9 ?7 t' A- R, C! Y" }
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据
    & ]( K! L# U4 F( D6 P  L7 ]& {0 S

  164. ) p0 Z8 K$ X& C# M4 Q

  165. 4 F2 u" \3 Q+ ~9 M# i

  166. ' ~! h- h. T; k7 Z) C

  167. & m) `  G. K, C4 S
  168.     //发送数据5 X# k9 Y2 _$ H0 Y1 K
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    4 g0 N5 K3 I' M+ u" ~- P" u; D' H
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))' l$ Q+ T3 \6 m
  171.         i++;    //等待发送结束4 a$ ?' Z6 t( d: W1 i" ^
  172.     if(i>=0XFFF)
    & r! F/ d% P* v, x& R. H
  173.         return 0;
    ; s0 y2 w. k  ~# E# c
  174.     return 1;
    5 ?4 I/ Z) u) B6 v0 v
  175. }
    * F, I/ ?4 W& J8 G2 Z* b1 f
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)) l2 p9 f+ e% r+ b7 b. u
  177. {) ^5 q' F/ g) v3 R) }
  178.     if(Rx_flag == 1)//发现数据
    . f) D! |3 F  v: R8 {0 K* y
  179.     {/ ^: s  _" v' }% i* `5 x& z
  180.         *msg1=RxBuf[0];( ?0 u8 w+ w: _% w+ \3 k3 {
  181.         *msg2=RxBuf[1];' `9 E5 Z/ C% j1 u/ o( |2 Z
  182.         Rx_flag=0;//数据已经取走,可以更新数据% l1 }3 Z" e  r7 Q# s. O- W9 o
  183.         return 1;
    ( E2 f6 G$ d  X8 K) X
  184.     }else0 V/ f5 [) x2 U9 _
  185.         return 0;  X7 G+ U9 n) p# c" z: [. k
  186. }; T( C  T1 \3 R- a( A' O) T" X6 g" z
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/6 o) F% s5 O- R
  188. void USB_LP_CAN1_RX0_IRQHandler(void)
    9 H* R' G2 Y& H% _! a- i1 ~
  189. {
    # p  Z; j' `0 Q3 y0 ], @& B2 ]
  190. ( p) a- ?7 A) t
  191.   x' O, P1 M6 e
  192. # _6 |2 y2 a  Y$ d. b) Q, E
  193. 7 C* Y% B' v5 G. C8 Y1 @; X: q' c. e
  194.   CanRxMsg RxMessage;- i2 i2 Z( P( R; n

  195.   S: H/ r: W2 z/ u# O' P
  196. 9 |0 W( D* A1 W' C1 S
  197. % T2 k$ a% r! b" R; [  s2 m7 ]
  198. ) _8 T/ w1 _) D: Z
  199.   RxMessage.StdId=0x00;% W6 ?1 y/ ]* X: f# I  J
  200.   RxMessage.ExtId=0x00;
    % M; |' W$ k/ I- Q( V
  201.   RxMessage.IDE=0;1 Y/ l8 ~0 o5 e1 I1 S% |
  202.   RxMessage.DLC=0;
    ; @  H3 u! [: G& ~0 I7 f, u1 q7 P
  203.   RxMessage.FMI=0;" d8 l8 f" F& n
  204.   RxMessage.Data[0]=0x00;
    & {" U1 e+ a/ z+ G% C
  205.   RxMessage.Data[1]=0x00;   
    * k( K8 C2 M, F0 X1 n- K6 U* E

  206. 2 j5 u$ D. G" B# q* L2 \; z
  207. 0 y* q7 e# J- ~" T0 e5 v) Q3 v
  208. ! S# Q1 P7 S9 }; K. M

  209. 0 Q% d9 Z) h# a( e
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  8 y3 m6 D! g  j, q5 n! w7 r' D

  211.   N& x& V+ V3 `5 _

  212. / @5 k. U; \% w& V: S  q7 n

  213. & H% g: U. x, r. u7 i

  214. . w# p; b( l7 ]& o5 Z
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    1 L# F  @9 W# g8 j5 ?+ L
  216.     {
    0 B6 O" n6 P) X+ Y' S  h6 R+ i5 g% U
  217.         RxBuf[0]=RxMessage.Data[0];8 z+ D+ o% A' V/ ?
  218.         RxBuf[1]=RxMessage.Data[1];
    + m5 `! S  O$ u
  219.         Rx_flag=1;//数据已经备好,等待取走
    ( u, o- n" U7 W- [! o* j0 m% Q/ j
  220.     }
    0 W5 x% M3 C, p! z, K9 _
  221. ; ?9 l1 P* Y) ~6 z0 J

  222. , v% N) \, o7 n( n6 I
  223. . p; o0 {9 ~/ B' D

  224. ' _3 r6 U1 o+ Y7 e1 g' h/ k
  225. }
复制代码

. `* B9 j0 ^8 F) Ccan.h文件
! T% o2 Z' U' e& |3 a6 Q4 x3 O: K2 f0 Z
微信图片_20240615192757.png 2 }- g# @4 q! Q7 t! G2 v

8 Z9 m+ ^4 q8 N) Q4 H# p. U主机相关代码
$ g; Y( ?6 J" S  Q. r( }5 u, `' X$ s    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
3 t9 U9 S! |( s: w# Q9 Tcan.c文件:
- x1 M; m3 V9 S# ?2 e" t
  1. #include "can.h"9 t/ ]" U" D0 p5 E) g
  2. 7 T* w1 }# J6 h5 u# G

  3. / h+ G+ ]0 O9 ~8 k: x* }; y
  4. /* 在中断处理函数中返回 */0 X; [0 c1 N$ F- k. z; }
  5. //__IO uint32_t ret = 0;
    $ I: H: l' \7 v4 F# g8 f  \

  6. . |: @; E$ J1 r5 r6 u% m

  7. 3 N. H$ m  j- W/ g
  8. void CAN1_Init(void)
    9 A4 B- H! c% H
  9. {
    9 x9 H3 X+ M% Q0 |
  10.     ......//以上与从机部分相同
    2 X9 H. o- z1 ?& Z

  11. ; c! t; a+ l( R& n) }. M

  12. ! L, T( p2 T0 s
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    ' q; y1 j" u7 b4 A4 K1 G1 \
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    9 Y4 R3 t3 Y+ q# E( Y5 ~
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式- S5 X! N' P# P9 p$ b" R
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位' e6 e% g, k" I$ b
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    ' E! e4 j  _; L* A( o
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    * h  Y; [7 s! P8 m4 ~& W
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    & E6 |/ |# g0 A! I4 ]. f, W6 M/ U
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    " G" c8 \7 b7 k
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0. N* f, U2 I6 Z6 a3 [
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    , Z/ U+ |( U3 p$ U9 A
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    7 e- O1 b  Y4 |" a5 Q2 S
  24. ) _0 }2 \0 e% O# \9 l1 q6 Q" t
  25. & o0 y4 k# d" S# f* K$ Z4 o
  26.     /* CAN FIFO0 message pending interrupt enable */
    $ Q, }9 W4 O3 g7 [1 V
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    3 u7 f$ D  u; q* v, \  A% \: G# f! i
  28. }
    9 R. [5 w4 d" ~( V, z4 c

  29. ' s% P0 Q4 `9 |5 ]$ g$ {
  30. # t2 V0 b, u+ E) P- t$ c
  31. //接收数据缓冲器
    0 x; x4 ^4 N( e0 q
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.3 \5 @) I% I; O( i3 {
  33. //接收标志位
    0 T9 b6 ~  S  C7 h% O2 w
  34. u8 Rx_flag=0;
    * m1 w. r5 P( [0 n1 C) L4 i
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    * l; @# s) N$ K& `( e
  36. void USB_LP_CAN1_RX0_IRQHandler(void)( M. \8 `1 o5 m0 c2 d8 O( w! R
  37. {; M- S8 W5 n# K
  38.     u8 i=0;* p3 s6 |' u' \
  39.     CanRxMsg RxMessage;
    9 @0 G/ ?# w/ h/ O0 S' `( A
  40. 6 R5 L, n, Y* J! P

  41. ' x) C  {5 N' B6 S2 S# `, Z. Q2 F
  42.     RxMessage.StdId=0x00;& i# T1 \) N* ~' o5 ~
  43.     RxMessage.ExtId=0x00;% z3 d. C! t8 f9 L7 n
  44.     RxMessage.IDE=0;( ?8 Q/ t0 L) r7 Y
  45.     RxMessage.DLC=0;
    - F. I" l- [# u5 ~5 j- Q' K
  46.     RxMessage.FMI=0;' a8 p, E4 Z: n6 O5 i% r
  47. ( n. `/ l4 f' q$ d& q# m6 \

  48. 6 M) ~  e# \- `7 ^; C2 N# o7 g9 X
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    ) |8 s- c7 N1 G; {: I

  50. 8 `8 r; R/ l6 U, T! \5 @
  51. : b4 C0 `$ L# X( D! r7 w4 s
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空# S5 O; n4 J9 G5 \3 `
  53.     {
    $ w: @7 r. o8 B! g8 u; K! |" d
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    4 ]/ g( ]; N  q) i  w4 i
  55.         {
    5 t1 r7 a# K' T, u
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];
    . V* Q9 ?! m" M+ q) q5 n3 Z
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    0 [! K0 ^7 }0 D# c" W) T
  58.         }  @% B+ i- \4 e. T/ G
  59.     }( h: \9 S. {1 z0 P) g3 Y* K

  60. 5 j+ K. I6 M3 r

  61. 3 c; b# c$ Y  m2 C4 B$ Y( }& v% a6 I
  62. }
    * b. ]: u! \/ ^3 \& a

  63. * R3 Q# U" W# P2 x$ A+ l3 [

  64. ( F9 l9 h# g. b  A* s! p+ y7 b
  65. /* 发送两个字节的数据*/* q+ o% E. A+ t) s* Z! h
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    : y5 r. o6 j+ B1 Y9 F3 G! s& t
  67. {
    : `: _) r$ W2 N* L# j0 K
  68.     u8 mbox;
      [2 Z: X& ?, O2 x$ D  @, Q
  69.     u16 i=0;
    5 A' |. D8 M& U
  70.     CanTxMsg TxMessage;  
    2 `* |4 ?7 \7 w
  71. 4 k& c7 x9 B/ S/ N) P& @% d0 y

  72. * A3 [  B& O) \& {- T1 T
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    $ ?2 D4 @( X% c5 }3 I7 t, o/ }' q
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    ! N, I# W; n) {& v) x0 N4 Q
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    4 C4 S6 J2 X  d
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧- L" p0 A2 ^; C- Y9 R
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节5 I% A6 K$ Q6 t7 o
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据& [. b9 D7 D+ R9 y. w5 C
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据1 x) o3 L) x2 x1 z/ _
  80. ( P; W! r5 n! t6 u( t. d
  81. $ _" e: l  g; x% D& P- J3 ^
  82.     //发送数据
    - h' j3 N6 b# E( W, v8 a
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  2 B1 d! W: F2 R8 F$ K" T3 K, ]
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)), Y& |& o( z' E
  85.         i++;    //等待发送结束$ o( ~( k8 X$ V
  86.     if(i>=0XFFF)
      `& n, _% t7 j& Q# S4 B
  87.         return 0;//发送失败; B" x: m0 A4 A' n$ e
  88.     return 1;//发送成功5 d0 m6 N6 a: Z9 B( v
  89. }
    $ |) p1 g* ~3 @: P8 x! L
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    4 ?* }  |, U$ {7 c5 }+ R9 f' {1 ^! |$ G& ]; u
  91. {
    2 r2 T" ?+ H& l6 n
  92.     if(Rx_flag == 1)//发现数据
    & h5 o7 E# G) Z9 Q5 w: p
  93.     {
    ) ]/ T" |4 |1 M) c3 Y3 @( _- q
  94.         *msg1=CAN_RX_BUF[0];
    * X6 i# K7 F0 S% d3 F
  95.         *msg2=CAN_RX_BUF[1];+ k: X5 W; E/ s2 @/ p6 }
  96.         Rx_flag=0;//数据已经取走,可以更新数据5 N0 `& n' I# |9 g0 A
  97.         return 1;# o: C- f9 M+ O6 i$ I, w
  98.     }else
    * g% C4 S' L: q4 `8 T4 l/ e
  99.         return 0;/ N* t$ Z( ~) B' y( M+ `
  100. }8 q! |, r# ^/ v& h' L4 G
  101. void Clear_canBuffer(void)- j$ R  F0 x$ \6 h0 F
  102. {
    9 g& k& i* h4 T7 W7 A+ p
  103.     Rx_flag=0;//清楚接收标志位* N/ q. G( S: C; C$ z2 Y
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    1 \9 ^; b0 c1 T" I6 a4 F8 q" ?( m
  105. }  [$ L# C+ n, s  M! M) @( ^2 K
  106. u8 Check_canRX(void)5 q+ U! N, r% I$ ^
  107. {# I' X2 t  c; B( j% z8 W
  108.     return (Rx_flag == 6);
    6 v7 L+ W% H. w8 U) x) H( C  K
  109. }
复制代码

- @: @/ }( L) n, ]7 p
) j6 |, F  e7 k1 j  h8 M
can.h文件:
. u( j. z/ t2 l7 P2 `
  1. #ifndef __CAN_H# E; d  {" M4 ?) l; |* P1 H
  2. #define __CAN_H
    7 ]6 k4 R) e; M1 I! p
  3. + Z5 d# o) C( `7 @+ K' a
  4. & \8 D" w3 [0 r  P/ v
  5. #include "sys.h"
    ! Z& I3 i0 z+ Y
  6. #include "string.h"& Y9 C1 }, Z9 y# y( h

  7. ( ?, v  j! E: K: v7 h& R. U) F

  8. 0 k% i& M3 ^. h
  9. #define CAN_RX_LEN          30          //定义最大接收字节数7 f/ R3 b" C3 K
  10.   r6 l" Y& q# m$ @1 k: z6 t

  11. * C" @" N- o1 y( J2 A& `0 s$ L
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    - s9 G/ I, ^$ Q2 J$ T  i

  13. . N' ~# |- V" U( z

  14. * R# I; h0 e; y* O' [+ l
  15. void CAN1_Init(void);
    6 _/ [; G& S, u% D" o! s
  16. u8 CAN_SendMsg(u8* data1, u8* data2);
    , K# P% t. z9 f
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);3 k) G) O, r+ g2 U$ v! w
  18. 7 h, A9 d4 Q( J4 E
  19. ; W$ ?- c3 K$ n5 Y0 H# L) T2 p
  20. #endif /* __CAN_H *// X) p$ A- H* ^
复制代码
! R5 K$ }" F/ `" R* i( e& ]5 C6 J
  H- T2 Y- b2 h$ i" y
转载自:单片机与嵌入式
* b7 C2 }+ m4 w( A0 R& [7 {4 i8 c( E0 i
如有侵权请联系删除8 F7 G* G# S6 c- ~

+ f: P" @, V# o; O: w) \7 B# O+ Z" T  d7 U: `

  U% V3 o. R6 p4 u2 k9 O& t( p3 e: R- }; n7 K8 O
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版