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

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

[复制链接]
攻城狮Melo 发布时间:2024-6-15 19:28
CAN通信
1 t- E3 b0 c5 o  y    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。9 w$ l  ?2 R  j9 n4 p7 u

& U% ^& C, H  g$ [" m4 ?& _ 微信图片_20240615192751.png
- y4 {- o( X" U5 j0 W% i: f
2 k: O4 U0 d9 W2 y" F2 e    CAN协议是通过以下5种类型的帧进行的:! K+ A+ k& h/ g9 }; ^1 O& Z+ A
数据帧3 n/ ]+ ?" L8 y9 X& U" f
摇控帧
) i- [8 U0 a! r错误帧
2 L1 ~7 i6 k6 G, \4 i- z过载帧
+ \" d7 q/ |+ k3 n0 [4 q帧间隔
' R4 X6 p5 D2 v& E. }  c
' J! F6 M, ?2 c) F5 q1 X  K+ \
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
# a, e/ ]/ e- d7 s* d' d
. `6 q& v  l8 g# o
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。/ U( k1 A' |' A
    数据帧一般由7个段构成,即:
+ H# Q9 y( G) m: a1 s  Y(1) 帧起始。表示数据帧开始的段。
2 U- g1 c6 y- j% Q  h(2) 仲裁段。表示该帧优先级的段。
" q" V: Q# n) C$ D& |(3) 控制段。表示数据的字节数及保留位的段。9 t, o0 L4 ~  m( P6 E  F0 _3 \
(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。9 a: b4 @, d, f1 E9 ?  e, j
(5) CRC段。检查帧的传输错误的段。5 z. s" {$ |5 d
(6) ACK段。表示确认正常接收的段。8 D" ~) _* [2 G* k
(7) 帧结束。表示数据帧结束的段。6 J: t* R8 X& i, u8 f7 V
; a0 ~( I$ q0 l" A; X1 y
    明确了数据帧概念,还需要理解一下过滤器的作用。, s8 ?" ^, g# q, L( f9 F/ x
* E. d' ]$ s$ b% s0 Q% l: }5 C
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。3 Q0 u4 h# M8 f, g! D% I
$ J/ K8 V5 X$ X: a0 q
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:  G8 }, }( O; x; e& s2 ^: c. t" F
1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位$ X: T6 `6 w/ b9 Q
2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
8 a  I6 Y' m- ~, e( U+ h( [4 n( X6 n' X
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。7 |9 i2 N( m/ y6 r+ K3 u; d
. z6 l3 a/ b- w6 L4 _
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
6 ~! ?4 \5 e$ e; ^5 `
6 b5 q, [( A* ]  T9 A
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。
+ u& P- n# S: F( W6 z. F! Q5 ^
7 q1 K4 M  c8 ]- n
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:- I* a# y2 |: `: o

4 h0 o/ i2 P( k: J, @ 微信图片_20240615192755.png   h1 C9 l6 Z6 b  X5 }) x  t. U

: M" O1 c* L/ i  E+ q1 @* I8 s$ A( g    在程序中就是:5 h+ g2 Y, S6 O8 `, c* L( f
  1. //要过滤的ID高位+ W  R6 ?% r& k: G( q
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    : Z! B0 G  L/ D$ R. @- u- J3 _3 c
  3. //要过滤的ID低位                 - Y9 `6 e6 o$ g( f; B
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
      z9 x% k" p, @0 F& b0 Q
  5. //过滤器屏蔽标识符的高16位值
    # ?5 {+ k' M' ?/ m$ _+ M
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    # g  T/ n; I9 m" |
  7. //过滤器屏蔽标识符的低16位值         9 H% h  X+ l7 H. I- g
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
1 L& s$ D3 U# N1 b; `+ S: H
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。5 s, y' J. O2 e& V  d$ F
4 Q4 _8 f3 }% R0 C# F/ k
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
( n; W  \% }# \8 D9 @' g; a8 B
程序思路$ A! a, Z8 u: [# X  ^6 U
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:( O! v" F5 Q; x6 @2 z% Z2 |4 k) g
主机:0x1314
$ B! V0 {; S( R从机:0x13118 w5 @- [: b- R5 t, K( Q

6 k6 L# E: }* X
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
- ?' x; r. D  q/ m/ K$ d8 I  ?, H3 B" h: C- r7 O3 n" G& S

2 D  F. Z  D5 s) p( Q相关代码
6 N; a0 ^6 I: p" j6 r, k    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。! n: ]* C' x9 \/ O

: y! q4 \4 r" u& q# n
从机相关代码2 p2 t% N/ V* k" l  Y8 k0 Q
can.c文件:1 D- b$ k8 T# S6 O; B
  1. #include "can.h"
    1 w, y; r: C6 f2 y+ w) L. M* `
  2. ! a/ Y/ O* @; I9 [8 E
  3. & ~7 ?. m1 S( R1 B( }2 @+ @. {
  4. 7 m$ v/ N8 G# X* \  X. a- c

  5. 8 X! O4 W; K- A, b/ t7 s) k5 t, P
  6. /* 在中断处理函数中返回 */
      Q7 n6 w, j" h7 g/ l  V; w
  7. //__IO uint32_t ret = 0;) t$ l% I$ O6 r7 {% Z

  8. 5 C: ^4 y( j  b: [, @

  9. # Y" [7 [6 X0 E, ^4 F
  10. & @: S- t& @" j

  11. 0 N! _$ c- T2 a* B9 {
  12. //接收数据缓冲器
    / e2 K5 {. Q3 c5 S7 t
  13. u8 RxBuf[5];) r$ p0 ^; c" ~4 i( S' A
  14. u8 Rx_flag=0;
    ) u8 Q  \# u4 N, [6 }
  15. 0 {2 F" g2 u; g) g" ~

  16. ) H  Y; w9 ~# w

  17. / n% X$ {+ A' D( _- i& t: [
  18. 2 H0 t, {3 e; R6 ?, K5 y3 c
  19. void CAN1_Init(void)
    ( a  T9 [' Q% [, n, B3 O# ~4 D
  20. {  f" l9 y% z, M% q; i
  21.     GPIO_InitTypeDef GPIO_InitStructure;
    ( D4 V8 I! e+ D8 k& g1 ^" G; S
  22.     NVIC_InitTypeDef NVIC_InitStructure;4 I' _; G: U: ?0 C( I7 `5 v
  23.     CAN_InitTypeDef        CAN_InitStructure;# ~8 w3 `/ i$ D1 H6 B2 X1 C
  24.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;8 c: C* o8 k- A; @. u! U1 o# B6 \& P

  25. 2 j: R6 F& {7 b0 Q  v

  26. 8 m6 E. j7 n7 C

  27. : c5 f' Y) `5 p4 c2 x
  28. ; r5 X! O. r0 I" v" O# U  g' ~) [
  29.     /* 复用功能和GPIOB端口时钟使能*/   
    & o* e9 z% P" j6 f, a. q2 |7 j
  30.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     
    ! E7 }! e. n, D( l5 G, F
  31. ! Y) @( Z0 ^2 ?/ ?! j7 w' C

  32. " _* d4 r6 {; {
  33. . x( h% }! |) ]

  34. / J7 l4 h$ g9 ~* q5 E
  35.     /* CAN1 模块时钟使能 */# F: u( W4 a9 W) Z$ n
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);+ r( U' k. C# g0 B- V
  37. ) h4 u8 w# b1 \

  38. , t6 D: d/ d0 Y* J+ d  P: O

  39. & F( R7 [/ ^  n
  40. ) Q( J2 @- q6 W& \8 K, e
  41.     /* Configure CAN pin: RX */  // PB89 i, m; t6 \- i% r4 R) F
  42.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;; d6 |/ N9 l8 `9 H
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入( S% Y, ^( A  t- j+ T
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);( H' |' c  u+ N: y1 C5 I  y/ r
  45. ! k% |# q4 K4 S6 d3 ~

  46. % f4 b8 @3 r5 P* m- a) K
  47. / v4 O4 f5 Z7 ?

  48. 0 f/ k% ]$ ~: ?. L  k7 }4 [4 K3 ~" R* ^
  49.     /* Configure CAN pin: TX */   // PB9
    5 l$ M+ g4 e  l5 _
  50.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    - Z. b' i2 y1 A8 B4 G! ]
  51.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    - w6 ~/ p( c8 U2 H. X( W
  52.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    / u4 f& l, ^  q  y9 [

  53. 4 o: W9 @( r9 j) G1 Q

  54. " Q1 p, A) T: j' U
  55. $ G; }, e  `3 |& m

  56. / Z! B+ Z: S+ r* B& g+ |
  57.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    / `" I4 ]) c6 Y; Z  D6 J' W
  58.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);0 m& Q- v; i; p0 ^$ n6 {7 ]1 `) K
  59. 9 f9 J% I* a1 I& z5 |. H  t; g, J/ e

  60. ( }( ^* I* {' [/ F

  61. 5 @" m# o  E# h3 j9 G
  62. " f3 r( X4 u) M6 `
  63.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    ' c7 I/ X) M  c% ]
  64.     /* Configure the NVIC Preemption Priority Bits */  
    ( ~) Z' m! A- m0 o* E) A# j2 e
  65.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    - C9 h2 t7 y* }; J: \& A

  66. - }. g% R8 I" c1 x0 N: `

  67. 7 k* b* }7 u" D# [

  68. : s8 \9 ~$ {. \) v

  69. / O5 t$ `# A) y9 X
  70.     #ifdef  VECT_TAB_RAM  
    0 ^( x; d5 C; F% V) i3 C
  71.       /* Set the Vector Table base location at 0x20000000 */' w; |! v# D3 V$ J6 L) t2 ^
  72.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    2 q) o" @8 l; S; w% A, \
  73.     #else  /* VECT_TAB_FLASH  */
    0 s' e* o, w4 s* [
  74.       /* Set the Vector Table base location at 0x08000000 */0 e% [& S2 Q- R
  75.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   ( X3 ]4 x8 @" [* H+ n
  76.     #endif
    5 l' @! A  M# [/ \8 M
  77. ) O! `$ C  u. |$ \/ t+ d3 _- g

  78. $ o: X) o% O' `" i

  79. 4 B& J4 }. e1 D4 C

  80. 1 G8 F! Q% u# N, y+ h
  81.     /* enabling interrupt */0 }) ?3 o- @1 m8 |; L. _' r
  82.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;* [' m5 U$ R. x6 L& w. R
  83.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;) ?" m, T3 V4 S2 I
  84.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;! y1 r0 R6 b  A! K; M' ^* j
  85.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    8 t0 U' z! L0 I  O( S
  86.     NVIC_Init(&NVIC_InitStructure);
    & Q0 F1 ]9 N& d8 T

  87. * a" }* k2 A, }! d0 y# z! z

  88. " J: T, M6 J2 N: J- ]! @

  89. / t5 C0 c1 Y) q: F
  90.   G2 }1 @# X& F3 j9 T0 P/ [
  91.     //CAN_INIT();//CA初始化N模块' f# ?, q( U1 @: m
  92.     /* CAN register init */
    , U3 L. m( l6 d) [; M
  93.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值/ U& \5 r% L& E0 Z1 A' @8 I( U, V
  94.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
      j/ m# X" Q" D$ v- \' o: \

  95. 7 ~; J% `% y3 w8 j0 u1 k5 W

  96. ! |& ~2 T1 m- k. X% O: f4 s
  97. 5 {$ p# C' S0 J- f( O  S$ g
  98. 3 K' @1 c" b5 k
  99.     /* CAN cell init */. D/ X, c- \( r5 {7 c: x3 s2 G
  100.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式+ d& b, c4 o6 v% O/ _
  101.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理1 {7 S6 ?/ e) }2 L) W0 K* t/ D
  102.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
      e3 \, y; D) O% O4 Z* L$ k( {  C
  103.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    # u. K5 p( i! s
  104.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式$ m1 z: _1 U  O2 w1 x, U% M
  105.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    1 b$ x9 Q: h6 l0 g" ?& M! ^
  106.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
      L5 O- P. l8 |4 V" ?6 ~
  107.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    + T% Y, |; o, T  i
  108.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    6 J2 }/ b& E3 t$ I9 t6 J* t
  109.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位, y) f8 R# p' i1 k. D  c
  110.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    ; v/ a( L* J  Y# t# D4 Z
  111.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    ( e2 I1 I0 Q  w3 {9 a  l* j

  112. 6 \8 G" x' z) z- I) L. `

  113. 1 t& D1 w2 e# `/ n3 ?

  114. ; V' h# C) {2 j
  115. - `) N8 I* P% x+ O4 [2 D9 D  W
  116.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    , \9 w$ {7 f) E% E% Y
  117.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    / a2 h1 [5 E( t4 p3 s2 h
  118.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    ) {2 Y$ U0 T7 g) V
  119.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    : C. h/ {2 n/ r/ T  K, G

  120. / Q. t: w# B& N- T# n3 C7 s

  121. " @  C" Q$ h/ ]; b* o
  122. / S1 m$ P0 Q, z/ ~

  123. 2 G4 ^) j/ t  z9 \& k" }
  124.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    " q3 _% w7 u4 t* q4 W0 t" a
  125.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    - R, C0 n7 I3 _, ^
  126.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位2 D) S) M% k/ H6 u) Z5 C

  127. 5 a- D- k* y3 u5 M! m# e

  128. ' I% m- u9 g4 L
  129.   K2 D; y7 n0 W3 z! V( s8 G
  130. 0 I8 t1 [9 Q: \  y" N3 \% _
  131.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    8 {) o% d8 _2 S9 z
  132.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    / T: z+ k' I) v
  133.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为09 _" H7 n* f! d
  134.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器) H7 }8 D2 R/ Y8 M& A5 N; L
  135.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器( A  h. a9 h: l$ x9 f2 V
  136. ' ?8 [; C8 `& Z- e2 r1 K" A

  137. : b1 P  E1 ]* ]" w5 R# D+ H8 U

  138. , p' |! X) Q: I) K( A

  139. 3 Q" e# }6 _' H; r7 m
  140.     /* CAN FIFO0 message pending interrupt enable */
    6 W/ T/ n# i, t  _
  141.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断0 r# p+ x; ^6 S3 |$ t1 \. i
  142. }! `6 S4 b) V) g3 G
  143. $ e! l/ Q, P# A
  144. " P* O2 I* n  l+ u. H5 G
  145. 0 d/ v3 o* E9 a% S. a0 q/ r
  146. * j4 S* ~9 R) Q! j
  147. /* 发送两个字节的数据*/
    7 [" I  q4 G/ F' g2 F
  148. u8 CAN_SetMsg(u8 Data1,u8 Data2)! H# a4 A. e" B( _* e2 o
  149. {, P; L0 O1 S! ~
  150.     u8 mbox;1 W" t0 h' R! p+ X6 l5 _
  151.     u16 i=0;& k4 ^0 e5 m. y3 z$ ^( h" j
  152.     CanTxMsg TxMessage;  7 b4 J5 v( L+ m4 H8 z0 [. S. y/ r

  153. : ?: U) E9 _/ b" w2 }! a
  154. 8 f! C( ~. h4 M5 }8 X  a- t) Q

  155. 5 o0 r  o6 w+ A  z4 L" [) f
  156. ' p& e0 ~4 C' U7 @( @; W/ Z( T, l
  157.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    & n" Q1 V" o( ^7 J, S! b- E
  158.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机# ], u' E$ q# y. h( X! l2 n7 p
  159.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符9 k, m8 w5 T3 ~$ i% V4 H* w  b
  160.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    . L' J( \9 I: c+ ?; @+ V& v! G3 a
  161.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    & f2 j2 O6 x) P. `  m1 c$ }9 I% T
  162.     TxMessage.Data[0]=Data1;    //第一个字节数据$ O2 x6 n9 U5 O
  163.     TxMessage.Data[1]=Data2;    //第二个字节数据
    / z$ f0 U  ?" {" A7 \5 ~; C% Z* \
  164. 6 x/ q0 M; D" T1 k$ h6 E2 n

  165. / g2 X1 R2 ]% ^: b

  166.   }. s3 z# U& t9 r  W1 }, B

  167. ; |/ |" t1 h' u: z; k6 T& y
  168.     //发送数据: h7 p. F6 s  M/ j% J/ c) B' G
  169.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    1 Z2 b# Z9 `3 c
  170.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)): _) o3 j' m$ L1 Z; k1 D
  171.         i++;    //等待发送结束7 m" D7 j% u( q8 W. ?3 a+ e
  172.     if(i>=0XFFF)
    , n3 Z8 C9 K2 k7 Y' Z2 B7 k, J) @
  173.         return 0;
    8 }. r2 S  ]% y+ {
  174.     return 1;
    - e' a8 b% ~- I* b. V
  175. }8 o+ q: W) d. g% ~! t
  176. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)" p8 q5 s6 P- @8 V
  177. {
    ) u. I9 L0 t, E1 H
  178.     if(Rx_flag == 1)//发现数据, |4 k- r9 g4 r1 G  b
  179.     {
    6 z. D0 h9 z* O2 @1 K
  180.         *msg1=RxBuf[0];
    - B/ K9 [, ?) R5 d" Z; ~4 \
  181.         *msg2=RxBuf[1];1 y* U4 ]) @6 s+ f
  182.         Rx_flag=0;//数据已经取走,可以更新数据
    9 x4 ?0 |. H( n( S# R
  183.         return 1;/ A& t' ~. g  t
  184.     }else4 p# q$ [4 r8 u2 K
  185.         return 0;
    ; V$ v$ t" D7 W4 N; x
  186. }/ c, v9 q+ T% q: B; }
  187. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/+ C, K) t- R8 _. R9 ?
  188. void USB_LP_CAN1_RX0_IRQHandler(void)  k/ p3 S/ K) J3 b) m
  189. {
    6 k  x; J8 r, w
  190. 7 z7 b8 J$ J/ t4 d6 ~
  191. ; t4 {, r0 ^% I" M
  192. 8 E. f, J" J7 h& R0 {
  193. 8 T4 x: p; u, [2 ~/ v
  194.   CanRxMsg RxMessage;
    ) r% Y/ x" L. S$ L; [/ D+ E
  195. " ], ^  ?* W; F/ \! l! k8 V2 a; }8 a
  196. ) K+ L) T1 D9 c4 u

  197. ! e& p" c  h1 d7 D  L
  198. & f  w9 i! D7 w4 `- d8 g
  199.   RxMessage.StdId=0x00;
    ( x% K. ]# Y$ |. @2 b& u/ N
  200.   RxMessage.ExtId=0x00;' y5 Z' y/ N: B+ e: W
  201.   RxMessage.IDE=0;
    + `! X/ ^9 U& q1 x1 _/ h
  202.   RxMessage.DLC=0;4 f6 d: w. _& V
  203.   RxMessage.FMI=0;
    ; j5 u; {- @8 X1 B$ W6 d! V1 @* Z
  204.   RxMessage.Data[0]=0x00;
    / m. W/ o! P- e* @( u- D6 g
  205.   RxMessage.Data[1]=0x00;   
      h5 c2 \; b! \9 e
  206. 0 ~- i8 h6 P7 }( c  t6 k
  207. 0 }3 f- B8 a$ D& h) a) S

  208. 0 Y$ N* J7 I3 s) n! L) r
  209. 4 o: m! L1 k9 i
  210.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    : i  F% l8 [6 e5 |" X; v

  211. 8 Y& a. C5 E7 d

  212. . i+ x* b. d# j  c1 P  _

  213. % _' }) G$ U& g$ P, c
  214. 6 n" z( }- s3 @. s
  215.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    2 v* Z0 T( x3 o4 c- M% V
  216.     {
    + i/ D# j; b; g
  217.         RxBuf[0]=RxMessage.Data[0];
      o. s" ?' T6 P! }
  218.         RxBuf[1]=RxMessage.Data[1];2 X! U/ {/ s4 y
  219.         Rx_flag=1;//数据已经备好,等待取走" N* H) N5 n" g& O9 J2 r7 G
  220.     }( D' B/ X9 i3 e2 n+ P0 i
  221. 8 N6 F* S; e- f) y# O

  222. - R' r; X* Y4 K
  223. : y8 ]: r. R! h5 M7 Q' z  }6 p: f/ A

  224. , V0 _3 U7 [0 n- ^
  225. }
复制代码

" Z7 c6 s$ ~3 v$ {can.h文件
5 T9 s) i( E& k" Y
! U6 K/ T0 L* r$ Q5 {! ` 微信图片_20240615192757.png
6 v5 F  z3 K7 J; M6 J6 M( f5 o& w
5 a% A2 f5 n- R3 `7 E主机相关代码
: h4 \2 @. J7 D    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
% _6 C+ w2 S. b6 xcan.c文件:
6 F9 x' V% @4 _
  1. #include "can.h"8 r& ^2 s; ]# M

  2. $ w( Q6 n* W8 b  z2 ]
  3. % d$ F. N5 b& u
  4. /* 在中断处理函数中返回 */
      p; Y7 I5 X! c" z2 y4 U% g
  5. //__IO uint32_t ret = 0;% Y& m' `# T3 U0 i
  6. - }: e! ~$ g( H& B3 W: l

  7. + Q" D  k6 ]- `3 b4 E
  8. void CAN1_Init(void)
    ) \- p8 W; m7 }' y, U2 g/ s) C
  9. {7 P) g2 L2 D1 W9 C4 g( ^
  10.     ......//以上与从机部分相同
    ! `; X  W! S! b' U8 \) i) z: p+ }3 f
  11. ! ~# J/ k) R5 B/ r, @: H) G8 o
  12. ! ?1 j4 e8 |1 m1 q9 e# {! N
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    - t3 N1 E: S$ q* s2 h
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    ( _. z8 k4 n/ e+ {; |  |7 ^
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式$ ~8 M. D  q8 w6 ~1 W
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位: J% v+ o4 ^5 G2 g( }+ X
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值# q- X- Q2 D9 f" W2 s- b
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值+ s) m) Z2 D$ F3 j/ B; C( Q$ H
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    ) E8 a5 q1 T' x1 \
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值; @1 G: Q& C  ?! Y
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为01 A1 h3 W+ z# G+ |. U
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器3 h# Z. T) Q  }5 ~. ~) I4 T1 E( h7 X
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器) s; ]5 i4 _3 D/ T; f

  24. 5 f4 l& }  Q3 c# J7 a

  25. 4 Q' o6 \) K( r' |4 L2 U8 F( w
  26.     /* CAN FIFO0 message pending interrupt enable */
    ) j( _) G. u# f* a+ t
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断/ m7 ?) y# [2 {9 T' D
  28. }
    8 v+ k/ P$ C7 f; Q* }

  29. ; S' r6 a) y- x9 P4 b  X/ G& R; j

  30. # |% W: a3 G! P* V: {4 y8 S7 Y% o
  31. //接收数据缓冲器
    * q& T0 j4 s9 ^' J7 u+ S0 w, a
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
      C' w9 M! r2 B5 G) [5 y, p5 u
  33. //接收标志位
    8 ^; g- p6 ^9 Y. E3 [
  34. u8 Rx_flag=0;: y. ~9 p& h1 w* l
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */1 }1 [9 G# Q" H" l1 M
  36. void USB_LP_CAN1_RX0_IRQHandler(void)
    8 d  b0 W$ k' a3 {1 G0 q- H' u
  37. {1 K7 _. M) l( d5 K( X
  38.     u8 i=0;
    1 q) `5 {0 y2 ~
  39.     CanRxMsg RxMessage;1 w8 \) M+ l5 @2 z7 |6 {
  40. ( _0 C: Y" `% |: _: W
  41. $ [7 R  I, T2 g3 ?2 Z& V
  42.     RxMessage.StdId=0x00;
    ) W1 L- ^' a# X) X2 ?
  43.     RxMessage.ExtId=0x00;; R4 t( _' x4 a
  44.     RxMessage.IDE=0;, _- Q3 L6 ~7 `+ q- u: \7 e4 b
  45.     RxMessage.DLC=0;
    - O* X' q* w* n4 N2 ^- w
  46.     RxMessage.FMI=0;
    2 ?& r3 \8 ]  T3 H/ u. p1 C, K
  47. + `8 I5 ?' R+ e! U3 Y
  48. ' B4 f0 k8 d0 `( @8 G
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据    M, `: V. @1 ^+ _6 l6 _7 l3 C) |
  50. " V: j9 v" S- v$ ^5 U% W8 r" c
  51. : n( W0 G' k. F: }/ h
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空( H1 W9 ?7 S- a. R$ ^
  53.     {
    # y6 ^# v1 j% B9 S/ Y1 z
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    # R  F+ [! E, l! z; R2 e: h& w
  55.         {, d" a2 A3 R6 o) d+ N8 ^7 u
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];2 ]2 r1 _7 J  Y+ w' c$ g9 ]
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    3 E! j/ R; }4 L8 g& h
  58.         }
    6 A- A( [) t7 w9 |
  59.     }1 k) _, b0 w3 k+ \# F# k( W# E4 L& f

  60. - w. s8 z( v) D" E- B1 U
  61. 0 k& c* K+ l% o) \
  62. }
    # t/ y; s8 c$ W8 x5 ?

  63. " y0 _  w0 C; S! f

  64. ' G6 C  [2 H5 l/ ?$ y5 d
  65. /* 发送两个字节的数据*/
    7 r; ]5 R# D5 y. [  L. U- j# x
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    1 z# W" |3 h9 M3 D5 H1 F
  67. {
    ' l% q, M+ Q9 N, I3 P* X) [8 |
  68.     u8 mbox;8 D, w' h, p. P+ n
  69.     u16 i=0;1 s2 d* I7 G: B
  70.     CanTxMsg TxMessage;  % ~6 U4 i# H$ E0 X  y, y, {

  71. / Y. b1 \+ I( p+ ?
  72. " L; {% o7 _+ V5 ^6 `6 [
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00' ~( ^, y$ J2 @4 q: s5 Y' d
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x00007 N) @; c4 C8 ]# [) @# n4 k
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    + e& T  g5 b0 M9 k6 E- u9 d* F
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    ) b9 H! i) u( o) n" s
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节- q2 T& ~) I- s. C! j4 m
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据# j- g4 t5 e% \  G
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据
    * g" J' ^- `( M. t5 F0 Z4 }
  80. 3 w" k% M+ ?, s
  81. . K0 f. C7 n1 V  f0 ~0 T
  82.     //发送数据& q* \2 O9 j& `/ x
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    ! U) U* n4 ]5 t( Y  E
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    2 q" K$ h: i) w) N% v- z
  85.         i++;    //等待发送结束: {+ Q, U8 r7 n0 g8 s) |
  86.     if(i>=0XFFF)  ]* v. Y9 y6 b) r
  87.         return 0;//发送失败7 Y2 U2 c- X2 J
  88.     return 1;//发送成功0 _4 F& s9 D' _' V* N
  89. }
    ( T" H  J8 ]# J$ ^: \
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    . d" [/ a* I! E3 _
  91. {( l+ Z( \9 ]9 O$ {
  92.     if(Rx_flag == 1)//发现数据, i+ O8 Z8 Q5 V0 ?3 ^3 `. ]
  93.     {
    6 @# Y; f* @8 d! d1 {: Z8 m  s
  94.         *msg1=CAN_RX_BUF[0];
    " a$ w* z& C" N0 [1 g/ P
  95.         *msg2=CAN_RX_BUF[1];
    6 v# s0 v, `9 X: Q+ h9 v; E
  96.         Rx_flag=0;//数据已经取走,可以更新数据. B0 J1 `% u4 q: R" I
  97.         return 1;
      G9 A& B, C$ W3 F; n$ r
  98.     }else
    0 O2 V, ]; y+ c+ S; l
  99.         return 0;
    & W0 m/ |' W! g6 b& W
  100. }. H$ D' ~  h+ w! {3 {
  101. void Clear_canBuffer(void)5 B" g' L1 i  s. t% I
  102. {* R; W3 _! w* x/ t+ @
  103.     Rx_flag=0;//清楚接收标志位+ W* }6 z% T  {: ]% E, `) ^7 R
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    - A! s$ g+ w* _5 @, f/ A
  105. }
    " c  e, }4 {4 n9 u
  106. u8 Check_canRX(void), f$ c: N" c; |4 L8 [; f
  107. {
    " b& b) G' |1 h
  108.     return (Rx_flag == 6);
    ) e  k- F$ {2 J  @! z( K
  109. }
复制代码
* ^) t) m: m( D# q( a

% w" f7 H2 r2 ^  f4 v' I
can.h文件:
, J- I3 O9 L; _8 s7 @4 }0 t4 @# m
  1. #ifndef __CAN_H5 E" X6 {; L4 L! I" \, r
  2. #define __CAN_H
    + A2 r5 y: ?2 P$ c( i
  3. ; x8 A  `1 o8 v7 w- k
  4. ; b! t& Q+ y$ B7 @' u8 F' z
  5. #include "sys.h"; b" y: `: V. P+ Z! w$ S6 F3 q% _
  6. #include "string.h"
    - I9 j* }/ X3 Z! R5 L( f1 o

  7. + }4 ~. t( P! e+ j

  8. 3 S# D! f' i: v: E* U0 r- O  g
  9. #define CAN_RX_LEN          30          //定义最大接收字节数: B/ V, j9 C3 Y  ^8 \, b- Q

  10. 4 c! j! w( z+ t) w! u' n
  11. : N: I/ T# ^& }- S% `7 \/ R
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符+ f, ]. {+ g7 ?$ f

  13. " y/ d3 H! u; V9 K2 o- M

  14. , K, w/ F/ s1 g% V# ]7 G8 x# H
  15. void CAN1_Init(void);1 H# S  r* i5 D3 r
  16. u8 CAN_SendMsg(u8* data1, u8* data2);3 @1 v+ H( a' F1 E- w) A$ H: l
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    " ^( H' }, P" ], n7 Z% |6 M1 n/ Y- {! y
  18. # F+ T3 n! `' A) c5 k
  19. : o7 i  `6 |2 O, z1 S- ^9 B% P0 A
  20. #endif /* __CAN_H */9 ?- q: ]' d) |. A) d% B
复制代码
! W$ K9 D4 D0 e5 j1 E

4 E- z+ v4 g$ ]8 A  @, {转载自:单片机与嵌入式
3 i& E6 Q4 a( c" c, y. ?' |. w8 a  P7 G$ Z- c
如有侵权请联系删除
, l9 @% \* A, f! a6 [) L7 G6 i- W6 p& {* r1 ]* D

( m! ~. ~; G" s4 J  D! C, f2 q
7 X! c% y9 t# D/ Q- Y7 k
7 E9 e: ]  t, X% g
收藏 评论0 发布时间:2024-6-15 19:28

举报

0个回答

所属标签

相似分享

官网相关资源

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