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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信8 o. m8 T# }: V, @
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
5 d* {0 p5 @  m# i+ A, W/ _4 K
, u% u& ]+ X0 l' c5 L. b- B 微信图片_20240615192751.png
6 E/ j. b5 M# \# p' u0 O3 m& d" |6 h! X5 F2 ?5 e
    CAN协议是通过以下5种类型的帧进行的:, X* [6 @1 f7 ^2 M
数据帧  G, j/ j. s3 j( w+ i4 f* ~; M
摇控帧
6 C* F7 d" P. M0 J错误帧
) y% p9 T5 H4 d6 Y2 k过载帧0 h6 E/ t; {2 j9 y+ `6 v7 a0 D
帧间隔
" D9 P, N4 D$ T) P: |; I2 O
1 z. [# N8 _$ u% q* f. ?) ]
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
2 R. {0 ^9 Z2 G9 S- @2 G9 A6 ]5 u7 m' Z7 [  G
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
* S$ E& g7 B7 W2 d) l) U5 g6 k    数据帧一般由7个段构成,即:( u- G. _3 C. s. }
(1) 帧起始。表示数据帧开始的段。7 L6 \& d3 L; n, c% E" X/ [7 d
(2) 仲裁段。表示该帧优先级的段。
" i" D! e1 [- i3 {2 I(3) 控制段。表示数据的字节数及保留位的段。
8 e& B+ _0 {. K6 I9 A, H+ h8 I(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
# t# B; e3 H5 x(5) CRC段。检查帧的传输错误的段。
! B9 p- ~" w: N3 u(6) ACK段。表示确认正常接收的段。
" \% n9 n+ a5 ^) J5 B3 B(7) 帧结束。表示数据帧结束的段。
/ T! M( J  W- Z+ W' Y- B9 A* d6 h- V& P
    明确了数据帧概念,还需要理解一下过滤器的作用。
* J: W( l0 I% b0 ~, l3 Q# A: k. i& `$ _4 X4 B" b
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
$ J* N+ b* i" c9 x% `3 J; I2 m  d
6 V7 h: Z8 ^2 b4 `
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:# ~3 G" I6 _6 ?0 Y5 \' {
1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位9 b- n! Q9 ]! {9 Y  [
2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位' P& z( n% F; e7 E' L$ F

: K; r7 Y1 Z8 C' v
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。/ ]% M7 x) i& e) d: O
; v! `& E) [! A  ?
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。/ M( p5 h* l+ F0 e6 G) ~
$ Z9 ?  J5 z. C9 \% _# K' I
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。% x! `, B" O2 D6 k, q3 H& e( _3 i
5 k; I( Y. `2 r) p5 N# I( i
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:" c" C# y- |/ N: s8 ?# N
8 i: N3 H+ G7 \% r
微信图片_20240615192755.png   s* s: W, g4 N4 N
) |: i+ o% c9 C
    在程序中就是:6 h- V' {9 p8 H5 y; ?+ Y; y& g, i
  1. //要过滤的ID高位
    ! [5 @  \' T  n- j
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    , G7 q4 a/ k- H6 |3 Y& w
  3. //要过滤的ID低位                 9 v$ B9 u! r; T+ m
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    ; s, n) e, K1 \. c9 l5 w
  5. //过滤器屏蔽标识符的高16位值
    " w: J' \- K4 W( N. V* W. p
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    1 o; u4 M& k" o3 U. C
  7. //过滤器屏蔽标识符的低16位值         
    + s' A4 j, D8 t. [
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

