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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信3 E/ b$ J& X# i5 K; ~3 g1 B2 H' j; m
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
( H( r1 f# e) G& k# r2 m3 w+ r. m
- e2 [: F) O7 D: c 微信图片_20240615192751.png
2 `& b% G/ J' e: m, A% b. y' ^/ z- Y7 o, g+ P
    CAN协议是通过以下5种类型的帧进行的:, k4 V. z/ o" N4 }8 Z' q8 Y
数据帧
) ^3 E3 z6 ]8 w# J7 W1 f4 s摇控帧9 g2 I# \  i6 T; d
错误帧
/ ~" ]$ N4 o+ H% K/ `5 M过载帧
  j9 u: h+ e* \% _帧间隔
5 A- ]8 i3 r( H
$ ?6 Q+ y3 Y) Y5 [6 @3 U
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
' [2 m6 f& M, I) U$ q; U
' d" ?: }" A8 I# d$ }
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
3 s- E& X: j- X4 {* g    数据帧一般由7个段构成,即:
& V# B: g4 s$ N9 S( I(1) 帧起始。表示数据帧开始的段。* r6 `" {0 ], n" R1 F2 |
(2) 仲裁段。表示该帧优先级的段。4 q! P* H0 T+ V) x9 }/ _
(3) 控制段。表示数据的字节数及保留位的段。
+ v) f6 M% c6 H* H* \5 w  i(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
7 X: Y$ v8 L3 s3 q7 h, k- c(5) CRC段。检查帧的传输错误的段。
9 w( k# d) ~2 V(6) ACK段。表示确认正常接收的段。
/ c0 {8 |. S  _6 B: o(7) 帧结束。表示数据帧结束的段。
2 T7 @1 ?' f. c+ y; [3 |" Z% `1 z
    明确了数据帧概念,还需要理解一下过滤器的作用。
6 T0 j2 A3 l+ t/ F" L, a0 K, N: I2 f& z/ x) L% {
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
  M# o: R  \9 j- Q' f% z: q; |
# _! a% c3 T6 I2 Q( l. H* X
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:" b+ M  n. D0 q5 L& \4 q. l2 E6 o
1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
! p8 R6 Z3 d, i: T" [2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
& Z8 q& r& J8 O( d- M+ T% b- b7 V6 P- R# X8 i7 J
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
0 T  z# b! |! `0 u/ T( u$ X
- V5 O6 t3 a* L/ q% b- J' T
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
# U% r# e- L5 v% \
1 ]1 ]) R1 h8 O, o1 O: q3 l
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。
% R: O/ X% w- F% [6 b# ~) C% s1 O2 R
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:1 }% t: h: e7 L. W6 U

- I0 f" E' h9 d6 w/ x8 h 微信图片_20240615192755.png + w, n& }' O/ W7 w; f! |
! y3 b% \( K+ x& E6 p* o
    在程序中就是:# B: S6 g7 x* a8 s: W) X7 E+ x
  1. //要过滤的ID高位
    : ~, O) z# _' I; }9 f+ O* V5 n6 p
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    / J/ d1 k. W; p
  3. //要过滤的ID低位                 
      Q* N7 \& P5 Q8 V3 p
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    $ x$ [" _2 N0 B* X; ?( B
  5. //过滤器屏蔽标识符的高16位值4 V+ Y' c1 }- i$ B
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    6 S+ y) k4 t* Y
  7. //过滤器屏蔽标识符的低16位值         
    + e; }8 i& i) \, \& s
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

