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

【经验分享】使用STM32F103做CAN的收发通信

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧
    7 F' g1 k( P: g: ^* ]& a
  • 摇控帧
    0 _# H! `& D- d
  • 错误帧2 }) q! W/ D; t! o, D- s' @
  • 过载帧4 Z# R, T3 a9 I! ^
  • 帧间隔
    : Y( T/ {7 O, W8 H1 E* K) A- j
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
5 u( @2 r/ s9 `    数据帧一般由7个段构成,即:* }# K0 E- N8 |: b( Q
(1) 帧起始。表示数据帧开始的段。$ y5 X' o/ L3 o
(2) 仲裁段。表示该帧优先级的段。
2 Y; U6 K$ _- {, n' `1 k(3) 控制段。表示数据的字节数及保留位的段。
2 F9 g: v" q4 A" |(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
! F( J* ]( _+ J4 A: I/ R0 n# f* g(5) CRC段。检查帧的传输错误的段。$ a7 N5 _  ?- o( s
(6) ACK段。表示确认正常接收的段。  _7 |, y  x; V# G: S
(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。6 C4 e. f# z. \0 p0 C5 L8 E
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

    4 ]. m9 P: ]) `0 ?' i' f
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。7 _. t; k$ H* J2 X; _7 ]
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
  w! K' I: {, W
PERMNQ{)L%G}{986WRA~Q]W.png
  }4 }. ^- _+ ?, t! @# B! ]. F
    在程序中就是:
  1. //要过滤的ID高位
    0 Q. w3 `+ y2 T3 h5 _
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    # ^* U4 e3 n3 ]8 `/ C# d8 Z
  3. //要过滤的ID低位                 % U; a" D& P; M/ W! N8 t
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    9 G3 k5 k5 e( p/ l9 v, U  b8 g( S
  5. //过滤器屏蔽标识符的高16位值2 j- W( \# H( b3 L8 d  u/ l4 [
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   ' A& g# G4 V6 R9 o6 e3 m
  7. //过滤器屏蔽标识符的低16位值         ! X6 h* f7 b: ~* y6 W3 ]
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

( [. X* N/ i6 t" n& T  M+ S
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。5 a% K3 Q+ P8 B3 F5 `
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
+ {% N3 y0 W1 u; Z2 p主机:0x1314* n! ^5 c4 `. j% i
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:
  1. # d# k* b* M1 Y
  2. #include "can.h"9 X" w+ I& I/ w& o
  3. " n* {3 ^4 g5 _4 v% Z

  4. 8 j: Z- l: P  k4 F3 L4 \
  5. /* 在中断处理函数中返回 */
    ! N# X0 o8 P2 s' v9 c  D
  6. //__IO uint32_t ret = 0;
    - A/ v' J1 @: e: b* O
  7. + b% d0 b" J& M. V

  8. ' s4 C% d7 v3 q5 `
  9. //接收数据缓冲器
    , x4 ?% L5 t) ~# `" G
  10. u8 RxBuf[5];4 j6 S9 B6 r8 V' H6 w4 T
  11. u8 Rx_flag=0;. q% y! y% l+ E0 p; f8 C4 y
  12. 9 x( f2 Q$ X" Q4 f: p$ I
  13. : |5 v% K. T- g$ c& `
  14. void CAN1_Init(void)- [& `  N' V5 X, g7 g+ T
  15. {. G' j! I4 u& w* a
  16.     GPIO_InitTypeDef GPIO_InitStructure; , V# E5 R; Q+ s( `( B3 Z
  17.     NVIC_InitTypeDef NVIC_InitStructure;
    1 H3 I1 l  F! w0 t$ [
  18.     CAN_InitTypeDef        CAN_InitStructure;
    2 F, v+ \% J$ B) a
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    ' N3 d# P" \& i- e6 g

  20.   N! {$ Q: P5 G* \$ c. r, Y

  21. & B" H+ w: w( f7 [+ M& c& B
  22.     /* 复用功能和GPIOB端口时钟使能*/    + t6 m' O# I$ {! Y
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     
    & @. Z1 x5 N' ~3 u% S

  24. 6 w" ~+ {& Q7 i
  25. - H+ }* m( [$ }1 e- k
  26.     /* CAN1 模块时钟使能 */7 Z5 g; J( ~8 B* K* C
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    0 `" _3 r  X( n7 Z! U
  28. , D4 a: q' s% h0 O0 \
  29. 4 X0 u$ x8 c; z% Y  W- ]! z
  30.     /* Configure CAN pin: RX */  // PB88 k# o5 g9 x: k+ h
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    0 k4 D# }) a3 F; h& z- x
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
    4 o; T4 l+ ?1 y( I% j
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);# h5 H2 \4 n' L
  34. ; L( l9 I* a/ C( V8 N% c- T
  35. * a) ?9 f' E6 b. C1 l
  36.     /* Configure CAN pin: TX */   // PB9
    3 l, |, k; @- [7 O. e% s& g6 t3 P& v
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    7 B0 K- U: m6 m" C2 T8 V
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出+ z! d- j. B% u+ T& E) s" }
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    8 k; p! |' J- ^: q1 Z
  40. ( p4 z, J/ E+ h' _) K/ m7 F
  41. $ E4 s: o6 j3 P, d8 d5 `
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O1 S( V( T( |' B9 ?7 w. }1 X
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    ; C2 |  A2 [$ r+ W# G0 S
  44. + o6 K% e/ x/ H  c; i; n0 _

  45. . k& C3 s; n& W# }8 y
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   3 j% p2 R' ^4 g/ Z
  47.     /* Configure the NVIC Preemption Priority Bits */  $ q" h4 Q0 g- ]' ?
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    ) d- V4 j( O% t8 H+ o0 k" p

  49. : X- L4 _# q* N' a

  50. 0 H/ h8 W; U8 b
  51.     #ifdef  VECT_TAB_RAM  
    3 {5 ~5 @+ ]/ E
  52.       /* Set the Vector Table base location at 0x20000000 */
    : b5 {( j  f  K0 ?7 Q7 @# u
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); * V6 w1 k6 A! w; h
  54.     #else  /* VECT_TAB_FLASH  */- b, \9 p: C5 q3 P6 ~; }9 e! Q5 j7 d
  55.       /* Set the Vector Table base location at 0x08000000 */ % [- p  ], L  T7 ~' H! P* D
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   % ~$ @5 \( p. x4 s& }
  57.     #endif
    & h+ u7 f4 N; S# U
  58. 9 ]& u! [* O5 Q# m. v' i$ Z( a
  59. + j; M( U1 I  q9 U9 P
  60.     /* enabling interrupt */
    - [$ S5 c4 }5 K7 ?+ u* P$ N4 `/ F
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    3 t8 X& o  Q' g
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;" I3 D' z1 @2 m9 S1 a
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;& b0 m! ?. F: A3 _5 T
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 \1 t5 E' l4 T) K
  65.     NVIC_Init(&NVIC_InitStructure);
    / d6 \& I3 F) H/ g2 C; n- ^$ W1 G

  66. 2 j+ p% o: Q& n& @; K6 {
  67. * X2 _8 t* ~* s& X2 Y9 z& [
  68.     //CAN_INIT();//CA初始化N模块 % m! U2 l7 W: j: v
  69.     /* CAN register init */
    ; w. h& x: }$ C3 p
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值- K  @0 p8 r, \/ p8 o* _
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入8 s9 G! J$ E4 s

  72. 0 z" p3 }8 @0 ]9 P- o# n
  73. 1 Y7 \% Q4 y! X
  74.     /* CAN cell init */, @) N" D! p% V2 _
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式0 q" x) Z& |' S$ F& e1 H' T% |
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理! F& n0 I( n/ z3 k: k# @- L% J
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    # H+ b6 r+ e% y& p
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式8 Y. g$ W6 _- O4 b' D& x0 L8 Y: {! K
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    " q. _( i6 g* b( g
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    7 P, g% p% O/ ?& _
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    ) T7 x7 ]% S. A1 w1 U& z7 D
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位- z/ w  V9 F! b2 X
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位5 m% B5 P' `6 \6 ^3 ^5 M
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位0 B  C6 @2 U9 y
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60 ' e1 l- O: b& m3 }0 l& e
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    4 g4 P4 d4 N3 _6 |1 S; W& A- |- O  d
  87. * V) c# f' t' s5 e
  88. 6 [. t8 p7 O$ m/ y
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据* l+ b) N$ p% g3 D" u
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为10 h% n: f- F7 _; |
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    4 Y8 @* k! [+ R- y, U2 q
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位1 Z, R+ g8 T' V7 p. N

  93. # [/ [; ^. m. Z( o

  94. / e: E+ h& D2 S( l5 \! M' c
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  2 ]* O1 H! e9 @6 i4 }
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    3 m) |. ?' f$ z/ b& r8 W
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位 * ~1 X3 m5 j8 E, F1 b4 q2 Z
  98. . V8 d2 z. K2 l, X  T

  99. . ~9 Z6 q; j" r' X/ p
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    , O, U. D# C" ?4 n& ~- F0 q
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值8 V$ G' g7 \7 `, y
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    + s& g& z3 @2 J
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器$ f/ f1 ?7 g1 n0 E1 @' Z1 B! s
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器. O, X7 Q& y4 N, d* l( `
  105. ! u; U/ Z6 D9 i& D% ]

  106. 5 r# T) O# z, a$ {2 {# @
  107.     /* CAN FIFO0 message pending interrupt enable */ 8 J" e" p% }0 I6 B
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    5 F* m8 c! Q' K) w9 k# W( z
  109. }
    & S0 P. J9 _/ U1 c( _5 d: v

  110. % k9 ^- \6 p4 ]& L
  111. 7 }2 j' J+ A. d; @  O2 }5 Z
  112. /* 发送两个字节的数据*/
    + z& q9 E5 H+ a7 c4 E
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    % f) p7 S9 L& P5 s4 r/ A
  114. {
    # q7 V7 z3 y7 z( w$ `% t
  115.     u8 mbox;
    4 a* E# d; H3 K
  116.     u16 i=0; $ u( s7 U. M; i$ u$ C
  117.     CanTxMsg TxMessage;  , p/ z5 i/ _3 w
  118. 0 }2 `% A6 E) y" |5 `

  119. . H( _; h6 e6 B$ h) Q
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    7 G0 z9 f6 B. S" O9 y+ ]5 E
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    $ Q& Q( ?. }, _- `2 H3 l. N. E
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符. Z& @: ^) x) G: R
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧: I  @5 d2 E1 c8 F, U' i
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节. L1 F; `1 u, K# U
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据
    8 \% B- o5 l0 h: g: S! ^
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据 , _  s" _0 a/ T/ `! V$ ^8 W
  127. 2 G7 C" y( u, i# I
  128. + B! v, {& b8 @3 A$ Z
  129.     //发送数据7 h: c* ?+ @: `7 X7 l
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    . W  V3 k; G! T8 e6 P
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    - z- y* V* b$ O. D5 P
  132.         i++;    //等待发送结束  c0 R4 B4 B$ n( P$ t' j. u
  133.     if(i>=0XFFF)$ ?$ y  ^8 a1 n8 O
  134.         return 0;
    ; W/ D# S6 p- m9 Y0 O. \
  135.     return 1;5 B3 g, ~1 ]" e3 U
  136. }
    ) l& K% N0 }, Z  t, v/ Y; W
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)) l( ^9 n; T8 |
  138. {
    5 }0 t& d. G# V' v  c- h0 C
  139.     if(Rx_flag == 1)//发现数据" V/ }; V$ N, U6 j
  140.     {
    . O7 v. h: {7 u) P$ B
  141.         *msg1=RxBuf[0];% z; X, G# p2 D- k( r
  142.         *msg2=RxBuf[1];
    5 q; ^' t6 U* b$ x
  143.         Rx_flag=0;//数据已经取走,可以更新数据! o# p/ d1 r* M' O: i+ w
  144.         return 1;# e5 l0 o- l$ R# }
  145.     }else
    5 q0 t  m! h6 }  X! L8 `* V6 n) v' _
  146.         return 0;
    " }9 }9 v7 U  v2 G2 T
  147. }
    8 w& I& m! ?7 a8 |; h; G% h8 y! }+ {
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */. U8 |3 h, E7 Q/ |8 A+ d0 B" P
  149. void USB_LP_CAN1_RX0_IRQHandler(void)
    1 V3 ]6 s; D3 n: I& G) w
  150. {
    , [% N+ R) q2 W3 `% y
  151. 9 \" }/ o7 K. W6 M7 i& b. H  L

  152. , h. I6 ]. T4 ]) e! ^4 _% L1 l7 |
  153.   CanRxMsg RxMessage;5 j8 k9 q* N8 T  B- d* G

  154. , b2 F3 w3 h7 f7 `. o- d
  155. . d! C7 g0 s! L9 _- k- m! H& B! a
  156.   RxMessage.StdId=0x00;
      N1 q9 q7 S0 C
  157.   RxMessage.ExtId=0x00;. d- h2 T9 ?5 T1 P+ R
  158.   RxMessage.IDE=0;, _8 j! i8 U4 y2 M
  159.   RxMessage.DLC=0;
    : e: B. E) E2 B! m/ u! N& v5 z
  160.   RxMessage.FMI=0;
    - h3 P6 @5 Q+ z) }, [/ M8 f0 @
  161.   RxMessage.Data[0]=0x00;
    / M4 C5 w9 ~, \
  162.   RxMessage.Data[1]=0x00;    ) }! `' y* b0 n4 W
  163. ( U' E) c; {: W! j& _" m' w

  164. " R3 q! d* L& J: P" G
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  6 `5 X+ F# N5 r- f) `

  166. $ T) N" b( J! f% d, @7 O

  167. * ~4 |  D: V0 v. F, e
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    6 J  I  d4 o8 o& r' C( }" u$ y
  169.     {( q# I8 ^# u; Y+ K" Q" f
  170.         RxBuf[0]=RxMessage.Data[0];
    & M9 b/ B% z7 n# I" m: V& Q
  171.         RxBuf[1]=RxMessage.Data[1];
    - d9 E4 p, e- B- {, L
  172.         Rx_flag=1;//数据已经备好,等待取走
    % S, U3 P5 M. |- w
  173.     }
    7 a5 e5 i  i* z& C& X. a
  174. ! m4 L) ~' \) M, e' g8 C2 u' d1 I- i

  175. ! Q$ V2 ~3 Q: i1 c! q
  176. }
复制代码
( C: q1 w2 Y( {
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
0 g% C& n9 p" ycan.c文件:
  1. . L" Z- n" d6 O$ G7 @
  2. #include "can.h"& a) }& ^# ^& h5 s
  3. - d% r+ X( Z5 L/ c( O5 M+ m) S  {3 D

  4. ) @7 a3 Y' ~4 |7 s) }
  5. /* 在中断处理函数中返回 */
    , G9 y8 s5 Z: ]8 ~* n- O) [) E' q- ~
  6. //__IO uint32_t ret = 0;8 Z5 J! f- B5 T8 \. V( o
  7. : v0 B* \8 Z: ~, X# J

  8. 1 {1 O8 q1 c0 |2 U' ~3 u
  9. void CAN1_Init(void)
    $ K8 G) v6 l- M4 i: y
  10. {1 l+ @! S- |* O+ w$ L& E
  11.     ......//以上与从机部分相同
    . j4 V6 ~5 V' m( E. Z1 P# d  A
  12. 3 y. s  T5 v) y

  13. ; P: X4 S( r8 L1 W
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号, Y+ H8 C8 |; D& a. W$ Q$ Y
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1( c# J3 Y8 q* b* m0 H% e8 P3 K
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    % A) [1 q/ _- M: h, B
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位  N6 i7 H( Q1 ]* A3 A+ Z) `7 A
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
      Y# T5 m, {: j5 m1 V$ a+ d( p
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值, d! w* `1 {) b/ X- x# T- u
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    4 v) a1 v: `+ O# c! V
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    . u' A9 n5 A5 K4 l9 y4 T" R
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为03 p! R/ ~; c0 Z2 E4 i- Y6 _0 A2 `
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    1 T" Q  `/ P, ?  L7 j& z
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器; q: c  P, d. V" U- B
  25. , b; c+ |( O8 X9 k9 X* G& H3 [

  26. ) h/ N2 \5 S9 s
  27.     /* CAN FIFO0 message pending interrupt enable */ 0 l5 Q, d& ]. A4 ?# Y6 L/ e/ c8 l
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    ! G, h. l' N6 }* {
  29. }+ ]; h* N, C& k
  30. ( _/ Y# F) g1 [. ~6 |/ S

  31. / L4 W, l) {- W& g, W. z
  32. //接收数据缓冲器
    $ u$ p+ P* e9 S6 D' B$ N/ g
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    0 l: L/ T1 w3 f8 L
  34. //接收标志位
    6 `' w, D- ~/ T8 k; j$ g( n
  35. u8 Rx_flag=0;! n, v* w! X, q; q8 n( }* b
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */9 g- ~( u5 f$ D1 k
  37. void USB_LP_CAN1_RX0_IRQHandler(void)0 n) H( F+ I5 g) x/ m0 S
  38. {; j( @- l- P2 |$ D4 f5 L5 [4 t
  39.     u8 i=0;
    3 A: B7 P0 V+ |6 c) `' U8 m) U6 ~
  40.     CanRxMsg RxMessage;
    ! |. F$ I& X0 q/ O7 w2 _

  41. # {8 C& S$ q4 o6 l

  42. # n/ W5 [& {5 j. G* }6 [8 P$ ^1 Z
  43.     RxMessage.StdId=0x00;
    * q/ h0 O8 l6 }. X/ l! j1 a" a/ z
  44.     RxMessage.ExtId=0x00;2 o: E% M9 _/ z- r3 [
  45.     RxMessage.IDE=0;
    5 ]8 w5 Y7 g+ e  m* x
  46.     RxMessage.DLC=0;5 d) u" O) `& F* H" b4 V. i
  47.     RxMessage.FMI=0;3 S; v  X* s3 x% w, O9 [

  48. # W1 a; U, L" a; c3 G% o
  49.   J7 o) L% s# g, H/ N7 }. a
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    . W" z3 u+ m' D7 v# w  I
  51. ' y& r; R$ g# A# D# t& \
  52. 0 I2 z# \, B, j8 ~" \
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空
      A7 \8 W8 a' @+ T6 Q, n
  54.     {/ f3 X. k; k+ Q, I2 S3 I; Y* Q9 e
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据+ C9 \( g1 }" A& A1 Z
  56.         {  z: v+ i2 z' I9 a. f
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];
    / A% w2 w* S+ |5 k3 q" X
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    1 m' G: m! g( S2 d' q/ h
  59.         }
    ! y' f$ L: U& [( N, h
  60.     }
    , G5 ?8 `9 V2 y5 O' |
  61. ! n- S! [4 @4 c. i$ s- n
  62. % g+ [8 }# [0 u
  63. } % w" g5 X" b8 a- J- z& e

  64. " T; n1 O/ Y, e; z  L
  65. & x6 G1 u4 `! e$ `6 i8 p
  66. /* 发送两个字节的数据*/5 N8 Y4 z- c2 |( a
  67. u8 CAN_SendMsg(u8* data1, u8* data2)
    ' J3 d' w9 ]# A. X
  68. { 7 D. l+ ?' P' H5 C) Y9 _# U3 N7 ?
  69.     u8 mbox;
    8 b! Z: ^8 Q; o% B1 c! V5 {5 N3 O
  70.     u16 i=0; 5 ^4 Y; W  g9 I$ f% S% }  X
  71.     CanTxMsg TxMessage;  ; |6 G  `, M% Z6 |- ?1 Y4 m
  72. 6 \- w2 t% D3 W. C6 m  M

  73. & j$ s$ O8 q. n- I- a( @
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    , E( Q3 c' x( \* g9 @5 }; b% v9 [
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000$ K; G3 A5 Z" m/ e2 i2 Y( t( B4 t) U
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    5 Y% z0 n6 m1 o$ r  ?8 y- @
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    1 }8 t$ r) O5 c1 U: [4 ]: Q
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节7 s& A6 ^, g2 n4 T+ }
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据
    / T- W- r7 _  Q# C, v
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据 . C2 M8 L) q# I% D; \- a4 X

  81. ( i7 k; v) P5 C9 G( S

  82. 0 ~( D1 d" x3 h5 r/ e
  83.     //发送数据7 p. ~4 y9 u6 P" b
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    4 e8 Q0 S! G, _  G( x6 g( E
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    2 K% U4 R  C3 Q. N5 O
  86.         i++;    //等待发送结束
    , g, c- q0 |" r( P! z
  87.     if(i>=0XFFF)% m. K5 I2 `. [
  88.         return 0;//发送失败
    0 J* [8 C; [6 |# z
  89.     return 1;//发送成功
    5 A% Q/ }* c$ q. U+ K" Z- s
  90. }
    ! [( Q: I% G. }# W
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    : N+ S4 g8 `. A1 \, o$ x5 e
  92. {& p9 B9 H3 g0 `9 \* ^3 P% V
  93.     if(Rx_flag == 1)//发现数据8 w' P2 u3 b) y
  94.     {' y9 @, f7 h7 k9 ^: G3 O$ M: w, p! t
  95.         *msg1=CAN_RX_BUF[0];6 P4 Y7 P1 n2 g5 w) y0 A8 t
  96.         *msg2=CAN_RX_BUF[1];# J' Y( z5 H$ B/ s
  97.         Rx_flag=0;//数据已经取走,可以更新数据
    ( z1 C1 c9 l1 B  u0 `+ s7 }
  98.         return 1;' x. V( H! w+ b* _# p" M( [) L
  99.     }else, D& c( U4 j% s% F6 L4 B5 }8 g
  100.         return 0;
    ; x, s, X& o: A6 ]2 V4 V) A
  101. }
    . b2 }, |4 P0 z6 b
  102. void Clear_canBuffer(void)% G# p+ ^: u9 V3 _* _; Z' C
  103. {
    / W1 _3 s# i  x: ^9 P3 Z! n
  104.     Rx_flag=0;//清楚接收标志位7 _. h1 [4 p9 u( s, b' Y% o' R
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    % R5 V9 ^! p- T; W: W4 s- v% @
  106. }8 U& {$ V! Q( P% c0 i4 V( v
  107. u8 Check_canRX(void)
    % n0 {' Q3 @  Z$ P2 K' A4 _% g
  108. {
      U4 |0 ~, ]1 Y4 V  h. Z  }
  109.     return (Rx_flag == 6);
    2 o# C: y# V* Y
  110. }
复制代码
, g3 e$ z0 r6 g% {
can.h文件:
  1. 3 R) J- w/ p6 K7 D" L$ v6 n/ k
  2. #ifndef __CAN_H$ b0 r( P2 ~" B. o) c8 M! C# T/ r
  3. #define __CAN_H
    1 B  x& m$ b7 |0 O5 Y1 a! @
  4. # W& N7 }! Z+ u% ~" \& p9 w: {* X' I, j& ^
  5. $ z8 J9 h& r- |' A8 G' T
  6. #include "sys.h"
    ' S2 p6 V/ j1 B: H) K" e
  7. #include "string.h"* y2 |. h: ~( S% p, I$ j. `

  8. * E/ L* T. q; J1 u* W
  9. 2 ]/ e$ ]6 _# {% t3 Y* _9 F9 H8 t
  10. #define CAN_RX_LEN          30          //定义最大接收字节数
    ( ?  |$ R/ R3 T; y* K; a
  11. 2 M8 M. Q# S5 D6 W  p
  12. ; Q, u# K8 i6 h1 F  I$ N- Z
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    + f7 ?# U* y4 q2 C
  14. ; H$ _& p! ]* }5 ^) o
  15. 0 V5 K! u5 Z* Z2 U) d9 l. K
  16. void CAN1_Init(void);
    * {- B- P  P9 i+ M& [" k# h
  17. u8 CAN_SendMsg(u8* data1, u8* data2);
    / X) ^9 a* G. o% c- M' l* D% Z
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    ; o( f& Q6 H6 d  ]2 e6 h
  19. - X  u3 K. i+ \) y6 @. b
  20. ! r; G+ y$ \+ P
  21. #endif /* __CAN_H */
复制代码
# z! |) e/ @: p# L) F/ P
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

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