5 |$ _( B  V1 \0 l9 v$ z/ |$ T    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
+ X6 l* l5 R6 u9 G6 c" N" X
8 S5 J( k! [: a0 s1 |! j9 }
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。* P* ^& d8 P' o1 V* a' m
; i- a/ l. X+ |: _9 _% k9 e  m' d
程序思路- _& `( s' D8 O( e9 u& {# Q
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:' z) [+ S0 M, V; Q6 {: J6 i, p6 L2 n
主机:0x1314: ?7 t  w. }0 c8 o4 v3 M8 ~7 i
从机:0x1311
: |5 o, N# y6 I# W3 C. b6 Z% S
9 ^) w: I- ^  N" E/ Z) I
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。" ^% o( y! J* c  _3 s, W

! X  Q+ r! Q2 `, u- a7 U- b

" U$ _0 a$ }$ r  C/ S相关代码7 q, C: M3 q* p# l
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。  P- }( D" i! d# n) ^3 \

+ ~3 T5 X, ]) h
从机相关代码
4 l5 B4 y  ]' ecan.c文件:
6 k8 e4 m5 C9 P  W3 C; {$ u
  1. #include "can.h"4 `/ S8 L' k* p( l) V" s- j

  2. 7 a6 g% h! N1 f8 v. H9 W

  3. ; k- u4 D+ o8 I# \' [4 x
  4.   ?! i6 G  k8 J

  5. ! D. t& u9 _2 j9 C) q6 {
  6. /* 在中断处理函数中返回 */  C$ Z6 C7 c' c" |3 Q4 F) Z
  7. //__IO uint32_t ret = 0;
    % T; Q6 K' B( E* Z  t
  8. * c3 U& W$ E& [! L* q, N/ p

  9. ( A7 h4 Z) |. D( R1 a: t7 I, X9 j

  10.   c6 v- M7 O+ e! |% K
  11. ( ]' ^- U" h) g  o
  12. //接收数据缓冲器
    . E& w7 ?2 t$ d$ I  `9 c$ F1 c" a
  13. u8 RxBuf[5];+ ]9 }1 T0 x, ?0 X
  14. u8 Rx_flag=0;4 t/ X1 \1 K, Y/ P
  15. $ @0 x. g% {& R3 B6 V
  16. 0 x6 N0 K- O& ~& ^3 @, Y; P1 }
  17. 7 e: u: y# D1 h1 v  i! L
  18. ; m8 e" v6 M- Y! G& q
  19. void CAN1_Init(void)
    / L/ N3 O4 ?3 z9 M- w$ I
  20. {) S3 ?, B# `6 B7 h8 C! l7 I, _
  21.     GPIO_InitTypeDef GPIO_InitStructure;1 d0 i! K7 C. A
  22.     NVIC_InitTypeDef NVIC_InitStructure;6 \) c5 R2 W8 X! K3 V2 D+ D
  23.     CAN_InitTypeDef        CAN_InitStructure;, ~: V& V8 Z" c! }' c' P7 [+ Q' U/ H
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    9 b$ E; [, S* `2 ~9 M, {# f" i

  25. 3 E8 N5 F3 Z4 H2 }# _5 h# b0 I

  26. 8 _1 m" |1 A% p9 g) k

  27. 2 @: e% Y, [7 F+ x. K

  28. : `7 ~# y+ |- j
  29.     /* 复用功能和GPIOB端口时钟使能*/   ) A# @  d1 T' ^  A: ^2 O
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     1 t- [8 {# O6 s) O9 [6 P

  31. / w, d, X' o# Z& E2 d8 E( r
  32. + b: F0 e/ ?( |+ F; m" Y4 M
  33. ' A# v* t2 g/ ~! [2 [2 ]

  34. ; ^4 H3 A( N: n4 Z& N5 n9 q5 N! {
  35.     /* CAN1 模块时钟使能 */* P' x( S( y, \5 f9 u+ C
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    % w3 d3 q9 J3 j# X, b9 P# }, n
  37. $ p3 {* c; m4 W: ?6 r0 n2 v  n  z# V4 q
  38. : h' N3 d/ W0 j* q
  39. ! R8 M- v7 S7 g6 s5 E" x

  40. 3 t3 V$ l$ l. o& r
  41.     /* Configure CAN pin: RX */  // PB87 [  V  i  Y2 z2 o: \" C
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    * O5 E3 w8 h# \
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入) s) c3 ], P5 n
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);8 k8 Y: J1 j1 @* H1 N* K
  45. - [3 A4 ?, Z4 D8 P3 x* _

  46. 1 i8 A7 M* k& v& h" e
  47. 7 G8 f4 J6 Z1 ]* @7 B* I( K
  48. - @7 n% z. h" M2 h; E
  49.     /* Configure CAN pin: TX */   // PB95 D% q. o% h  q  a
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;/ e2 q' _0 ^/ C' Y( `
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出; G2 a' A# `( b( C# I  h1 c; W
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);+ M$ E- a/ j0 z" R

  53. # g  ~& C! \) v2 r

  54.   E+ w) \; T: X4 |. r" I
  55. ( A' m+ P5 Y% I) ~$ g

  56. / g# }$ S3 w% i- [. D5 Z
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O1 @6 g% Y: U+ z9 P* X- [: ^% Y
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    & w; r1 ], [3 T1 p% E

  59. 0 B% U# G! y2 y* K

  60. 1 B6 h/ B9 Q# a, V" O8 i/ ^
  61. + N, ~' O; n1 ?6 y5 o3 D

  62. 5 B3 x% w" c. p7 O
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    6 N+ |5 l# v* B' e7 y- R
  64.     /* Configure the NVIC Preemption Priority Bits */  - }0 O4 S( M' E
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    & G. Q, ~1 ]3 W# @  X+ q5 {& j" B

  66. 3 A8 i7 s: l  \! N) Y
  67. " }& w6 M" M5 D6 |
  68. 3 Y5 `  `0 p1 M5 Q% a+ r  d0 B

  69. : @+ [( \, N+ Q2 U
  70.     #ifdef  VECT_TAB_RAM  ; ]- a2 C( s9 H. |7 }1 l
  71.       /* Set the Vector Table base location at 0x20000000 */! q. W4 b4 R2 Q1 ^
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);( M) @' {$ R4 Q& P" k9 j% f8 f
  73.     #else  /* VECT_TAB_FLASH  */: d, n5 \: w2 x5 m" \! x
  74.       /* Set the Vector Table base location at 0x08000000 */& _& B7 B; u* M6 i
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);     B* N! u, G% n6 e' a
  76.     #endif
    * r; R* z9 c! y+ Q% w

  77. 0 g$ y' T1 u6 R* Y3 l3 M

  78. ; E8 c/ j" l( h

  79. ) _: v7 w) J  ?% M. D7 R

  80. ' l, {+ z- ?0 ?5 C. K. E
  81.     /* enabling interrupt */
    ! h& j% r6 B: o. w; `
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;. o& t7 @7 M. z
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    0 b' {2 y5 a; J& @1 j1 s- g% A8 O
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;9 r' s, Q0 L; t8 F
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    ; T4 ?+ w* ?- |& L  f9 h& ?
  86.     NVIC_Init(&NVIC_InitStructure);
    5 P( Q; T: V- ?- Y3 `9 H
  87. & Z+ ]! s0 h' Z8 L- J% c4 Y
  88.   J* K! Y( I% J  r
  89. 6 H6 q9 r7 a1 e/ ]# `
  90. ) [6 A7 ]9 ?$ [, I$ b- y, V1 J9 V
  91.     //CAN_INIT();//CA初始化N模块
    % _& C( A# X* E+ T$ Z" Q; ]
  92.     /* CAN register init */
    2 j5 v  _/ n4 x* j
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
    - H6 y% F% u  t& C) z
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    8 F% V& z( d4 r) b2 z/ t
  95.   O6 s1 H% |0 O' i, A

  96. + X$ G4 v6 i: }) m" T
  97. 5 M. q& L3 f/ K3 M0 y5 p  W  h

  98. 6 a3 Z6 N, p/ _/ i
  99.     /* CAN cell init */
    9 P, J8 ~& t% ^4 j6 B
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    . N# D' f/ D( Y* b% t0 A5 H% Q7 i
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    ) M* r8 F& y$ p7 {# k* [4 s1 g
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式  ^9 D* W4 a0 n" W9 D4 k; F6 P1 S
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式; U; V: y/ @6 r2 v5 i
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式2 {1 m2 ?, }+ |" _# H( A! g
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级' B+ P$ w3 n; S" v$ ^. ^4 L
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    + o; L. W* T0 o! L- p
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    9 a, I+ G6 m  {/ i6 q, l
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    ) ]& o; E7 j5 b
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位% N+ _+ H" L; K
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60$ @5 \2 J' Z2 w5 h" O! g5 P
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    2 R* k. {0 a! w- k
  112. + _: Q7 d& ~2 u
  113. 8 a: F3 `" c% {# t3 Q) [; k' G

  114. 0 E& G" H& |+ I) o7 x5 |

  115. 4 c9 f0 N. w6 ?" N% g' F
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    4 M% M. L3 p. T( n
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    ' i# ^( E1 }# r4 i8 r
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    5 W  d* S0 B9 @+ C
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位* t  Q! p, V  [6 O- {$ O/ T: _

  120. 2 V& A. g" i; [7 M

  121. ! L" o8 s8 ]1 U$ T
  122. * q7 }4 e8 l6 L5 B' C% s

  123. / J+ H+ A9 k3 f
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  ' Y8 u. f# ]9 k% O  t. X& b% ^
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位0 b: t) B- C3 I; E
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位( b- G! E& C' w
  127. 3 A# p& Q2 M& H# ~
  128. , z+ U$ {+ i7 H8 C  H% L

  129. & y; ]! ^# V* c1 W% x: Z' \+ z! a  v
  130. : V4 w* i% i7 h0 b7 A
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    / a; |, r+ U3 _0 H! W! _, U' A
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值9 C8 B! `8 F$ R" a8 `( ~0 c' {
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    ' X/ n9 U9 ~( V- Z
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    - B) d* z: L8 x. e3 K5 I
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器; F; Q3 K4 ]1 f1 h: g$ Q

  136. ( p( X0 B: D5 [- y4 b& T6 H
  137. / K' x: d  u- l: x  U- [& H

  138. 9 e: M, o: g) g1 ?
  139. ) p" m% L3 p7 l! }- H& r: N7 h
  140.     /* CAN FIFO0 message pending interrupt enable */
    0 D& T  x# x9 V$ g4 O
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断$ a5 f. y/ ~8 N8 u4 Z+ U4 @
  142. }+ q) u& M9 y+ Q9 i
  143. & a/ ^$ A* F% m* W

  144. # |6 p  x) I& n) f' D" T6 ~
  145. / |3 o- B0 C2 Q* T
  146. ' ?2 y2 ^7 }) Y
  147. /* 发送两个字节的数据*/1 }5 `5 I* C1 H- c
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)9 O  o- {) h3 R" w5 y. M) D
  149. {
    * K8 h) r+ @( E/ g
  150.     u8 mbox;" Y& N3 _" c& S9 q& r
  151.     u16 i=0;4 n- R1 b- v6 |
  152.     CanTxMsg TxMessage;  ! q& Y  O' p2 x1 J) D

  153. ) r9 m9 _- b. T( L! D/ Z9 y. L

  154. # }% Z! }; _: @

  155. 8 W9 X- C# W3 `' M& H* p9 q

  156. ) c+ v1 J+ s8 K  y: C1 M6 @
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x005 Y, W2 C' r3 ?
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    ( j4 P' r+ K4 P6 B: ~. X
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符) q; Z4 f4 x% b! U; w
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧/ k) _+ B1 E6 X7 U) d
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    6 n4 u1 Q" i# L
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据
      ^* i# l% Y2 \$ T# S6 e! X
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据7 J! }  m! g- q* A: y/ @, q% ?8 u0 T

  164. / \2 x/ ?( M4 K

  165. ( Z# v/ {& o# y$ v# Y& Z
  166. % @9 _8 N' c3 i; j: ^
  167. & A' [- {3 W' D. b8 m
  168.     //发送数据, C3 n5 t9 V: }+ u7 N
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  / e/ C/ ^% s& {% I8 \
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)), c$ e* Z2 {% h% \4 b- m
  171.         i++;    //等待发送结束+ P7 H: k. Y! n# S' U; p- P* k
  172.     if(i>=0XFFF)
    % N( M" N  v, J7 H
  173.         return 0;. }5 @" e) B9 N4 H" \) O
  174.     return 1;% o. [4 c0 b1 y- b
  175. }+ O9 x, x* b7 V8 V
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)6 h+ v, X8 i- l* C5 h7 W/ ^
  177. {0 Z9 ?$ t0 C7 d" r* K4 F
  178.     if(Rx_flag == 1)//发现数据' w- m' k" U: l/ r+ T* w# o# o
  179.     {8 j! L" F( y5 a2 G3 n# h- @
  180.         *msg1=RxBuf[0];" U9 Y4 E2 w. Y8 R$ I3 t0 l5 o
  181.         *msg2=RxBuf[1];
    & d: z0 _8 B9 g
  182.         Rx_flag=0;//数据已经取走,可以更新数据
    - X8 m4 B, w7 N
  183.         return 1;
    ' l( P* b3 K( k; _" R
  184.     }else
    * Z$ \- Y' G/ k( {) w/ f
  185.         return 0;( [" }& J! o3 }5 H$ b
  186. }
    / d3 v1 ^. e2 m5 v6 s9 x4 w
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/
    % r% Q  K% c3 l" e' ]
  188. void USB_LP_CAN1_RX0_IRQHandler(void)) S; }3 X, |8 E, a7 g$ g& ]9 z( p$ e
  189. {
      U7 Q1 g$ n$ U! E

  190. - J7 k  {  J4 n& J$ |* N

  191. + k4 ~; F) G; b$ j' O, T# {, q4 a8 n8 q

  192. 7 ^/ N, m8 U9 Q1 |& Q" ?7 c

  193. ; b# y( P/ N6 A' Q) k( F
  194.   CanRxMsg RxMessage;
    . O( n  O$ I# h) o

  195. 7 C& q" H' f, S* l$ ^
  196. ' j- X" B$ K# [
  197. ! o& N6 V0 f4 F" n" ^+ y0 ?0 I( d
  198. , m. m& n' G8 P! w0 S- L* c6 O
  199.   RxMessage.StdId=0x00;
    $ U2 ~2 _6 @7 o+ T% I, Q
  200.   RxMessage.ExtId=0x00;
    * U: c/ `/ @4 _
  201.   RxMessage.IDE=0;
    ( H, S" M& t! R7 S8 O6 f& ^
  202.   RxMessage.DLC=0;
    - P) @, y4 y2 P/ |4 l) `' M0 S; R
  203.   RxMessage.FMI=0;& R( f+ l# E, c3 X3 B! V% p
  204.   RxMessage.Data[0]=0x00;3 \. r1 [, k6 V9 c
  205.   RxMessage.Data[1]=0x00;   
    ' Z9 K5 q; {( e) Y6 x4 @
  206. $ W+ o: r. B& K3 {# t

  207. $ ^9 O, V( x( G0 R
  208. 0 W: x: a7 J* X  e# f3 x2 i! m

  209. 1 Q8 _9 L2 {3 m1 B6 N
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    ! {4 |5 X/ W+ w/ l( @

  211. 5 B" b) r3 [+ j, X9 I

  212. 4 p$ q2 J4 [. L  b

  213. ( P0 Y3 L& D/ L1 L/ p# k) A
  214. ' W! @% j9 ^9 Q( C$ q( M7 b8 |* J
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    & {' o! A9 H# W' N& k0 r2 [
  216.     {# d7 `3 U! m, w/ f! f
  217.         RxBuf[0]=RxMessage.Data[0];
    0 u# Q; }( f& ], w- f/ J
  218.         RxBuf[1]=RxMessage.Data[1];
    1 k  a  R4 g1 r* w  t
  219.         Rx_flag=1;//数据已经备好,等待取走$ A$ J3 [$ E1 }
  220.     }
    6 z# U4 r4 A& P8 X/ j& @

  221. 9 t3 P  M) B& O8 W

  222. % `3 Z4 d& Y; l' b! ~. w

  223. ! w6 R6 s% L9 N+ c& a" g$ a) ]/ u
  224. ) m! D6 U6 Q2 D5 |
  225. }
复制代码
* }/ }$ I, t* c1 f/ [
can.h文件) X7 \3 U; i$ E' d7 c( Z
! |; p' p/ y7 E$ [& ~9 C. Y9 ~9 q3 Q
微信图片_20240615192757.png
9 l" z/ Z6 Z& {" W  `0 f( M( q; U9 s
主机相关代码
, y1 ^: |$ U# _, K# T  ~: e0 }6 G    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。$ s1 j# i% Z' s$ A7 s5 A7 L
can.c文件:
0 {# q# P: G$ T( v, x
  1. #include "can.h"- I4 C% ^8 J* \$ _, K0 q
  2. ; J4 W& D; l( x, j  V: p1 {, H7 R
  3. . |2 C7 m* t6 `* X% P) E1 b
  4. /* 在中断处理函数中返回 */. o  V' g) a% v5 Q3 `% X* ]
  5. //__IO uint32_t ret = 0;6 ]: R8 {2 L4 {& C& y* f# z
  6. ; W* _0 V( y* k% T

  7.   B) e) @* y% [$ M
  8. void CAN1_Init(void)
    ! Y, M% \/ q9 k$ e. G/ O
  9. {6 p: V% _% A2 h% V+ q3 c# T8 l. }
  10.     ......//以上与从机部分相同
    & @* L( J0 z" s2 z8 \7 ?

  11. / z2 |$ e4 _# H- h7 P

  12. ' a) w6 h" Q+ `- g" U9 C. B) g
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    % H' \, t( K) n) c7 N( X
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1( V4 {& B. \. Z9 V2 E
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式8 }* c5 l% |6 D8 H
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位- U5 C$ @) A6 Z/ w0 d/ v' D# M2 ?2 f
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    ' \6 E( J7 e7 }3 ]  F
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值0 I. [/ \& F, ?2 U( B
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    ' n+ N$ Z0 b( E; s1 @" t
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值2 [' `5 u, w3 K7 `
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    - f' O/ I( W9 s
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器7 D3 p+ h4 U, u. B. Y! g
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    8 l6 c; S4 X! P2 {" A) Z

  24. ' I* a6 q0 {$ |% N0 A- R2 O/ ^  ?
  25. ' w0 F( s: E5 C5 M- ]. e
  26.     /* CAN FIFO0 message pending interrupt enable */
    3 A+ D7 Q6 n, F
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断5 S$ s0 E9 ^; i: g" B$ T  @
  28. }, U2 `/ Q4 F9 z6 d

  29. ) \* |+ \! d& ^; U

  30. + e$ V" m# g: z: d
  31. //接收数据缓冲器
    ! e1 K$ o! N. X
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    # R4 X' y* u5 x2 X: y$ C, H
  33. //接收标志位6 F$ N  r. u8 m% a  Y
  34. u8 Rx_flag=0;
    7 q; k& }& N1 |' o7 s
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    5 ~/ L1 Q# P& n' l3 \% q  m3 q# ]
  36. void USB_LP_CAN1_RX0_IRQHandler(void)0 f6 ~# B* t- @4 A- C
  37. {' n# m- E( b, ]
  38.     u8 i=0;! c/ S% e! p2 B8 ^+ [
  39.     CanRxMsg RxMessage;
    - l4 f5 n# i# {; {# o/ `. D
  40. $ u. l, a3 {4 I% ]! |0 U

  41. 3 t3 L" G" V8 R' ]  u9 H2 ^
  42.     RxMessage.StdId=0x00;
    + y9 L* \2 h3 n- U5 a
  43.     RxMessage.ExtId=0x00;
    ( b, e, k) Z3 T$ V2 }5 V/ y9 L' ?4 L+ y
  44.     RxMessage.IDE=0;2 r1 M- U1 S# x2 a9 f
  45.     RxMessage.DLC=0;5 o( ~& y4 C3 G7 K9 G
  46.     RxMessage.FMI=0;. I6 S$ Y3 [7 R# j5 H
  47. 4 g) j" _: X( M9 r4 E/ I2 H5 h

  48. " B$ |# O* |- K$ F% ^5 H
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  7 |5 W$ ^+ n& g) s  ~

  50. % h$ A# {9 a; M. J' }2 t
  51. ( B9 `5 h5 \% _; \% G2 d
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空) C- B( u$ S' P: U0 `
  53.     {& b: N+ i3 P1 W, V6 l- e
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据! e: q7 Q- W$ z# `8 Q
  55.         {
    3 P$ m' |$ T3 Z* A( e/ c3 _
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];+ m0 R9 @9 |2 T6 b" X
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     5 e9 {( [0 V* c0 R- h7 B. C
  58.         }
    " {9 V7 s6 d5 o7 k% K2 B% I; Q
  59.     }0 v$ V0 l8 `$ Y$ B( b

  60. ; k& C/ Z) x4 |4 J2 ]  o+ C
  61. 9 O5 X: E; D/ C- Z% n4 |' g. C
  62. }
      h7 N- y  Y9 @5 ?
  63. ) M9 g$ f3 M2 J5 z! a

  64. . ~2 N& W- e0 k
  65. /* 发送两个字节的数据*/3 m9 J; \( g! o1 L
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    ; r7 G$ N" J1 n8 j8 U
  67. {
      _8 n' O+ W3 |, O! c
  68.     u8 mbox;% Y6 S5 W5 T; B$ W* b- c- l5 Q
  69.     u16 i=0;" j( ?2 ^; i3 F9 D, |
  70.     CanTxMsg TxMessage;  
    * T7 J. ~+ d5 b' ~) y& T5 {% `3 ?

  71.   }9 s8 W% F3 @: \
  72. 4 m8 @( H: i- e9 n. e' m* \3 M5 A
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    8 H2 q7 p+ Y7 k* j  M
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x00006 C3 [% F0 e2 E3 X& j
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    0 `" M# m: D9 i1 J5 f
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧" k5 F1 b3 i7 H1 H$ z% M
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节) K8 g7 `/ j" ^
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据
    : z' u$ f) o) D
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据# T% k% }" x& n3 U
  80. ! O$ h) }- M; [3 R/ V
  81. 0 b& Y# A$ y+ u9 Z  |2 F
  82.     //发送数据
    # n- @  i/ q6 H
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    + j9 R  r! M6 z/ x: S
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    - W: i6 z$ a2 ?1 A
  85.         i++;    //等待发送结束
    6 B9 ~$ H5 A$ q: n$ u$ _- C8 O
  86.     if(i>=0XFFF)
    ; S: \  H0 o  x2 L
  87.         return 0;//发送失败$ ~+ v/ Q# }- J
  88.     return 1;//发送成功* }5 T8 k( k' S: M
  89. }
    1 E3 i7 S5 l- D% v# p: P9 N
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    0 m; K! q; w2 c/ V
  91. {6 T. m, ]1 p8 e
  92.     if(Rx_flag == 1)//发现数据
    5 q  d1 c7 @9 f4 m8 j" R: }
  93.     {7 d& j" S' J$ @  o5 c
  94.         *msg1=CAN_RX_BUF[0];
    # i% O* C+ J* |- {0 |
  95.         *msg2=CAN_RX_BUF[1];4 Y) {/ B& Y+ I+ d
  96.         Rx_flag=0;//数据已经取走,可以更新数据
    ( _6 X2 E3 f' g1 l' C
  97.         return 1;: N. Y* e3 G! {# J( ]* ~
  98.     }else
    % b0 u+ n( W: X1 O5 O5 h
  99.         return 0;( e7 z- N6 X! c$ `% D& |7 F
  100. }/ u; F! G( m% Y: c% G
  101. void Clear_canBuffer(void)- q. R- [- @* x0 I* K
  102. {
    4 \+ n: V3 w* U" A  y6 ^
  103.     Rx_flag=0;//清楚接收标志位
    6 K' p1 x4 j0 U6 A; @1 d
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区5 v' L+ n6 H' g: d5 K2 d
  105. }
    $ g( B! ~$ ?& R  ~& r6 K
  106. u8 Check_canRX(void)
    % b4 A( s4 W, |9 g* e  W
  107. {( K6 F/ F6 s: D9 O! u' u
  108.     return (Rx_flag == 6);4 D# E5 K" {; R! Q" s+ F
  109. }
复制代码

! |- f4 e, K8 I+ r% q& s6 x3 W' H4 Z5 ]% E
can.h文件:
# K; }9 U( O: e0 a4 S4 ~
  1. #ifndef __CAN_H0 A7 B6 U8 k3 C  ^
  2. #define __CAN_H
    2 X! t2 F3 A( e4 D

  3. ( ]9 {" L. U7 {" t! }& M
  4. . t3 N  ]! l" n3 R! \2 }$ @2 W
  5. #include "sys.h"
    8 u. `" k/ V7 M/ @1 Y
  6. #include "string.h"! V/ }2 l4 z, G" V0 p1 r2 p
  7. ( G  N! W( ^! Y/ a' m

  8. 4 G+ _# {6 r! p9 @7 Z2 c5 y4 M0 C
  9. #define CAN_RX_LEN          30          //定义最大接收字节数
    6 v  c7 B9 x" \6 @

  10. ( e+ k4 v% V( q; L# ?; ]

  11. 6 p$ S  I( ~7 s+ Y% d
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    5 z; J" y0 O' I( B/ B1 d+ f
  13. ) ]0 b) M/ b9 o& i
  14. 5 r8 c7 n- P+ }& U. R2 _/ p
  15. void CAN1_Init(void);( o5 \; ^/ X. s, g
  16. u8 CAN_SendMsg(u8* data1, u8* data2);
    + S1 i% [5 Y+ k' Q: k" i0 e* w
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
      M! ^. G4 H; ~/ E5 k( |

  18. " m* Z& r: `, w; S( ]: ?" i! m
  19. ! ^7 }+ W8 |0 w& E; }8 p  L
  20. #endif /* __CAN_H */$ }% ^3 H9 B. v. N; @. t3 z
复制代码

' p% t$ `6 ~2 k9 R( O6 v9 Z1 S8 r% w* ^, y0 H) Y0 ?/ E
转载自:单片机与嵌入式
; D3 u& v( O6 v% y; R
" t6 a3 h+ b) n6 [" t# d如有侵权请联系删除  p: M" I& R+ S/ o* \/ E1 U% m
% z4 \3 n5 W; ^
8 B' R% w/ A* B3 U
# M6 x0 G  z# g  j5 I6 B# V7 [
4 `' O* m. Y  @# n9 F6 b
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似分享

官网相关资源

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