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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信
% S7 `/ a( J: T" l. m    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。; e. I$ o4 [; ^& N7 w" D
# i% b+ U9 }) S% e! `5 [. Q
微信图片_20240615192751.png ! m3 o" i6 B% A" M
8 `/ g2 j% j0 Y
    CAN协议是通过以下5种类型的帧进行的:
- F& E7 s' Y3 a. ^+ s0 U: C9 M  O数据帧- {4 X& x6 L, g* c& t- l0 ^2 n, R
摇控帧
( ]3 d! h3 G: D, M错误帧
1 N/ X/ [& k/ a0 Z" Z+ D8 V过载帧
6 P+ r! T3 a! y# T# u帧间隔
! ?( l, f; ^3 m8 R
8 i  l: ~8 c" r  M
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。: F% e, \. b) F, r) q) c2 S

0 T9 u  O) N' S- x
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
6 L5 z  q# Y1 v* w    数据帧一般由7个段构成,即:
& [! r' k1 u' b4 v# l8 [7 b$ W(1) 帧起始。表示数据帧开始的段。
5 \! F6 k0 j4 {5 \9 v" U0 K& ~(2) 仲裁段。表示该帧优先级的段。# `3 k5 X6 z4 v  I# c* A8 w: L% B
(3) 控制段。表示数据的字节数及保留位的段。
# e1 i" H9 \% I' c; E9 n! ~; K' l(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。  y0 T( `- z7 P7 O3 ]1 q7 e/ f
(5) CRC段。检查帧的传输错误的段。
; _( o) R5 `7 y3 B# R) W1 w  x(6) ACK段。表示确认正常接收的段。
$ t! p- z& X$ Q! z7 ]% P(7) 帧结束。表示数据帧结束的段。
8 O4 f% Q$ ~8 ?/ R2 J4 c7 P* `4 ^  g8 S4 G8 G0 {* p
    明确了数据帧概念,还需要理解一下过滤器的作用。
- Z% \9 O* ~4 ]- d) F
1 K; R) U' `8 q
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
. L2 y% D/ S$ u1 Y/ c$ ]! h
9 q+ a$ W! t: W
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
# x6 q4 C( {2 x/ Z( K$ I1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位1 T$ M7 v; ?. `9 K2 X" H* T$ G
2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位7 k2 \+ ?) a( F0 _( p7 ]* _

+ W7 o6 P& t* Q, T
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
( H& L+ T9 l" Q
6 J: V8 I) b' n% I0 J3 @
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。2 j/ c& a8 I" `) J* j% ]4 T
6 k% ~9 \6 `; _6 ?" x) L" o" _- L
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。1 ~; ]0 ~+ G$ F

1 X' _4 \0 m+ c0 y
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
9 R3 [, m3 y3 b* C+ P" p& |4 g  e: I
微信图片_20240615192755.png
& B) G2 t  N+ E, b- q
* f3 N3 N, [! e" ]' b    在程序中就是:; F/ H  _4 [6 j/ y2 T( M
  1. //要过滤的ID高位7 l; B6 b$ l8 m
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  : y; t. }" [( c) z+ r$ r
  3. //要过滤的ID低位                 ' l% W2 Y1 N1 L* Q. p
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;4 R' K3 o' }7 F* q
  5. //过滤器屏蔽标识符的高16位值
    : q: Y  e/ L5 {5 u6 M. A
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   6 p( h6 R% S. A; O
  7. //过滤器屏蔽标识符的低16位值         
    $ T" t  y9 s1 z# x
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
1 S4 o4 C) c* A4 H& L( h
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
$ N1 {$ d( k3 I1 b) _. Q- \5 u8 x. f- d9 A& w
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。+ _* R; z  Z' I
' f/ T- }8 J* F
程序思路8 E, o: w; v- Z
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:. f2 r; }0 j8 u0 _* v: B! d9 H
主机:0x1314, c/ ]4 _# c2 t' Q  b% E
从机:0x1311/ r; \2 g2 x9 w8 V
. q, T& G4 `4 o1 T/ R
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。0 h* k/ n" c, q0 S% {

# N( ^7 P  B2 U4 ^2 l! i
' I! u8 C8 q" t7 j0 q
相关代码9 t& ?0 c, a- S  T& U* F; B
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
4 n9 D1 U6 _" U: N9 w9 Z
( b& w* P' n6 \$ Q- ]
从机相关代码
' V0 N1 h: T' S( c. Tcan.c文件:- Y7 `3 o& y8 T) {, L2 n
  1. #include "can.h"' P. o3 Q6 n, r7 F
  2. ! G" z" ]4 n: R* |9 w# i  F

  3. , p; k/ C8 t4 _' s6 t
  4. 3 W$ m% v! U( A
  5. 1 ^/ W9 ?; u  v& n, [2 k
  6. /* 在中断处理函数中返回 */+ b* S# F2 u. n. W
  7. //__IO uint32_t ret = 0;- e3 \4 C) A5 A8 y6 Z# C

  8. " Q  w: f3 y% p  M( K. i+ ?& k

  9. ; w# g2 g5 ]( @) i! S

  10. 8 Y6 Y3 s. J2 ]  J3 o  r% h
  11. 3 u! e) y0 @( H* B$ h
  12. //接收数据缓冲器
    ! |7 B" X6 g3 ~1 c4 q6 v$ P
  13. u8 RxBuf[5];% x1 n/ \+ w6 g  A$ b
  14. u8 Rx_flag=0;
    ! t" o8 o  I' N9 e' y2 z  n

  15. / t( J' ]; P4 z& U3 n0 z0 ~$ s# s* b4 p
  16. 6 d* C$ E: ]$ w/ D
  17. * L8 I1 L$ G! m  w

  18. ) M) q# j3 ~7 E. f5 b
  19. void CAN1_Init(void)7 F; F( A6 n; F# Y
  20. {( T9 Y1 n% ?- |' c! [
  21.     GPIO_InitTypeDef GPIO_InitStructure;4 C2 F# N/ @" W+ O/ f
  22.     NVIC_InitTypeDef NVIC_InitStructure;- C# K- y) `# o3 n% F9 ]2 Q
  23.     CAN_InitTypeDef        CAN_InitStructure;0 `, e# r* ]( ]" o6 N' u4 s3 `
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    2 o* V) e2 V( j' V+ [
  25. - A' D  v) o3 _1 A% M, u
  26. " b4 y* \5 [' [. _, ?' K
  27. ! ?% L& p  V8 `, l
  28. 5 T: y1 ?9 L# f
  29.     /* 复用功能和GPIOB端口时钟使能*/   0 B3 \) ^% N1 W5 O6 T+ c
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     9 L# y, C" E9 H0 M4 S, _( v

  31. 1 D9 t# ~8 ^  E/ s! R

  32. $ x% [8 {1 t$ V5 l4 K
  33. % g1 l- ^9 v% ]1 t2 A$ [$ c

  34. - Q- w) O( \  `. e$ [# \8 [
  35.     /* CAN1 模块时钟使能 */
    8 o) B# E4 @4 W$ @+ L/ v4 }* w3 r
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);" a6 \% M% T) p) C5 J& c

  37. 0 w0 }& C7 P: A5 m0 m
  38. ) k' b& r& l8 X1 p; u2 G4 y

  39. ) z0 y( n1 x5 a3 C# Z; x

  40. 6 }# B! F, f+ w4 b- b1 h
  41.     /* Configure CAN pin: RX */  // PB8
    - p! b, T+ e1 ]/ v' r) B2 n9 n
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;) F. v/ `) ~! P. s- @* q
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
    6 u/ p  Q$ c# ]: v. Z* N
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    5 [6 f" ]: C; d0 f
  45. # ~) K3 k$ I- I$ Z, {* l

  46. 6 }3 E' G8 h/ Y' V1 ?- r
  47. # E9 @2 \" {8 w: y
  48. * j2 r7 p* i! z
  49.     /* Configure CAN pin: TX */   // PB9- ]' w/ w: L7 ]
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    8 a. F' _; t9 ^' ?& W# R
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    , {8 r1 b! U" l% {! V+ z
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);' J! Z% G$ u" U% N, n

  53. 7 w% R* w# E9 B6 d" i1 X$ _
  54. % W# O. p8 o2 J1 Z6 V; x$ L1 d

  55. ' j4 R8 }. }3 O; h% |* w

  56. ' [- N+ I6 Y; F9 o4 [& W, r
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O! _* h, X; S7 V5 h+ b
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    ; l, f: `: j# L7 [( w$ W) J) v

  59.   K( k# f2 ^& {: L) J+ u* Q

  60. / L% p8 k/ K8 x( |8 P- R, o

  61. 0 ?) M& R- s( Q: X7 y$ C/ ]

  62. : s3 Y7 H) J$ q0 W& Y
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   % ~4 |" X, C' T
  64.     /* Configure the NVIC Preemption Priority Bits */  8 K! F" ?# ]  O- D) s3 K$ X
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    0 Z$ p: v, f" b) z0 |7 [

  66. 4 G. w, r5 s, ]3 ~

  67. 6 Y- a: t$ L9 \  e

  68. + y  [8 d! C  a7 y" T1 H. q
  69. 2 z* |* ?0 J; S  F- [
  70.     #ifdef  VECT_TAB_RAM  
    + l+ N, t0 i, A! C3 N/ n, Y, U  g
  71.       /* Set the Vector Table base location at 0x20000000 */& ~" c+ i* Y3 T' n! V1 I
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);; i- |4 K8 n7 z3 p5 s# T. d
  73.     #else  /* VECT_TAB_FLASH  */1 k( M" J  N$ U9 Y, h
  74.       /* Set the Vector Table base location at 0x08000000 */
    3 K1 \7 ?6 r. O2 b9 i- y' l4 r
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    ( w* D0 O5 [# O3 q6 l9 ^- P5 ?
  76.     #endif
    ; M) x) X, f' }) k
  77. . P* ]3 T( u, V! [) ^) H
  78. ! `# I6 }$ a- m: D; U: V
  79. 6 }/ f( m( b2 V! W% M
  80. ! @/ e9 s# w3 b6 c
  81.     /* enabling interrupt */1 H1 o8 R7 x8 J8 w+ Y( |
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    1 b2 S# c" t9 B; I' n
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    $ S! b: D, e" k
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;+ }/ y9 \1 B% X7 v
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;. t, k) i3 _6 W- ?1 X; m
  86.     NVIC_Init(&NVIC_InitStructure);! S5 I( r& e, ^7 a$ t; r

  87. 5 y7 ^" N" u2 R" y1 I7 }( Y+ B

  88. - z+ }: v' }- V( @

  89. ( I3 m! F( T# g0 {7 p: H
  90. - T  d( m+ N: I8 N& Q) J! c
  91.     //CAN_INIT();//CA初始化N模块
    8 f. Z$ x* ?) ^& |5 i8 o' C
  92.     /* CAN register init */; x3 V& ?5 m, j- C; C
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
    3 z# B3 s  Y$ \/ r5 v
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入1 A  [7 _; s- s# e" I0 R

  95. # [1 Z! N' p& u
  96. " X! G& n6 T! Z2 T$ b. v

  97. ; C" S( c! s; |' o

  98. " ^. O1 @; w/ O% }% M: @# i3 o
  99.     /* CAN cell init */
    + E) O  a( ]; ^
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式# l2 N% Q# D0 B' W. a; k$ j
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    6 v" }9 n0 Z9 K2 ?: j& P
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式5 c3 Y! K9 W, i/ a: D9 X( z
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    + P' L: n% T# C
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    6 {) I- S8 Q8 n# f5 J
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级! ~8 p' ^5 e5 u9 {' S3 W
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    2 N+ T% n  o; x- y5 I( F1 N9 L0 _
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位9 m9 W; N- p% J
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位: G' D& i: C: R0 B- q! S! I
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位4 `" J3 |% B: Q, x
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60+ o5 k3 g5 u& `5 q, ~5 C% B
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs: U6 \. P1 _* ?2 O" I/ }" l5 K

  112. : p3 ~: P0 M. Q  i/ E) e$ x
  113. 6 h3 u- T) {/ O, I9 `7 w% G
  114. " N( j5 Y8 Z2 D# C- g$ z) u
  115. - F9 ?% }0 Q' j( |3 i
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    - V( k7 A0 T) m5 @
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    7 t' e. G3 G# _3 I  c* C+ j
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    % c6 b7 S' C( f+ ?6 ?
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位1 S9 M9 [) G. l2 d2 ?

  120.   ^- @! A" Q/ Z$ X! z
  121. + S9 e# U: h' h/ ?. L! M( i
  122. * ^: S! E: H* K" P! K9 B

  123. * v0 R( f9 t6 P2 p
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    , N0 j0 b6 x' E" n. [
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    & |. z" ~+ j* [9 O/ y
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位" g4 p+ H, f0 g* a( Y0 p
  127. 7 _, o* b8 |3 b4 G+ b

  128. 6 E7 d' e8 n3 x4 U) N0 ^& r

  129. 0 W" K) L5 k9 c" L4 `9 E

  130. " \0 n* _( @: [6 Q* D0 B% a& ^$ z
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    ! R% m2 t: t3 q( Q0 Z: G
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值! z! V; G' k* j3 o
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    8 J( W* v5 g9 B' O4 _
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器/ M1 t  Z& I: F$ X- H
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    + ?7 T0 z% ^) h( d% M( F

  136. 2 x7 v  I5 y  |6 W- g

  137. % `1 y$ [9 R! w+ E% D0 B# B' N; o+ R4 q
  138. ) E8 l& n# V( l

  139. 7 h8 }+ `9 K6 |; z4 s: Q0 h/ x
  140.     /* CAN FIFO0 message pending interrupt enable */
    + w. J$ q$ ]9 Y/ ~( u. X5 w9 h5 E
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断# @% y0 v* A1 h- f. V) ?
  142. }, J1 L. y0 p; v. a% e& j5 J- _

  143. 4 k. w* v5 T5 L; r5 h5 K

  144. ; }3 n  H/ D: y3 A2 C# @3 r1 Y( p- P
  145. + L2 D0 `5 L: H9 h) K
  146. 7 H3 M* C  u+ R6 V' H8 F) }, B+ K4 N
  147. /* 发送两个字节的数据*/8 S- `$ h# m  X8 R+ v1 Z; U
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    & \. R2 m' Y8 c1 }
  149. {6 r6 }* H2 l# M! }$ |
  150.     u8 mbox;
    . y/ `: J; y) u3 Q: K
  151.     u16 i=0;
    " ]! [0 H+ W4 e3 ~" i
  152.     CanTxMsg TxMessage;  
    1 M  V/ a- k- ]

  153. 3 U; ^- t3 n+ Q; D# o
  154. 8 r! j! l1 {* k# |
  155.   }1 v; D7 ^. l* F

  156. ; Z0 E3 l2 j9 e: e* x7 F# C
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    3 v4 P: A8 }. F+ j' q9 }
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    ) B5 C2 w9 e) h! h/ _/ Z
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    ' S, S+ j+ L( X0 ^4 X
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    / |9 J* }9 \. S1 L
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    % @$ ^% |+ D8 n/ w4 a5 A) m
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据: L6 @! W) i  _8 P, [
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据
    8 E" N5 K7 n9 i; Q' @

  164. 4 o  [: h7 {, R$ U
  165. ; y" r# d3 }/ ^, T2 y8 b

  166.   `% o2 q- o& _# X1 A* [( t$ I
  167. , Y' Z4 F; `. q
  168.     //发送数据( J* C& l& m4 Y/ S. c% J. q
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  # e1 h9 ?" O  e: y6 {% D9 o3 @
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    1 i* U5 X7 V7 ?
  171.         i++;    //等待发送结束
    2 ]% i4 Z% Y" n, H  o# e0 R
  172.     if(i>=0XFFF)6 u) o3 Y. ]4 k- S6 l) y
  173.         return 0;+ O! N2 T7 O: G9 R3 c) U2 |
  174.     return 1;9 i3 l" i* u) ]( f5 B0 n
  175. }' P& P; o4 K9 t2 g
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    6 y( w( v  P! h/ j% L( b1 K3 D8 X
  177. {
    * r( p, k% t* _, e7 N" A6 Q
  178.     if(Rx_flag == 1)//发现数据8 S) m8 t7 g! V7 g$ A2 \
  179.     {
    4 ?3 |3 U8 {, \; r2 \; z
  180.         *msg1=RxBuf[0];
    1 {6 A+ M/ x) l: E+ [. T
  181.         *msg2=RxBuf[1];# e4 I: \' i- F. _
  182.         Rx_flag=0;//数据已经取走,可以更新数据
    ; R8 Q2 j5 w/ W) n  `/ E
  183.         return 1;) |/ z! p: @/ E4 D1 ?- @, R- _
  184.     }else! F8 C6 P% ?- _6 Y
  185.         return 0;8 R& c2 C/ n6 n; _) M
  186. }
    " P' j( k; o2 H$ k, n3 A% H
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/, [6 t7 q9 N- I# I
  188. void USB_LP_CAN1_RX0_IRQHandler(void)
    - s: z# d' V. O
  189. {" m5 B0 ]7 ~& f/ T
  190. 5 K9 n: b; i1 F# t8 y! {$ r; G1 o

  191. ! _  `( v0 [- w  u

  192. 6 j; K3 x+ i5 v! J# ^7 R* m; r

  193. ! d) O* Y$ u: l' D/ D, ]$ V, {' ~
  194.   CanRxMsg RxMessage;3 [3 A  Y2 w8 |( r5 V$ L
  195. 8 F! m$ t8 Q, {$ O6 `
  196. / ~  t. Q& q, k2 Y5 p. h0 J7 Q

  197. / L, U! D, A9 c3 e% M9 f

  198. 1 U5 {2 p8 L! ]5 Y
  199.   RxMessage.StdId=0x00;( Y; C3 b6 j* z3 M) _% M( V
  200.   RxMessage.ExtId=0x00;8 S" d9 D2 p8 g0 P! ]0 E* G6 j4 _0 H
  201.   RxMessage.IDE=0;! V& _0 g7 X, R% P7 \
  202.   RxMessage.DLC=0;
    ! A* a; `- ~1 K% r! s/ C
  203.   RxMessage.FMI=0;
    4 s/ [5 M  W3 E: W8 K
  204.   RxMessage.Data[0]=0x00;
    6 D; X1 o3 x9 `: k
  205.   RxMessage.Data[1]=0x00;   
    5 `, c5 b3 z5 ^' [. b5 e/ ^
  206. 7 g# V% P! O, k; l% D+ i$ i
  207. $ G3 Z7 [% @/ @. F5 }' s4 H

  208. / l! x2 d4 Q, h& Z  p( p

  209. * O* R  E! U- P+ ?
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  & ^# A+ |( v( y; x
  211. & B8 v/ y! {$ e* p
  212. 8 T# U$ A) f! E& \

  213. ; K* ]& U  q9 x* g' Y& k8 w8 E3 {0 i

  214. ! X: k6 m( L: L& h* H  ?6 y
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    , X, B8 s, l( p5 y7 I- Z/ Q
  216.     {
    - O# K8 z, m7 `! V
  217.         RxBuf[0]=RxMessage.Data[0];- A: y2 Z' X/ h* z
  218.         RxBuf[1]=RxMessage.Data[1];
    / N8 q9 z+ ?6 f
  219.         Rx_flag=1;//数据已经备好,等待取走8 v7 p, \& X3 u" \% V/ [% G
  220.     }
    - l0 x: f% T$ w- O$ X5 O' s/ a
  221. + q! }- m) S- E7 a: }  e& n
  222. 3 F# z/ ]8 e( D; W0 C

  223. 4 c* E0 d0 l7 _$ r' n

  224. # n' l+ V5 @8 [$ N! b# P
  225. }
复制代码
% [8 c& _* _4 Y" \- Q: X
can.h文件! f9 g  p! t7 m, w0 }0 N

; G+ i* h3 D; g- e- a2 i2 U 微信图片_20240615192757.png 7 {( s# Q" f9 [3 C" h

, B) q% x$ L1 n, o0 L# j, Z8 U主机相关代码* h# U8 P  Y% i* _6 t8 m
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
7 f! ^/ P9 ]  [6 h' @5 m8 N7 Dcan.c文件:
6 Y7 J% @, ~( v- `/ C. j0 F* Q
  1. #include "can.h"* ]$ b; o; C6 k

  2. * P3 Y; _2 j0 r: K* g
  3. 5 O1 @  N- f& ^
  4. /* 在中断处理函数中返回 */' [. y1 d' V" K0 N
  5. //__IO uint32_t ret = 0;
    ( o- U, W8 G7 T+ V' p

  6. 8 }6 a6 B7 m# \: }+ u. H1 N6 X. l- p
  7. 5 }# ^4 f" Z! [% A/ w, ]
  8. void CAN1_Init(void)! M3 E2 `# C3 k0 j! n0 m2 I- o
  9. {# ]. M+ ~+ I1 @, K1 X9 J
  10.     ......//以上与从机部分相同, {/ G7 s  @$ _, m" `' _
  11. 9 X3 x: E' F! f0 d& W

  12. : h" z. a) v9 b1 D% |) v! ?1 q" C; [* Y
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
      g* m; e$ R1 ~. w
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    " F5 B+ t0 W+ X& l) G
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    0 Q, v8 c3 L, Y+ B, ~* E( U
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    * Y4 ^3 s+ L5 W1 z$ |+ _  v
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    4 S& n$ M! q- e
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    6 t8 \6 w! B( o) Y
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值8 f3 b. O! @; o& h, [' U8 j
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值+ L( b) V7 L. R0 o
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0% V( \: P) r% B. S2 r
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    ; |! @3 F" m6 c
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    ( U5 c! O% U$ e7 m$ b2 ^3 M
  24. 5 p+ M+ ~; ]4 b9 ]3 A

  25. 4 {1 N: V8 t4 u' s. y: N8 W
  26.     /* CAN FIFO0 message pending interrupt enable */3 g# i' e0 r: B/ M9 _! K$ Y6 u2 {
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断! n/ A8 P' J- z5 N- q2 v
  28. }
    ) w, J' h. O% Y. m( C: `5 a

  29. 0 H, y8 G/ V5 w& e/ P

  30. 1 Q, ?9 I. e9 n+ {( D
  31. //接收数据缓冲器$ W. _3 i. N! Y( \
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    8 g, q  R- o' |" q! l
  33. //接收标志位
    5 P4 D3 k6 N2 b4 _, S/ U
  34. u8 Rx_flag=0;
    8 [* T/ R$ y& ~# x; Z7 Y
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    , v' x  w% x" @
  36. void USB_LP_CAN1_RX0_IRQHandler(void)
    2 B. O4 g+ L9 d5 ~# _" ^. w8 H! O' n. \8 L
  37. {
    9 b% Q% G  R7 T7 A
  38.     u8 i=0;, m, h1 k; C# i" o6 G, a- r, \
  39.     CanRxMsg RxMessage;1 b2 {/ A5 X5 j" U7 W$ V9 a9 n
  40. 3 |9 Y% G, \: M
  41. 0 V! v/ Z) R) j/ [/ @7 G5 |
  42.     RxMessage.StdId=0x00;* m! ~9 T( u, B$ S! ^' ]: m7 Y
  43.     RxMessage.ExtId=0x00;6 ^% R5 E: i$ u1 d4 S9 a8 `+ Y* Z
  44.     RxMessage.IDE=0;
    3 n" l# |: j! S3 X; H6 O) d/ H6 Z
  45.     RxMessage.DLC=0;  i( g: h* N1 c' U& `4 w1 K/ N
  46.     RxMessage.FMI=0;
    # F3 b+ U/ X8 g! Z# D
  47. / z# O# Z7 k5 s
  48. - D9 g$ r8 i% G
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  , ?+ O8 ?# R5 }/ N

  50. 5 t% T# c& y1 S
  51. & i! s+ S+ D; _8 e4 ~9 {0 ?
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空# c' N: _2 S- e) P* H* `% ~- T
  53.     {
    0 ]$ g/ O! K( z9 A2 E, c
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据7 Q2 W' N" m' U) O. H, h
  55.         {* _) E3 ]5 ]$ Z' z) e8 C. m4 h
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];
    8 x" q! s% {& Z7 r& ?
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    . V. j# y3 O9 P
  58.         }
    # ~+ B9 S! ^0 ]* |: J+ E
  59.     }4 C4 Q" Q4 a- G
  60. 7 I% @0 x8 d0 _& D! ?" c

  61. 7 Y% H- w, y1 C8 {5 `' |9 A
  62. }) [. {5 A  Y  {3 T& J! p4 X

  63. & h8 a6 @/ M! z
  64. 8 W2 P7 m/ o  z: z* K
  65. /* 发送两个字节的数据*/
    3 v* @0 F& d# U/ ]4 d( S; Y. i
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    . L$ B) G+ O$ n
  67. {) m6 a3 U: W* ?, B
  68.     u8 mbox;
    - h9 |9 |- F- Q2 a
  69.     u16 i=0;8 l( ^, j% K) b% K$ ~( q
  70.     CanTxMsg TxMessage;  
    6 g6 h0 U1 g; g4 @) W
  71. 1 k- J( O8 {1 f: |6 Y8 X7 s

  72. 4 V+ v. D6 J/ ?5 ~
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x001 _" f8 ?, ?2 O! ?; e/ }
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000! E% ~+ a. w9 D$ @5 e! _! n  J: {
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符) e8 F' w! Q5 H/ Y* E# ^, C
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧1 Z) X, O! z# a; c& ?4 N
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    8 p, m& c1 \6 _$ }9 O! w7 ~# S! D5 _
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据" r- j9 \0 c- j. E+ R
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据2 W. t& R) b! h% _" I

  80. # r4 y  ?/ }4 o, {

  81. % J" c! L. h8 ?
  82.     //发送数据
    9 F' H# i" ?3 C; T" M8 ?# Z8 W( [( E5 C* _
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    . Q7 e; R) R* Z: l4 N6 [
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    + n. w& ^# c9 n8 g' d: f8 h  m
  85.         i++;    //等待发送结束
    ; E4 @; s: e- F( |% Q% A
  86.     if(i>=0XFFF)
    4 X' F) r2 `& Q' M. Q
  87.         return 0;//发送失败
    - c% _" c" p4 X" P# [2 A
  88.     return 1;//发送成功
    * W" Y" ]4 S3 ?! k9 l7 F
  89. }
    ! @' i1 l' E8 T# ?
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    0 S4 U3 P/ I' T3 E
  91. {& n8 q: G; R9 F9 p  H& Z
  92.     if(Rx_flag == 1)//发现数据- p% L4 D- {% w5 G, M1 E
  93.     {
    & Y7 W4 _6 [3 a; \, _
  94.         *msg1=CAN_RX_BUF[0];
    1 t7 S( Q( d. W: T/ I& |& O
  95.         *msg2=CAN_RX_BUF[1];
    9 {7 j& S8 c9 A+ N( ~
  96.         Rx_flag=0;//数据已经取走,可以更新数据' a7 X' D) K$ p2 F
  97.         return 1;4 p4 e7 k" g8 t9 q) l" z
  98.     }else
    ! r7 P9 A& L# M+ k4 N8 _2 u
  99.         return 0;2 e( G/ K2 X3 ]# [6 H. b2 S$ z1 P, Q
  100. }
    ( [3 S# A+ B! l! e5 X) r
  101. void Clear_canBuffer(void)
    3 S. g9 y4 L. G5 R
  102. {
    , c# v4 C5 J( h
  103.     Rx_flag=0;//清楚接收标志位4 t) k3 j0 R  T. c0 Q% b9 G
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    : G# X0 U1 G" q# i% T" b. w
  105. }
    + o4 @! Z) H% U" U( }4 E2 T
  106. u8 Check_canRX(void)( {3 m( r7 s" s2 a6 b
  107. {
    6 D+ A2 }7 v3 s  C- [
  108.     return (Rx_flag == 6);
    4 s1 G( z9 \9 K9 x( O+ _
  109. }
复制代码

# J" e$ ?( a' v2 L8 B
3 T( y- F8 p' F; j+ m
can.h文件:
' s& M, o% u$ U
  1. #ifndef __CAN_H
    3 a' U+ |7 K. ~9 v. @/ B" ^
  2. #define __CAN_H
    ; x6 m9 N; v! X+ |9 |
  3. ' r6 P4 t5 N3 L( U( a
  4. ) N" R: `1 _; v/ d* m9 x
  5. #include "sys.h"7 B* `/ Q+ G: `4 v% w- r" l! }3 p
  6. #include "string.h"  H7 W" |7 I: @/ }2 q

  7. ; `4 ?( t- c$ L& F" p

  8. . E, O/ {! l: i7 q5 l3 W8 c) `
  9. #define CAN_RX_LEN          30          //定义最大接收字节数' ~8 s- K& B4 O- J: `  z# n( G

  10. 1 Y& ^# D3 i8 `! ^/ o: h
  11. 5 s5 P1 C/ O* y4 y/ _5 Q3 G
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    3 M) u7 q) Z3 V7 Z

  13. % e! k0 W" w( G  v+ g& h/ a

  14. 7 V; o0 ~9 ^# ~: _% F
  15. void CAN1_Init(void);9 E1 C3 f( n. n0 v5 T
  16. u8 CAN_SendMsg(u8* data1, u8* data2);6 J: M& V5 p$ n. z( ?6 ^! g/ c
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);5 p3 g% E3 Z+ e: r0 A+ \9 b4 K
  18. ) R9 ~9 Q! y- s. {( Z
  19. . i7 e# i+ V/ B4 N3 [; R$ {6 O
  20. #endif /* __CAN_H */! t# x" M8 L' }% q9 }
复制代码

0 V. B, h, j! b* A; B) G: u* e# X9 g5 h4 G
转载自:单片机与嵌入式" l7 v4 g/ t; S/ Z: w$ T3 R

! f7 J% B9 k/ z4 m如有侵权请联系删除
4 i8 o$ s) Y- ^8 g
6 e/ h! d4 v$ t
& T2 c8 H* m$ f! b$ U, Q0 D' I! x% Z2 L

% E2 `9 ~1 I  m. H  A4 E' r
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似分享

官网相关资源

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