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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信
2 d& J# Y/ |1 |    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
+ T- |2 S4 L3 A
0 ]! l/ `- o$ x 微信图片_20240615192751.png 5 o+ \% P9 e- N  S0 E+ Y8 M- B8 L

  ~/ g, e6 `$ M2 {; [- o    CAN协议是通过以下5种类型的帧进行的:. E2 i8 M6 E4 c8 u$ i9 R# w
数据帧7 j7 R- _( w, N) I' J
摇控帧5 F7 \' u8 X. l- O1 k" k
错误帧
' r$ R( m* ]* R! f. P+ `8 O" Z过载帧
) U( w* |6 E! H; F9 e帧间隔! q9 k* _- i5 J2 H/ R$ {6 q

# U6 D8 f7 a- a' s* F' W; `# R
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
$ q  I0 o) X/ R! S+ c
# v  z' v- j+ ?! u2 U; r4 d$ m
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
0 u0 Y7 _" d1 t& A9 {/ h    数据帧一般由7个段构成,即:* `. a- U7 g% a2 E5 e+ y
(1) 帧起始。表示数据帧开始的段。7 \; C0 W: U& ]: B( p- D
(2) 仲裁段。表示该帧优先级的段。
  y- p3 V8 V" S$ c(3) 控制段。表示数据的字节数及保留位的段。
  `% u* E$ t' J7 u$ X2 h(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。8 G$ k% C) F8 ^* q
(5) CRC段。检查帧的传输错误的段。
. ]0 W7 N1 D; m& A  v(6) ACK段。表示确认正常接收的段。  ^- O  Q& A& U# |5 c
(7) 帧结束。表示数据帧结束的段。
4 ?. @+ G$ ]8 L: H; z7 h; ^! t
4 |6 c& G, p4 P# G' v$ P
    明确了数据帧概念,还需要理解一下过滤器的作用。
9 z2 v; K6 T& B( ~, J  _
" E& ~3 Q$ [- e  L
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
) S. x4 H8 R" K) P5 H' X3 N8 n/ v# L3 d
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
9 v8 l$ {5 G7 c) e( Z1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位8 y) Z: B8 `6 A) W( T% I! [
2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位9 x+ J/ E! d2 x) ~# X, n

% l* [& f- z. b  I* Z6 m" Z( L6 o
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
; b7 s& z- h0 e( x  ~
0 T$ F7 M& ~  D
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
& I% l, F4 e& h& ^) V* i6 ], E. G* u
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。+ h" s6 B, v( O

- }$ E6 L) V; }0 m
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:, {/ y& l" C. P; Z( O# N) D

* R* T( u' ]2 F* j' k0 h 微信图片_20240615192755.png
5 S# P, `# t( G9 \( [9 x
% y* L# [8 f$ F* v0 a! c    在程序中就是:
2 J& H( W* q4 \% Q' N  v: P
  1. //要过滤的ID高位
    ' L, a, C. p; T* p
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  % A6 Y, v% H4 O# ?
  3. //要过滤的ID低位                 
    6 |, s$ v' z" Q" ~5 X* h) y* N
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;  R0 O; b! F$ {: _6 P
  5. //过滤器屏蔽标识符的高16位值
    8 y7 m4 O2 N* x: ^
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    # E8 n8 x( \9 x9 y9 y/ p: w/ X9 @
  7. //过滤器屏蔽标识符的低16位值         * t6 ?7 ~3 N% c3 X" \8 X! Q0 ^
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

4 @$ s- R) J9 G- x; a    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。. M/ z" |& e" E
7 x$ J. i7 a) `4 C! t1 m9 i
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
3 }3 d5 i# Z3 r7 |
1 T3 g  f- T$ J$ V
程序思路
7 G1 R; n. J1 ?5 p* @    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
% p6 Q& C: N  y' L/ X主机:0x1314
) [/ n' J- }( @" g4 p( i从机:0x1311* ]5 ?! I2 u& N* g5 b

9 _8 M  O. E. p9 U; \  y, L
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
0 i/ d. h: C6 b8 ?* @, N3 Y' R0 Z) M; }3 H+ c

- \( P4 B# O2 c" k$ x- g* [, m相关代码
0 w# N4 q3 w0 C, {5 W, d' A6 F    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。) c! u1 ]3 I+ p# x  T3 g, A

1 S) j# L# H' T5 C9 s2 @2 s
从机相关代码
6 G# M  i3 e3 w. ?) {can.c文件:
; m- |  T% u9 d( |5 i. k
  1. #include "can.h"
    ( K9 g' c, q' Z3 m# H: g: i

  2. & c1 V) O1 Q, K

  3. 4 x& G8 J4 \( S1 c- J/ n* B
  4. # o" J# m6 {" F, U
  5. 1 W! `0 X: X0 Q* c' x! h" }5 Y. O8 E1 g& g
  6. /* 在中断处理函数中返回 */% a& w# k1 v7 d6 H6 _4 c
  7. //__IO uint32_t ret = 0;" i% a% {& d8 X  d) Y: v5 H

  8. # ]* V" s, m% g6 o/ I( k
  9. 7 k. @# J2 l* X8 f7 b' a. [' j$ r
  10. ; h/ q0 Q' n" L# F
  11. - @' H( y  S2 q
  12. //接收数据缓冲器7 x" ^' ?# {" A: Z2 `: |! F; a
  13. u8 RxBuf[5];
    ! X* n4 P7 K5 j' u8 ], Z# g
  14. u8 Rx_flag=0;4 U/ f& [8 A+ x5 a8 d) `

  15. ) l0 T; B* E" v% Z" {( }

  16. 9 ?( S1 `0 J& {' |3 H
  17. 5 e+ a3 ?5 `3 ~
  18. ( Q, f8 n+ B8 N5 e
  19. void CAN1_Init(void)
    & H) p! z5 ?/ L4 r1 M
  20. {
    # ]& \9 C6 s8 ]& I" K6 k
  21.     GPIO_InitTypeDef GPIO_InitStructure;
    - e8 z% Q; W6 R
  22.     NVIC_InitTypeDef NVIC_InitStructure;
    + a" b, J' ~4 [( K; ~9 J+ c
  23.     CAN_InitTypeDef        CAN_InitStructure;( [$ m  S: a: t  w7 k% B& i2 c' B
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;: J2 V' ~% G( x
  25. . ^( J; F2 i  p$ r( X2 v4 v
  26. ; R& F1 m( m$ Y+ C$ Z( E& Q; Y
  27. 6 D7 u$ L* I9 h

  28. 6 _& ?  ~0 C6 D9 @; T: J+ r- C" u
  29.     /* 复用功能和GPIOB端口时钟使能*/   $ ~$ {# ~1 H! ]( j2 W
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     
    + D0 g/ b) \# V  v

  31. ; l2 i; n. e, _
  32. 0 z. E/ F5 X% c
  33. % K4 \4 l+ n. C" a
  34. 6 Y$ F0 n; x/ y$ R
  35.     /* CAN1 模块时钟使能 */
    " V" `, B2 O# o. @& m4 ~, J( U
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);$ \' G, }) k: L$ t2 i5 B( U

  37. ! t: s: @, w- D8 L1 @/ H
  38. $ B" f: P( D6 ]8 j- N: T
  39. ! Q, ^2 e: r" b, \% {/ R

  40. 5 v) y) `- C- j: q; X* ]7 w
  41.     /* Configure CAN pin: RX */  // PB8! C+ s8 n# a7 g! {& e- b; `; S
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;6 c8 k* J1 ?7 L8 c4 x0 ]- j
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入8 G! [1 f% `, t' _0 I8 d: `
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    2 w; q, L: U9 \% o$ n

  45. ( j5 Z: A. N* V
  46. # g! e; r( p1 `; R
  47. 7 S5 q3 W, ^9 M3 k2 O3 q  n) n
  48. . W  i1 e* h- W6 ]7 u: {- k
  49.     /* Configure CAN pin: TX */   // PB9  v  }. L4 w. W" ]1 R6 T7 ~
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;1 d) O+ F- @! W! l/ A- f* D
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    1 U5 l' w( b8 `: T5 r5 z
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    + g4 g+ o# h$ v3 M  F
  53. , E; B6 b9 u6 g+ Z& G% S
  54. ! \2 X! j! C7 z+ v6 H5 y

  55. 5 Y  f' b7 i" H. W4 }
  56. # i7 p5 i( O, l
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    " G3 c) V- f3 d
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    # L0 R$ I) d  b& j  R5 N  z

  59. 4 x3 Z( R8 q& L

  60. ! I3 ^/ P- r# S+ [: {
  61. $ o, l9 g7 `) M9 ]  n
  62. ' H/ K4 S- r# ]- {
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    & M! h' A5 k. R. P
  64.     /* Configure the NVIC Preemption Priority Bits */    G0 \* [/ ~3 t7 ?1 A% `
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    / c- Y' i0 C* F2 o4 t1 {; u  g  v# i
  66. " F/ N& p9 }, ^3 ]$ N

  67. 0 O( w" N3 l/ J- y* K3 ^
  68. ' A( d: r: H5 p" J1 ]( x/ v' b

  69. - P2 L( ]: C) ]( t7 C0 V5 [
  70.     #ifdef  VECT_TAB_RAM  
    4 i/ j- ?9 o8 e: y7 W
  71.       /* Set the Vector Table base location at 0x20000000 */
    ! O7 F& A1 k- z4 R% E
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);: f1 ]; p6 P! q4 [" r
  73.     #else  /* VECT_TAB_FLASH  */
    ! s- `1 w& c5 O. ]8 x" n
  74.       /* Set the Vector Table base location at 0x08000000 */* H9 R" P0 b) I2 ]7 ~
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    , F+ S9 b6 B& M; ~+ t
  76.     #endif
    ) x& ]$ d$ f  [! t
  77. 6 V* E6 @! n8 D3 N7 ]
  78. 7 z- N1 M# S  I9 F* x

  79. * H/ s+ [  D4 N

  80. 8 k; i  h5 O/ J- P6 R% F! {& j
  81.     /* enabling interrupt */
    & f) f0 Q  O, M$ h/ @/ z
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    9 m2 \6 t' ~" s/ f, m& t
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    2 X, v3 k4 k# O$ j
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;6 f4 F5 s* g/ t' }
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    2 m% |! _5 L. C
  86.     NVIC_Init(&NVIC_InitStructure);% i: }3 v- P- T9 Y. e1 \

  87. + ?5 X6 E# P6 s1 A$ a0 N8 C
  88. : J+ ?8 |; I* I$ @! _! K/ J2 K

  89. ' T/ s' n" t6 |, z3 c

  90. 6 A. I' Q5 R* S
  91.     //CAN_INIT();//CA初始化N模块
    & U" ?; [! P; Z; v7 j
  92.     /* CAN register init */0 [$ F# H$ p1 Z4 M' Q
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值- _0 o6 _5 C7 A$ y7 ^" X$ @( M9 t
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入8 z+ z; V5 w) H# u

  95. # w: G' Z, L8 K* S& K

  96. 4 ~# l. P: [0 M, m1 \, v3 K

  97. : P- M1 q( T- g- V/ r7 P

  98. 8 ~/ p& d* o7 S4 {' X7 u
  99.     /* CAN cell init */! }; ?% r- M; Z3 e/ h
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式( v' S7 U. _$ d8 p
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理# m0 X% a: g7 w' S, k
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式' h. G9 u9 {: `
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式2 T1 F, w3 j6 E$ `
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式+ ~2 F. x# T/ Y' N
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    . v. r- H7 P' `$ Z8 F# p
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    0 W$ y, a- [& [) n" k- y
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    - H+ Y1 S" `5 a
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
      z. ~* @4 L, N/ _* d
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位
    3 }8 p( Q, Y* O! R, i1 K/ t. R8 s
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为600 p$ w0 E; r& r3 U- r
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    & H' d, A  s# }$ n
  112. : r7 `" s6 G7 F" u
  113. - Y+ E" D; Z( r; w5 N
  114.   ~5 w4 b6 a! U
  115. + s% U$ c/ p0 s, {5 O& K* h9 C
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据# V8 h/ X( U" w9 }( }/ |
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1/ O; T0 R: o! y8 l& Y3 X
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式' k# I2 R" h4 x
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位' O' E: J; n% D( w- ^8 X) g

  120. , I+ @  P# [/ Y, `" ^

  121. 3 y, x9 |/ O. w+ P& {
  122. 2 `! @4 K: _4 r+ C- D
  123. & l. a/ a+ O8 J7 P& K
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    ! E: P: k2 v3 C2 e
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位( V% z; f9 ?# y1 {7 C4 q
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    % q3 I8 R; b2 t+ Z/ [; i

  127. - N+ Q7 D  ^: C" W, p! s( l
  128. ! X0 N7 G0 n' d% L7 ]9 T7 x) \. I
  129. 6 Y5 p( ^0 c  K* p/ L

  130. 7 A5 L* M1 r* m
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值2 l- a2 S. \* ^* W4 w
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值7 b; s4 I# n) U5 R# U5 t& J/ @
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    & g' m' j! n1 O0 |3 ]5 \% L
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器, ~6 h, m1 u) W( \5 i
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    7 ]: l5 c( r! c/ p$ `: E( k8 A

  136. ! e9 H, ^* w5 M2 I6 H" B% D8 Z- s
  137. 1 u; p3 M/ o, B, g+ H

  138. : A5 k; T6 p& L8 F: b( V2 g

  139. ) l" V, {# E( n4 }7 v, \$ u
  140.     /* CAN FIFO0 message pending interrupt enable */
    9 W, Y! W+ ?+ O0 a$ W. E" V
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    5 Y7 ~& c1 A" g* s0 F
  142. }
    8 \+ }# _9 X7 L+ Q

  143. 8 D# `' E7 m/ ~6 ^: m, b
  144. / C7 I. M( m8 E! Q0 `& Y

  145. / R- \( v, t( B8 Q

  146. + |" R3 A" E: `! X' [4 n
  147. /* 发送两个字节的数据*/
    0 @$ k4 k$ D# ?
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)  F* S9 D) C9 e' b& n( S3 Y
  149. {
    3 h$ c  F: x5 U7 W2 Z
  150.     u8 mbox;
    7 ?( l  B5 N9 [* \6 M
  151.     u16 i=0;
    9 U+ Y% ~* e" X) P8 L7 Z
  152.     CanTxMsg TxMessage;  
    & T" i7 K- c5 \7 w1 {( o

  153. $ k; o4 [5 X; {. ~
  154. & v5 J- D/ Y' q0 O! N/ ?4 ^: G

  155. , r# H0 N/ T& x: N9 ]% j

  156. 2 m1 z8 g, I" i9 _  o( `7 T3 M- w2 Y
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x00* ^2 q. @4 Z. J& Y0 S1 L4 ^& {
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    : Y3 H" R, _0 q6 |
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符8 h  S: K0 i! ~3 ?1 [: X
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    " n* A$ |# O6 x  C4 p
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节. Q% e9 A- z% ^8 {# f
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据
    ( m+ Z2 p3 j9 B- v- l# A
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据
    $ E2 Y6 @, z5 O/ ?0 B' X2 u- e, W

  164. 9 q: [3 Q+ u+ N  U

  165. % Q# s* B/ L' o4 |

  166. 6 o0 Y+ X/ L4 o. n; f
  167. / ^5 Y* f* l: H, x, F4 L
  168.     //发送数据
    / _3 f1 B" M  D6 D4 `* c3 G& w: ?
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    + Y+ w5 `& U! E- t# n
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    6 q! c/ A5 J3 e4 `& L
  171.         i++;    //等待发送结束& |" b% g* j) R& y  Z" [7 t
  172.     if(i>=0XFFF)) A7 Y1 O  Y! b; }
  173.         return 0;
    4 b6 U& E; g# ?3 \: g; G
  174.     return 1;; j2 e$ q3 y9 u$ z# \6 r
  175. }
      b3 o4 J. V) |: k( i% r2 e$ X
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    / Q+ U7 [9 _6 \  t
  177. {8 w8 l; d: F- W& l
  178.     if(Rx_flag == 1)//发现数据
    * ]6 I" g+ v& G$ M9 ]6 p
  179.     {$ X3 C4 `+ G* ?
  180.         *msg1=RxBuf[0];% x& F; Y2 x6 r* j
  181.         *msg2=RxBuf[1];2 e/ h$ M" x0 H3 C1 R
  182.         Rx_flag=0;//数据已经取走,可以更新数据3 o# C6 D! c: g
  183.         return 1;9 \7 Y1 L2 h" F6 ~# o, W& r
  184.     }else
    & `; v6 P% I8 ]9 O3 z
  185.         return 0;
    3 q- v2 A; x& q( p8 s% w
  186. }
    " d( g6 Z3 W; U) h
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/: _3 |) c6 i# v
  188. void USB_LP_CAN1_RX0_IRQHandler(void)
    9 C9 d4 E5 M5 V
  189. {# O; {3 ?5 I7 B% A
  190. 2 }. B( \9 U9 i$ w, P2 v$ M5 n, t

  191. * Y6 @2 Z5 B% r! [( Z+ T
  192. 3 A: ~) q# @( t2 d3 [/ g
  193. + k; ]& N9 i' E1 H9 s% v& u
  194.   CanRxMsg RxMessage;0 s" n5 D6 @8 l5 y

  195. * \8 {" I6 W7 ]9 k

  196. . c' `# k2 C6 f0 R. a! f" B8 G

  197. ! H6 S# F: }  \) A9 h6 {  U" A
  198. 2 a" ]' C" L$ j+ e/ P4 E
  199.   RxMessage.StdId=0x00;6 n6 ^8 ?6 ]$ ]8 u$ [
  200.   RxMessage.ExtId=0x00;: W  }9 T1 r4 ~. M% M$ W
  201.   RxMessage.IDE=0;0 }: j% t: [3 a# {) h
  202.   RxMessage.DLC=0;
      R+ s5 e1 f, Y  i( g
  203.   RxMessage.FMI=0;
      B* S" @+ g0 K  U( _6 t+ q
  204.   RxMessage.Data[0]=0x00;5 T/ G6 H5 ^2 W- k& z  C7 [
  205.   RxMessage.Data[1]=0x00;   
    , {8 q1 i5 `0 Q! D+ v
  206. $ i, Y( t$ m3 r- r. G0 B" K
  207. 0 V4 c  B/ e) i

  208. - E: X: p6 c* w6 n! P! l

  209. ! D% D$ A. h/ T, @+ e
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  ' Y; M& C. K! ?2 e0 |* K( _

  211. 5 f% e" e- R! w0 t  l# S

  212. 7 w, s9 d* T) ~$ `+ B. f% C

  213. ! v" u/ {5 [8 H. o+ w: K7 k' \# h
  214. 0 ~: O# r* o/ C) d9 M
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空1 Z2 {; w  @/ v/ R' _: `# T! n5 c
  216.     {
    . F% Q( K) Y$ W; n/ B/ M8 t
  217.         RxBuf[0]=RxMessage.Data[0];
    / K* n  I. Y" e5 K- @. Q2 P/ S( j
  218.         RxBuf[1]=RxMessage.Data[1];
    9 \9 y# f2 c: W
  219.         Rx_flag=1;//数据已经备好,等待取走9 `$ ]8 Y' O* D! o/ s& [
  220.     }2 ?! n0 m  S% j+ o

  221. - K4 Y3 M  ~8 Z# b7 R: C' j& [
  222. , M9 C9 z+ j' W

  223. 3 C3 ?' u2 I6 d8 c  G
  224. 3 `8 p, Q+ |% y. l0 a* }
  225. }
复制代码

3 Z0 {- Q; g9 i; B* Vcan.h文件0 x0 }3 F# f, E8 w: N

1 {: o% A( R8 _2 c* k 微信图片_20240615192757.png & N# j" P0 T2 {- q- Q

% d6 j; E6 M* g- [主机相关代码; R+ x$ h' `3 j9 s
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
- n7 K0 E6 h5 w" ^( O( xcan.c文件:
$ j% l( B9 }$ Y/ I$ f* J( D1 P+ s
  1. #include "can.h"/ X! G9 L+ l4 t' O( m" b* R5 g

  2. . g, v0 y- k8 k. ^. V" d
  3. ! e+ f9 n  ~1 R  B% e
  4. /* 在中断处理函数中返回 */3 S" T+ A1 A) g* t. M6 x% n9 J
  5. //__IO uint32_t ret = 0;
    5 C5 Z" q* c, h+ _
  6. / F+ G, X  R  }) o8 l) {$ Q
  7. ' k) M$ E; Y2 ~$ V. H
  8. void CAN1_Init(void)
    ; ^1 v) ~- A4 q' N1 D: W
  9. {; W6 u% R. u1 T; q$ N
  10.     ......//以上与从机部分相同5 w& Q- \! x; c  t( _

  11. 3 B  V- u, y/ d  E. x

  12. ; M- \0 `+ n: x
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号7 c; D) a6 f* ]4 u% U% M% D) G+ D
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1" y; D' F9 c9 D/ s
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    # z) P2 T& V  W) v/ L6 o
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位, Z/ s$ i: S/ J2 v7 G
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    ! k$ G8 x0 d/ V- {5 V& q
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    : s1 }$ v% `) Y
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值8 K' d9 Z  |8 S. J9 S. D$ _
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    4 ~$ N* v0 z+ ]. q5 E- a) z2 x
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    6 s. ]; O$ G1 X/ j/ t4 z9 |$ ^
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器2 {% l9 D6 s) t0 _# L4 C% ]9 c
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器* g9 _) p# `$ ~: Z
  24. 7 j5 j0 F( k6 D7 {$ k- I; Y$ ]
  25. 6 N9 X' G( }. C& F
  26.     /* CAN FIFO0 message pending interrupt enable */
    % O% r5 y% \. S5 I/ ]* S
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断1 o+ c& Z1 N5 b1 |2 K) v
  28. }
    % l9 e: u: |0 K) `' O

  29. , G* g. }  m# Y* M) z* S' T

  30. + v9 L1 Q( i; c0 a
  31. //接收数据缓冲器9 J" _- A9 I( f- B8 r$ f
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    $ k" s- d; p  k) W7 M% k- s
  33. //接收标志位* Q5 t( d5 f& c6 b
  34. u8 Rx_flag=0;
    $ @% @: y3 ~8 W# C2 h
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */& F% I% D$ F7 i: q& k  W2 z1 B/ {
  36. void USB_LP_CAN1_RX0_IRQHandler(void)% ^" b; M* t3 A& f2 m
  37. {$ `1 D0 k! r! H# D
  38.     u8 i=0;
    : }% Q7 e3 N5 {- w2 F2 s' X6 p
  39.     CanRxMsg RxMessage;
    ; M8 R% r8 V1 x. F# h. y  s

  40. 5 J& I( D+ I  B. O" E) p

  41. 3 D8 l* [6 x7 w6 U; \3 j5 A
  42.     RxMessage.StdId=0x00;
    6 M) U# |4 L" {3 h- F- g! g
  43.     RxMessage.ExtId=0x00;
    " z$ ^0 k" m$ N9 b1 s
  44.     RxMessage.IDE=0;
    9 P- r8 u' Z6 D
  45.     RxMessage.DLC=0;
    " w1 _& C# q( E
  46.     RxMessage.FMI=0;2 h4 D( F2 s+ v

  47. 9 F, H6 G3 l. y4 e& N% Q  q
  48. + U  H: A2 D% R1 E3 u4 Q( G
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    / b4 E+ n' `1 d, }  P# h# y
  50. 1 w3 s( [2 ^, l
  51.   T* f5 `. j* U. z
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空
    ; {( n/ @7 ]& t+ @
  53.     {
    - y* L- }8 f$ n8 f9 E" D+ ]
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据( A  F3 E1 ^. P' g0 {
  55.         {  A% r+ K+ ?- C* C9 o# y  C
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];1 O9 Z1 C. R) D  K+ ]: k8 `0 c1 O* C- l
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    $ I* }7 q2 |8 J2 s: Q
  58.         }
    ( ?1 t7 h4 U, I+ R" Q
  59.     }
    0 M4 t1 W* t% T
  60. : |  v) S  F6 E; S

  61.   O  s# A4 d# X2 n  d* Y& X
  62. }
    - B1 z4 I& ]7 b, t
  63. * g1 o+ z/ y7 N" V) [, R

  64. , R* C5 S2 `8 Z3 v) g  i
  65. /* 发送两个字节的数据*/
    - J- e* e! R* h3 T7 H! c+ _
  66. u8 CAN_SendMsg(u8* data1, u8* data2)8 \$ i+ z% b0 x8 {7 R3 |
  67. {
    6 C$ `+ J- H% f& p7 ]# B' I  [$ F
  68.     u8 mbox;+ D& U5 L0 P, S5 C* \( y9 U5 \
  69.     u16 i=0;6 b& E2 w5 x" E, {& {) t, r' y
  70.     CanTxMsg TxMessage;  . {' d6 W' L& ^
  71. " e  u3 z3 {5 Z2 Q
  72. # x* U2 f( i% O6 U# f4 u
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    2 s9 o; V3 H/ E  Z3 ~
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    ! H6 s8 b: x8 T/ E3 a
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符2 y9 _& s9 ~; Q
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧& c% B% V6 }+ w2 c
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    5 W! {! K# \4 s. }5 u
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据7 R' c/ i9 A, c2 j
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据6 F: V  p$ k) ^& X( t9 Q/ ~6 y
  80. 8 R7 u4 ]0 X8 Q# `/ r3 }& z

  81. ; k" _% x& ]+ B& ^. j' O& b
  82.     //发送数据/ X5 B, R# L) _$ Z* x$ F
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  $ k2 x; b& K7 d) c
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))& {  o# @# J" _2 O' L( H: X
  85.         i++;    //等待发送结束% r. Q* F; x1 y; B) w5 m; z
  86.     if(i>=0XFFF)
    , G' W2 O% W% _5 `: |
  87.         return 0;//发送失败3 q( _. G, d- I3 W. G! f  o1 l
  88.     return 1;//发送成功
    % I1 S3 m2 s+ A& j& w% V) R
  89. }% {0 D" r0 D* x
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)' o8 s8 U$ q8 g
  91. {! Y) S4 r1 J" w  Q! p. v
  92.     if(Rx_flag == 1)//发现数据( l: [6 a+ v' S& X
  93.     {* [- ]% @) H3 M1 r7 n
  94.         *msg1=CAN_RX_BUF[0];; o' o! n8 }& C9 Q1 v" p- S. p
  95.         *msg2=CAN_RX_BUF[1];
    9 E" }. M2 K5 w; n2 [- t
  96.         Rx_flag=0;//数据已经取走,可以更新数据# c9 [! G) [7 o; i" y7 T2 Q: V
  97.         return 1;* @" E: B0 L/ m
  98.     }else
    + a- i- E/ k4 E8 [. g
  99.         return 0;& I# m9 V0 X" l! E& N$ ]$ O0 }
  100. }
    3 u2 e2 z! x$ M& z) T, m
  101. void Clear_canBuffer(void)
    9 V9 g( N$ [' Y; r& E
  102. {
    & M' W7 ~( u( R* ]- q! e
  103.     Rx_flag=0;//清楚接收标志位
    - y$ l4 C# e; W' ^5 r/ h3 |6 a
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    " {. U6 g9 U( ^
  105. }
    / [, Y, z! F$ y0 @* `4 o8 M
  106. u8 Check_canRX(void): u8 {+ e$ N: F2 y- r+ U! s
  107. {% ]) V4 K, F8 k6 `1 Z1 O
  108.     return (Rx_flag == 6);( [& g; N) l" K- M. J+ J7 d
  109. }
复制代码
& B3 t- l, h2 z2 z" Z# `

- Y6 ?1 ~+ S: `3 H- ?
can.h文件:
* v3 M% |" W2 ~8 u
  1. #ifndef __CAN_H* X$ S' {6 B5 V
  2. #define __CAN_H# Z: Q. g  J# {  a1 F
  3. " F  j3 D8 ~' o4 W( D3 r' t
  4. / Y# a( D  Z- F  F6 m/ y* R. W
  5. #include "sys.h"+ b/ k3 x+ x* o1 L
  6. #include "string.h"+ ?& |/ D6 m4 q
  7. ! e% {( d3 s. W' Z5 D- ~

  8. 0 h7 f! J* ^/ D" C9 e, K, }
  9. #define CAN_RX_LEN          30          //定义最大接收字节数# n, k5 A3 _/ h, I1 Q9 `, w+ I
  10. ' F; v$ d/ A4 c$ c7 G) C3 t

  11. ( g! y0 G, p* J& _. H3 I
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符& m& J! B& B& @: n" E( L
  13. , w; l+ d, P0 p5 W& ~" g0 |
  14. # r; c! t% @/ E$ }7 T1 y
  15. void CAN1_Init(void);
    5 b* g# ~1 V6 m1 Z% w* Y" u0 S" i0 n
  16. u8 CAN_SendMsg(u8* data1, u8* data2);9 L, a( o6 O% B% u: L
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
      T2 r# k! k2 z) s+ ^

  18. - `$ @5 z1 @) C0 e7 Q. X! S" ?
  19. 2 b' |+ J3 q$ J
  20. #endif /* __CAN_H */- o9 ?0 l) ~3 V$ F
复制代码

2 r: C7 `1 I3 Y& \( C0 E( n
4 k2 t+ ~" E: g转载自:单片机与嵌入式( s" s  N9 N$ n7 h

( v3 G5 M' [" e; v如有侵权请联系删除  d% Y5 f3 V# |- ]% }

4 m% P9 }- v, G  `( W( L, t5 [# D6 A3 E6 _

5 m6 g  U6 X, D/ F1 i
2 {, @& V% B! [' g6 |: {* ^; l' \
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似分享

官网相关资源

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