& l/ N- s& q8 E$ B2 `" w, U6 z; Z    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。7 P( _* T* N! R7 I" o& q
; ]3 Z7 |$ s! Z+ q! e& f: Y3 C, x" B9 X
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
9 z: i3 V& i" s6 c4 O% V* y; w6 Z9 |" x, n5 g
程序思路
/ }8 \5 b+ i3 M: ^. S* T    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
  h/ w) A3 N, ]主机:0x13147 @+ m; M9 u8 ?/ G' d' |0 a
从机:0x13119 Y+ U' t9 Y2 B* C

4 g% B9 [! y8 ?& h8 o+ A) e& p
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
( y1 B$ u9 S% Q$ e9 k
# c$ l* h* A# B1 z( y( T1 S

- P3 i, P: p$ e+ j) v相关代码, f5 m2 e4 s1 q7 j
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
! `4 ]: E: s' C/ D9 A
4 @% Q* V3 h: K& c" S6 s! K$ c
从机相关代码
5 i/ Q0 l1 {+ z2 I0 R# B( tcan.c文件:% i$ h) w1 I4 A8 S1 n4 w8 P- N  D
  1. #include "can.h"6 p# D8 C- A/ r0 E% ]1 `0 V

  2. & _" M) k! V# R9 ^) M" F& C

  3. + H0 W/ p8 V% a

  4. ) h  x( ^, }  {. y; t* y4 Z8 J
  5. * f. P! _# N6 E
  6. /* 在中断处理函数中返回 */
    + s' W4 f/ e5 R; k9 _% g/ J
  7. //__IO uint32_t ret = 0;7 S$ j  ?6 p# W3 E

  8. ; E( `3 X- P8 U4 {; Y
  9. ) W' I, x1 }+ f, ~$ G9 e

  10.   ~" s) \( f- c2 S

  11. ; t" [7 c( ~5 Q/ B6 m
  12. //接收数据缓冲器# q7 l- t& n; F  V
  13. u8 RxBuf[5];7 }  f8 p1 |& b3 f" a
  14. u8 Rx_flag=0;
    2 Z4 y; M: u* ]7 A
  15. 8 r1 N- f3 {' n: A; H8 A) H. }
  16. + y% p% e+ T# ~7 s- @0 Z8 [
  17. + p! w! l# A/ {" q& c
  18. 0 ^+ q) c2 u* B( M9 ]
  19. void CAN1_Init(void)3 y5 D7 L+ E% {* G9 ?) s* {& o' a; I
  20. {
    % M5 |( s) d$ z& d2 I% k
  21.     GPIO_InitTypeDef GPIO_InitStructure;
    . K. a% P! n& t$ U6 E  s9 t
  22.     NVIC_InitTypeDef NVIC_InitStructure;: @& n4 O+ M3 l1 S, I( E' W5 r
  23.     CAN_InitTypeDef        CAN_InitStructure;
    0 [# o4 Z6 L: Y
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;! k; F& k7 l2 H2 r  u

  25. / u8 |: }" T" q7 Y
  26. + u) l4 @0 o+ Q

  27. / l; [/ X' ~( Q2 v) M$ F

  28. 6 \9 F: Y! o- S, ^4 w
  29.     /* 复用功能和GPIOB端口时钟使能*/   
    0 u7 U3 f4 z$ z
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     ' Y7 _" i1 z5 Y# k+ S. r3 {

  31.   p& X7 A- f; Y) L. Y

  32. 4 ~2 Y% O/ m5 J
  33. ( ]( ?" S7 v4 C' l$ X' ]
  34. 2 r; P+ G* E+ K
  35.     /* CAN1 模块时钟使能 */
    9 l, \5 N9 }2 n2 w' y: ]% Y
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    2 J* v0 }8 }3 K2 V- C& y

  37. , r5 O; E% u' P0 R/ a

  38. - J9 J3 \  f! N8 o+ |: {; D
  39. $ y) i  [! M/ b) N+ [  M
  40. 6 z- I8 n7 c$ L( e7 V. Z
  41.     /* Configure CAN pin: RX */  // PB8$ D2 a4 Z; `; m, W: ]# Z/ S3 }) \
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;: }/ Y9 k! n- I
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
    8 R5 V7 @, l$ }2 G4 D! q- {$ r  x
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    ) R) n3 e" ~; t

  45.   n( s3 |' s2 C

  46. 4 n( p# E. C/ ]5 Q$ K7 L! d

  47. % z3 m4 \2 B  ?4 U, ]
  48. 5 g1 J4 k0 N+ p- h
  49.     /* Configure CAN pin: TX */   // PB9
    ) g2 h4 D- L+ a! c
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;' X( R* l* g# l
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出$ M7 x! f% o8 Z. v# z& @" Y5 s
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    - W: F$ C3 b/ q# D

  53. * Z# J5 O. l1 L+ P
  54. # Z/ ~6 L7 s; M4 Z4 m1 D/ O' |! i8 P
  55. 3 h" g* ~4 U2 b! D$ \
  56. 7 v) T% Y/ ]9 M7 e* D
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    0 Q( ~# p6 t  J' L2 h, @' N& \
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);# V0 r0 e/ v8 G' j

  59. % W' `" R2 G& N- @

  60. ; W$ o: M; `# k! j' m
  61. + J( [" {. X: T/ O

  62. % ^6 M( }  ]3 D! f, p
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    ! ^' Z2 d* h. m! e$ h0 g. F
  64.     /* Configure the NVIC Preemption Priority Bits */  
    0 l* n' e$ I" m* b" K  w
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    2 h9 [# K8 f" o; M% x& H$ i

  66. 5 i, A0 ~6 M0 I

  67. ) F0 p5 e0 o: H+ Q- N2 X

  68. + t/ K) x' T4 `, o
  69. ; ]$ e3 P0 R' w0 B% u2 ?7 ]
  70.     #ifdef  VECT_TAB_RAM  % z$ d2 Z2 x! X. u5 K; `. l' n6 f, G
  71.       /* Set the Vector Table base location at 0x20000000 */
    : d4 f. {4 d: U& K9 u% K
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    # s* g0 K: T0 ?3 Q  y
  73.     #else  /* VECT_TAB_FLASH  */" j* Z% L" x8 u3 q# Z4 M; ^: F7 `
  74.       /* Set the Vector Table base location at 0x08000000 */
    ( D9 A9 ~5 G2 l" p8 [! P
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    ; R& \$ T+ d+ x3 w! w! J. M6 u% V
  76.     #endif- o6 I. K, ^# Q- `" n
  77. : P5 ^% H* ]( {* H$ M1 V

  78. 1 \* a7 M, Z/ H# m

  79. 2 \/ k1 O5 G$ [  a+ `
  80. ' k$ C( j9 c) z
  81.     /* enabling interrupt */
    % E+ q$ C+ u0 \$ W" U
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    " w( z3 j) z, `6 @6 o: `8 d/ l9 O
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;/ _4 `! d; S' {" n
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    9 E- \; W6 }+ g+ m
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;! s4 A5 Q: n% x/ E( _/ j
  86.     NVIC_Init(&NVIC_InitStructure);
    6 j( I# j1 q' r! r) Y) v! c
  87. 0 P/ y5 y) I2 w1 ^9 ]& r6 E$ ?
  88. ) J& f. t5 l4 x6 V/ u
  89. 1 F: [; s; v( U) ?' X0 l8 k" D/ U+ w
  90. 8 F: m1 h% W& V; ]8 V
  91.     //CAN_INIT();//CA初始化N模块4 K* W5 {2 `- x
  92.     /* CAN register init *// x- J$ G, C$ h0 P! z
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值$ U0 |' k5 E) d" o$ [% v4 L# E% n6 Z6 l
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入9 _% T% _2 S2 G! T. H) K( _8 r7 x6 R
  95. : R7 `: _3 d7 S; G# v

  96. / v/ l' p( j4 ?+ r3 X6 l' }

  97. ) f% r% N2 t8 W0 L

  98. 3 X2 \% ^- U% s1 {( w% u& f
  99.     /* CAN cell init */6 w* P+ y. b* [8 f2 l
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    9 H3 C# Z+ @" |" _# K! @
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理  O. j4 x( {0 {1 N
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    " o* B: L' i4 ], U
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    4 R5 }5 j# u  l9 U$ d; R
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式' G% [$ `% E2 Z  l" w
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    # G# D: \0 w6 Z) |0 \- I1 r- v
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    , ]" @2 @$ ~( z; R3 C- q" U
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    * A" |/ ?2 o6 ?7 q# L
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位# e; M  g$ j; o
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位$ V0 f% m* n/ {0 }
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    8 h" Z/ ?0 V+ d( S9 S$ u3 z& y
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    ' a$ u6 T# w+ n

  112. + N; ~" u& x( [- b4 p: u
  113. 7 T/ R; q) }* b$ Y
  114. ' {) x/ b- `: j' H  q

  115. # s* q4 b8 I$ [: l1 q* D4 g
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    . S! U9 y0 K6 m) N% W. C% y8 y
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为17 T4 {1 E! A) P- t! v
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式2 F) E9 x3 q5 C& J
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    3 z! d. G* l: A
  120. % @. [* C& Q6 W8 L/ ^4 ?

  121. : E9 f: u& s& `7 |( Q  |
  122. $ N* p( u# U) o7 k

  123. : q& a) j: d& k# l" n2 T
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  ( x% F& P+ |9 P+ r( b: Y9 _
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    3 ?* K* D$ E+ x/ j- B
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位5 u# ^# A7 l& k, x7 H  o" h
  127. 0 W$ Y4 d. Z1 f- H  R6 V

  128. 6 e! M! `0 f4 X; v

  129. ; `/ r6 g/ e/ p) K# T% Z

  130. . ]" T8 x- X- Z) h
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    , `, x, b' ?. }3 \" M& y
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    ! I+ y% s! ]4 S# f! O! b
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为09 t( a; F/ i4 `; Q5 s
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    0 }' C: n. a) L9 y( y- N7 d, m: V
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器6 v) l6 h& y3 F) C, X

  136. 3 R: X; X# B8 X6 {8 w$ ?5 t
  137. 3 a; k+ [6 b: Q5 C" U

  138. : ?+ K  u+ U) @3 |
  139. # f2 X' j  u, a( \, K7 x) J2 a
  140.     /* CAN FIFO0 message pending interrupt enable */
    ' \% v4 W5 v# }* c
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
      @8 I* n- b) H) s, e
  142. }
    ( q7 L% n" h. K( e# }5 d9 K

  143. $ Q% A- H: t& `  @& X0 X% Q
  144. . R# x, l0 Q  ]. D# o6 T# G

  145. 2 Y( ^2 b$ B% S: e: d: p6 Y7 P

  146. 5 h* C  {% m3 C2 `4 I/ {
  147. /* 发送两个字节的数据*/
    ! ?  o3 N( g% |# ?) e
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)$ j  I% J1 o7 S1 A  x7 z- v9 j
  149. {
    ' T% _: u0 k7 Q& v
  150.     u8 mbox;
    / s0 V* A8 D$ b# D; F4 U/ n; U/ I
  151.     u16 i=0;. j2 g6 R; [" S' m9 }7 h: r9 _' h1 p
  152.     CanTxMsg TxMessage;  
    . G5 U8 [2 g: z+ L! R
  153. 4 f% M0 l4 f; d8 P8 e0 {
  154. 9 ?+ ?  D8 _8 m9 \4 \

  155. 8 \8 E' J3 z# ^' j
  156. 0 |2 @, Z, i' y+ o5 p% y) z8 a& o; v
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    / l5 q9 g3 I  l( c" M
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    ' X% c) v5 y/ k
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符7 L1 ~1 k0 Q/ l7 B/ x+ ^
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    9 i% B' q- P+ Y+ ~  y
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节9 ?' W5 S; J% |, o# w; X
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据
    " T/ V5 Y  ~9 u* p' V+ e
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据- X" r! M1 R( }* X3 |8 f$ i
  164. : G( f9 p, N8 o0 N! g
  165. 1 [' H& J0 _" k/ A

  166. 1 t; _5 H3 n6 `0 Z$ y% I" o

  167. 8 i- N6 v$ O7 B0 Y- O& c: B
  168.     //发送数据( U, `. p/ f9 u* o3 b/ s3 T
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    # s: e2 x( w* v! C9 z  |8 d
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    / D! j* X9 r' J6 _& `0 h
  171.         i++;    //等待发送结束# L& g9 H/ K, w7 `7 b9 p" V: H4 V
  172.     if(i>=0XFFF)
    + o6 j' y/ l. V3 X% p
  173.         return 0;* H& [1 Z2 ~  F; {4 P
  174.     return 1;
    - j' D  l3 ]# ^( ]* @6 \% ~. ]8 v
  175. }9 |2 Z% Y. l# b6 E* `1 F
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2); G+ L6 f5 X8 D8 D# q% K5 S  H4 V
  177. {& d( c7 S  q6 Z5 Z2 F! E1 w) c2 a3 h
  178.     if(Rx_flag == 1)//发现数据: p5 x- a7 R, |0 U
  179.     {
    2 H/ A+ E* b. \
  180.         *msg1=RxBuf[0];, _, U' V" v8 x: o7 f/ e
  181.         *msg2=RxBuf[1];( a, b- d4 X! s5 Z" N! ~9 ]
  182.         Rx_flag=0;//数据已经取走,可以更新数据
    4 T# c! B; e, g+ B0 Q2 l8 J: T& t
  183.         return 1;
    7 I/ @& t( Z/ x8 ~
  184.     }else
    ' w+ A& T6 E; |6 b) E& {: g- t
  185.         return 0;
    # X1 L; k' d0 x( ?8 T  i
  186. }7 I4 ^/ u% @( N$ p9 O
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/
    # {$ _' A8 ]& U- _$ o
  188. void USB_LP_CAN1_RX0_IRQHandler(void)# J- }3 S' I, z! G& j2 j( X7 J
  189. {' }; w8 B4 p8 P6 x$ ~' t0 W9 H
  190. - a1 f7 E) r6 ~& q

  191. 8 `8 F/ g4 O7 _  k1 R  J6 Y5 d7 W7 u+ q
  192. % m/ P) _- ~: L/ K* M

  193. 1 q7 w( n8 V$ p/ _& |4 o
  194.   CanRxMsg RxMessage;2 Q. W# I4 q6 Q7 q3 C5 ?4 G' n
  195. ; H* o# }9 U6 n1 ]6 Q) R

  196. % `5 A% q) Q6 K/ c

  197. & a" L  \8 W- v4 V. S
  198. 2 `  u- M  _  Z& _
  199.   RxMessage.StdId=0x00;) w. W* W* I  h) H# e& D
  200.   RxMessage.ExtId=0x00;
    ( c. {# f: q, _- K
  201.   RxMessage.IDE=0;4 T8 o" ?! _% y; t( I' W1 ~
  202.   RxMessage.DLC=0;; q% V, m+ G- u0 d1 i
  203.   RxMessage.FMI=0;+ u( @! W! l& q  H: B( K
  204.   RxMessage.Data[0]=0x00;
    5 c2 L2 Y6 h. C. n  I/ h
  205.   RxMessage.Data[1]=0x00;   
    1 |/ r/ v3 E9 {2 n! Y/ O! [
  206. 5 W3 p3 m; |, o  k( [
  207. 3 W) u4 o5 Q& o: r8 @: H
  208. . [  S' U- v! m5 S' i  M! i
  209. ; _) G) ]2 H# D# z/ p$ b
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  4 J8 x% @* a: ^* k7 V- v$ D

  211. * d. [2 ]/ F" q4 y4 n; v9 [8 s

  212. 5 u8 T% K9 _/ L& F# |. I

  213. , E6 ^3 V( x3 T* Z

  214. 8 o3 X, n+ P& a, e9 O' I* h3 n
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空* b# Y  C& l) X9 |" r/ p
  216.     {+ [) B; F; T$ W3 \# l
  217.         RxBuf[0]=RxMessage.Data[0];
    ' T1 a5 z( [3 f
  218.         RxBuf[1]=RxMessage.Data[1];$ W& @4 F( ~$ y' H$ ?8 A3 S
  219.         Rx_flag=1;//数据已经备好,等待取走
    : S. Y& v$ I% ?) e
  220.     }
    ) x/ Y) [+ ^: s; O0 l( w

  221. 1 f6 l& {8 U/ o

  222. 2 S2 d1 u, j2 L

  223. ) X% p% I8 q' S) b& W- G- v( l( t

  224. ! j! @$ P9 U8 }- O2 M1 ?
  225. }
复制代码

$ U% K0 ~. E0 c3 A7 m. M. ecan.h文件$ i+ |9 C9 v, z& G# L

" N! R3 k4 b. F0 U* I4 @! I2 D7 g 微信图片_20240615192757.png
! b- o' d! C/ C% _' R
) E, \2 ]7 I+ q. W/ Y) z主机相关代码
4 d& z. u+ X& @( D& K, _    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
  v! `! r5 _9 |( ], a/ H6 ^7 x. kcan.c文件:& r: T: B0 |; `& M7 X* F
  1. #include "can.h"
    + I& X7 a$ C/ d+ S7 x
  2. 4 I3 Q& C/ Q: E
  3. 3 ?* Z. p2 X9 |- [- W
  4. /* 在中断处理函数中返回 */: M2 h. l% ]; a; V
  5. //__IO uint32_t ret = 0;& F3 y$ J5 R+ F5 R8 Y

  6. + w7 |, C2 r) a1 o1 E: R! j
  7. 5 p, B9 b6 l  @+ Y/ ^- I# F
  8. void CAN1_Init(void); }# X8 c$ Y- u8 }" o0 @4 ?2 D; Z
  9. {5 c1 I4 R, \4 C  v3 c; A
  10.     ......//以上与从机部分相同
    9 k' Q# A- N* D7 F  W' e

  11. ) ?2 R* i& O" K5 z
  12. 8 r9 t& g. D1 y0 [
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号# E6 U/ ]# {  @* {; D/ O) h
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    2 Y+ y9 D) Y) ]+ T
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式2 f' d$ r' z+ ^" h4 n% i6 M
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位% c) e: p8 r# `. Y
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值3 Z1 P/ `; Z% d; L$ \
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    5 X7 `4 }! K4 l# c/ e7 A
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值% O8 O- Y6 {+ _8 `! w- Z
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值0 |+ t1 q9 I! n; v/ F, x
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    7 [- t7 I& P/ N
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
      E) V4 p- K! ^, u0 P3 A* p8 {
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    : s  q; `; I( {- k

  24. 9 q% _3 D5 {( N( S" |
  25. " j( V8 H8 l  Y+ H
  26.     /* CAN FIFO0 message pending interrupt enable */# _- V; K3 P8 C8 {
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断. o: r9 L, o2 q# a
  28. }
    3 j& R$ t9 o! W% W3 o

  29. : [/ @: s1 h1 ]# n

  30. , d9 w5 a6 B3 @
  31. //接收数据缓冲器
    2 c* E& ]% M" z* b2 x9 V
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.; a( o* O( h. G) x7 P
  33. //接收标志位- n! R; F: L' W
  34. u8 Rx_flag=0;+ \. V' |1 n7 D1 r1 _. q
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */  G' Q1 I9 ~" z8 m5 _
  36. void USB_LP_CAN1_RX0_IRQHandler(void)! ]1 r: g: f1 o+ N
  37. {: m+ ~6 t# Z! ]# r
  38.     u8 i=0;
    3 T0 U% ~, {: L* o4 E, r- A- B+ @0 t6 O
  39.     CanRxMsg RxMessage;
    0 y7 [) ~" b; X% m3 j* Q
  40. - `; S/ p* _+ a

  41. 0 G1 D& ?7 F% j2 w* r
  42.     RxMessage.StdId=0x00;/ L$ p+ Z  B& M6 Z' O
  43.     RxMessage.ExtId=0x00;
    ! U+ ?- \; s1 m
  44.     RxMessage.IDE=0;: y$ c# h' Q+ a' _* r7 e  \' y' h
  45.     RxMessage.DLC=0;$ B" t6 E2 m$ F; {
  46.     RxMessage.FMI=0;
    ' O: V; u0 b. r: I! @6 j7 F0 r

  47. ' e$ u. F( l- X1 c% E7 c6 a' E
  48. 4 m. Z# T1 I, n; y$ S" Q: \+ q& o
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    9 i& `9 m6 |# _9 x" O0 N$ b1 R

  50. # [- i6 u' {+ i9 L
  51. $ j7 }7 y+ u, _& n& I8 [* S8 g
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空
    5 q1 m. i% @; R9 K9 s$ _
  53.     {9 F( H6 s/ F5 i6 Y
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据! }9 o6 T2 l; Z; ~# o2 |; i
  55.         {
    , v' ~& v6 a8 a# [, _
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];
    8 V) ?+ A6 I% n
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     % i2 [' n2 @3 \0 m3 S& Z; k! O+ P
  58.         }
    7 w$ [4 F& G6 q& n
  59.     }
    ; Z4 T8 U: L) O- e9 `& t9 d
  60. 7 E0 ^& q: e1 I! v
  61. % N, v, k  w* U% F* v2 a0 k0 P# U2 j
  62. }
    ) Y  \) m8 G3 m9 ^+ F3 g* N

  63. 1 v8 S& x7 w; V; B5 ]: Y" C1 @

  64. ! e5 W, A) Z8 O. N( Z
  65. /* 发送两个字节的数据*/( H# E- T1 L( {
  66. u8 CAN_SendMsg(u8* data1, u8* data2)/ P" b4 w+ }# ?. Q6 P
  67. {% ]1 s. H' ^- A2 [9 r$ k
  68.     u8 mbox;
    $ {* g5 b% T7 l* t7 H" A- d
  69.     u16 i=0;7 R5 L; }, d$ Q, L+ j: l" d9 {
  70.     CanTxMsg TxMessage;  ) _4 H% e9 y! C8 W2 g( L$ R
  71. 7 z4 z/ ~! e* S. @- Z# y9 W
  72. 6 G' Q0 W, {5 @- B$ A
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00& Z& g1 d2 r0 Y8 G
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000' V* j% y! E1 V: `5 k: n
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符+ c+ f  g& [1 f' z9 ^
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    , [# @: a3 g1 B; T' s, W/ E& K6 A; Q
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    " C. x  }2 T, M, g6 J1 j# i0 t+ L4 W
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据7 r0 S* L; W: q( Q- {9 ^" ~6 [
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据
    3 S& L/ _/ v$ [& L: o

  80. . h8 m" W1 s; f& n! F" o
  81. 1 E4 L1 X! Q: J: \: k+ C- L
  82.     //发送数据9 l/ E1 H& M- N0 O  e& Z3 e
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    & A5 F  ?6 ~0 f9 m: f- Y
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))' Z. ]! |# s. B: ^( x
  85.         i++;    //等待发送结束: o9 L" `# }$ A  L7 a6 o  U( p. T
  86.     if(i>=0XFFF)
      {  g4 F8 Z+ Q& V1 T  m
  87.         return 0;//发送失败
    0 @7 f* }8 _/ y2 }
  88.     return 1;//发送成功
    + U; z0 U) \/ U* @  R
  89. }
    : f0 y+ _# ^' }: R6 M# P
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)+ S9 @* f" Q% K" T
  91. {* H7 n8 k/ h* p$ S& H* }
  92.     if(Rx_flag == 1)//发现数据+ }+ A( c# v! ]  k, h) l9 f% `3 p! ?
  93.     {
    4 {* E/ T4 D' k! {$ g
  94.         *msg1=CAN_RX_BUF[0];
    # I/ T% S" u8 Z) b1 p. M
  95.         *msg2=CAN_RX_BUF[1];
    2 Z% P0 Z8 c7 P. v/ ^2 R/ \9 G
  96.         Rx_flag=0;//数据已经取走,可以更新数据
    , Z2 z: [; K% [. G
  97.         return 1;
    : x( N0 W& S- Z) u" C
  98.     }else
    8 S8 T& K! j' c
  99.         return 0;
    & C: y+ U* c" ?- J# G4 s+ B* X
  100. }
    $ O& K- F! W- o( H  o
  101. void Clear_canBuffer(void)6 n# Q  C1 ~. u2 _
  102. {
    * D8 p. e3 y5 u+ v+ b
  103.     Rx_flag=0;//清楚接收标志位
    . t) j  E0 I2 |: q. s5 p* {2 O
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区8 ]. E% B; m9 k4 m$ G! ^) w
  105. }" Q3 Z- p9 P, t8 B# p4 @7 e
  106. u8 Check_canRX(void)
    & B5 ~: U6 b2 m/ _- T
  107. {% x* B$ Z6 o: @- T% |3 ~
  108.     return (Rx_flag == 6);& m- K; L6 o, R1 ~5 m
  109. }
复制代码
" g. [# C9 c; e4 L- x

) u8 z, [% r$ h; Q4 U& o  ?5 D8 z
can.h文件:9 t5 ]- v: T8 Q2 \: P
  1. #ifndef __CAN_H
    $ z$ X3 ]/ N( l) _  X/ f/ ]
  2. #define __CAN_H' R, U  H8 Q4 G. e% }

  3. 7 q0 t# m" O  A$ V2 s- ?+ a
  4. + c! S+ X/ y+ z: j/ `, v8 Q
  5. #include "sys.h"
    . t6 @8 S1 ?  f7 W8 F
  6. #include "string.h"! u( S* q: V1 ~! V' d& H8 ^

  7. 4 t1 O7 t7 d4 }6 `4 m: o
  8. / m, p4 _2 I8 s' \& g
  9. #define CAN_RX_LEN          30          //定义最大接收字节数
    % B7 _7 t' a* }# O- H4 E& n) P4 T

  10. . W- K! I' Q# m
  11. # j8 D7 v+ O, e. q- B
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符4 k+ D! ^% b7 j3 _7 R
  13. 6 Y2 Z  f7 l$ B* B! N* O

  14. 3 [3 M5 ~$ ~0 r: V  f9 S
  15. void CAN1_Init(void);
    . y2 t. s! _: C
  16. u8 CAN_SendMsg(u8* data1, u8* data2);
    ! V/ v- C5 J- N3 l& P
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    * h. {- T" R4 S2 U
  18. 7 L" ?# V- x) V9 q8 ^. [7 t

  19. % V6 Q* v/ ~; W0 {
  20. #endif /* __CAN_H */
    ( C. @! |# x& @1 y, r, M! i
复制代码

& C- O5 k* d) H. @+ {8 r* P9 j3 B3 \  p
转载自:单片机与嵌入式; A; y6 f0 r0 _0 C1 J' j: O
; @9 H! V2 |8 L' A. }  Q
如有侵权请联系删除: x8 D2 l1 C! z2 I8 a8 O- J# k7 h+ I8 ^

+ R1 n1 H3 d9 A; X4 u' l4 Z. u
8 \' o6 W1 k2 o
' M+ |' u/ k& k- C
6 \( v; a0 r* y
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版