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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧$ ^( E3 P6 p& p3 I6 B
  • 摇控帧. h7 o: Q6 J( X0 @; x! ~" f* x
  • 错误帧% _# H/ H4 [1 b1 z
  • 过载帧
    5 D& X# _  N/ j9 y/ G! y
  • 帧间隔

    $ l9 b" u( Q. P; \8 U
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
. _9 ?) J8 C- ?) z0 I    数据帧一般由7个段构成,即:
& W' i% f5 A! p9 }  V(1) 帧起始。表示数据帧开始的段。
' [! F0 u+ R. K( Y(2) 仲裁段。表示该帧优先级的段。+ s' Z" k* o* v4 {
(3) 控制段。表示数据的字节数及保留位的段。& d/ W7 y6 m! V9 x4 Y0 e
(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
( [8 t: M( Y; `2 r: S(5) CRC段。检查帧的传输错误的段。- Y, e; q0 r. d) ?% ?. y1 E
(6) ACK段。表示确认正常接收的段。
  c3 m) C% c1 {3 ?! I2 O(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
" Z( h; I) v" k8 o4 U4 N    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
    0 s: m  {1 T2 u/ R
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
$ B; C9 q/ Q1 l# Z9 C, a    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:- {' G& E0 D4 h/ }% Y
PERMNQ{)L%G}{986WRA~Q]W.png

4 ^3 S! s! N' R) Y' P
    在程序中就是:
  1. //要过滤的ID高位
    , J' h6 v4 _4 ?/ _, M* v
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;    {+ y8 t1 p- z7 ^9 V- j( o
  3. //要过滤的ID低位                 3 c5 }3 x" X8 V4 M. H
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    ) B6 j  F$ ~9 B9 o' o4 S) l
  5. //过滤器屏蔽标识符的高16位值
    , y$ r/ N7 a# ~  C
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    + x3 g; g6 y5 j; K- k7 W& c
  7. //过滤器屏蔽标识符的低16位值         8 Y' A2 i/ K7 J2 p
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
! b  j' S$ K7 W, f* p8 {
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。% }) e' O5 `6 n  _% w8 U
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
) t8 ~. q$ C4 M! }* Z. L- a  P4 A/ O主机:0x13141 h3 G+ N+ ~5 x. Z% t& v
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:

  1. / w8 r9 {. b2 F
  2. #include "can.h"
    1 H. f! K+ Y3 I( O

  3. # y: [0 o* I! D+ c3 R' y' R& W* S# d

  4. : d* a6 _5 J; h3 I5 V
  5. /* 在中断处理函数中返回 */
    % b. A6 K5 P, ^; `
  6. //__IO uint32_t ret = 0;$ x4 P: B4 T, i  f

  7.   j2 B9 r  Z5 c, D) g2 V4 K

  8. ! E1 I. N- j9 U3 W% |% q( T/ N% T
  9. //接收数据缓冲器, q  t& ?/ P$ R3 @% ~
  10. u8 RxBuf[5];
    1 j* p9 `- U/ T/ o9 Y1 I
  11. u8 Rx_flag=0;* i2 _2 B9 i  b4 @
  12. ; n8 @3 U0 q; g

  13. 3 Q$ R' x5 I7 B$ q( b# t1 M0 B
  14. void CAN1_Init(void)# y, r  [( C  G, D2 a7 S
  15. {% @; |; |: ]3 P% h0 B9 L7 I! J* I
  16.     GPIO_InitTypeDef GPIO_InitStructure; " S) W2 I( s% D, g5 {( Z! `
  17.     NVIC_InitTypeDef NVIC_InitStructure;) _% q' r" ^' K2 [* [
  18.     CAN_InitTypeDef        CAN_InitStructure;
    : D3 D$ `: G" j5 E) m
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
      y2 m; N% A. V$ f8 r5 f
  20. ( i, n7 P1 e$ t3 G
  21. ) |3 e# l6 K2 l5 y
  22.     /* 复用功能和GPIOB端口时钟使能*/    : N$ S2 H" b6 }; J+ ^
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      1 b% X! g, o( M  ~; d" R: N4 K

  24. : E( c1 E: X! o+ w7 }3 ~* |, B

  25. " C% k- U& _- k, H/ I' }
  26.     /* CAN1 模块时钟使能 */! L& f" h" I( h4 O/ |
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); * k2 R; `0 S9 a' c+ u+ {: Z
  28. / `. B2 @* ~' f* v6 L' h, f  e3 D$ _* V
  29. / Z$ t: _' t( u, {
  30.     /* Configure CAN pin: RX */  // PB8: J/ M9 m  `; C% A& j
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    ( M/ E7 u" F0 q
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入$ ?5 p2 k& a! b- @1 p- X3 m
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    5 G. H" b- S1 b2 u0 a
  34. ! z4 _  Z0 J+ C
  35. * C* k8 w1 V$ [, _$ a: W
  36.     /* Configure CAN pin: TX */   // PB9  E3 R: ^1 F' M8 Q; R- u4 q9 F
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;, m) r: @& U8 X
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    5 r" V! r8 f* D% A+ x
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);" G- G) b' v* }, C; J; T
  40. , H2 J/ e" T! o4 x( Z! A

  41. 3 ^& k6 }6 u$ E/ d9 y% F+ K' L/ C& o
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O, V% a9 i( |* P+ O: U
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    , y6 D' Y* G% J: Y  {- p7 e

  44. ) H% ]/ P- D* o" O1 `+ R

  45. 5 k: o0 c2 \. D8 w
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   3 N7 N' D" o9 P; \
  47.     /* Configure the NVIC Preemption Priority Bits */  . V* Q8 b' I" e  s* K, L
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    9 P0 z/ m  Q8 o: r
  49. * @4 K2 q* O% g! a4 Y1 z9 G

  50. - d$ M7 z% |0 @7 F
  51.     #ifdef  VECT_TAB_RAM  
    4 V  T$ Q- K8 k/ g2 @$ M& K) ~
  52.       /* Set the Vector Table base location at 0x20000000 */
    . y& }) l/ H3 I
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);   m) v+ a" Z# M# F, v4 s% @
  54.     #else  /* VECT_TAB_FLASH  */
    5 [9 `9 f% c5 w8 F% a6 |( S
  55.       /* Set the Vector Table base location at 0x08000000 */
    * g8 @+ J  p$ d( F
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   + }) w) Y' _0 C/ q$ j! S# D) l
  57.     #endif
    - Z6 f2 J/ t4 b$ `4 W/ i
  58. # y) h0 N; E! E3 y! }7 \
  59. ; o6 b6 O7 ?! z: G
  60.     /* enabling interrupt */
    / @( X' U1 X/ H7 o( z9 g+ r
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;# t, h# X, {1 n
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    % ^- n: ]5 o8 p
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    / E, |* @* h) v, K
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    0 D% V8 W# I, A
  65.     NVIC_Init(&NVIC_InitStructure);
    0 P& `& s- B5 M$ q0 g2 ^( E* i# g
  66. 0 L# n- x1 A+ C6 P1 ]  L5 P3 i

  67. ) N4 T, B. e: ^/ R$ C( c6 f
  68.     //CAN_INIT();//CA初始化N模块
    9 G9 o4 R2 J. e9 G' U; T/ z
  69.     /* CAN register init */' u1 l& @9 G1 c( G$ n8 g5 s
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
    7 L( H; v6 X8 K/ v$ Z8 ~
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入$ p. r: X* U& [

  72. 5 E. ~! I: N5 @6 @

  73. 1 y9 i2 a' c4 g7 z( v3 n
  74.     /* CAN cell init */
    ! ~+ X( u5 d. n6 O$ z( `) @
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    & V+ O$ G* R, V5 U; M$ f% F4 v" g
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理: d  m: r8 q: G
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式0 S9 W* w2 S4 ^
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式% {" {* r# i4 B; E
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式; B. d, q9 K  X$ d) a4 [
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级0 v7 M) l: Z3 Y
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    2 `5 j, W8 |  _& B
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    ) D; X9 ^: B9 E$ N: O+ ?' g: f
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位  I  X( K7 I2 ]% R2 e/ [
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位, d: `8 J! F' v/ F$ Y" e! l7 x4 U
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    ( x* Y$ g  j7 ^5 `. M
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs5 W( E  z  g9 n: ?% F9 A

  87. + E" V$ f  g& ]

  88. " ^4 h) \& }! H# Z' R, `
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    9 c0 X* T0 f: Y- M  s, _
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1* m+ p1 ^! ~8 O- B! |4 _9 K
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式% I" V1 z4 \  T) S
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
      }/ O6 C: W) U" E

  93. ( ^  X0 |$ e. I- p

  94. * Q+ H* s+ J) m$ f! A* a  k$ X, X  N2 A
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    9 o+ t5 J9 n% g. X
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位 5 i% k; J4 }% D. w& E4 k3 l9 p: u; [
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    ; X6 F& P+ z0 s8 J3 v
  98. 5 r4 p/ }. C& J" }$ J1 w6 u

  99. , G! C9 J5 F- \# K( E* N6 y
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值. K: I  j. X: }) G$ J
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    & ?. Q! D# G5 x
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0' ?( n8 x# y" X5 U5 S
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    % |5 A  t! R) _
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    5 C0 H6 t7 F* V8 M9 G7 T! x

  105. ( m3 j4 X4 D9 C! S$ R7 ]/ P

  106. ! @6 C- H9 |% z: S
  107.     /* CAN FIFO0 message pending interrupt enable */ 7 w! }9 {  A5 z$ M! W8 j
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断4 |+ b" i/ ^: K6 C- F+ B  D
  109. }
    ) s4 \1 }& E7 m% [7 a/ Z) S# z" P

  110.   o( O4 J" a" F$ y3 u
  111. 1 q# F$ M$ v3 W$ g7 \
  112. /* 发送两个字节的数据*/  L* X4 M4 f5 V' b/ a% R& ?0 g/ e
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)6 b- _2 ^& Z5 j
  114. { / k, x. }7 o8 R
  115.     u8 mbox;" q6 V+ J, E. v& \: G9 t5 ^& N6 i9 T
  116.     u16 i=0; ( f4 S8 Y( R/ w5 F. ]' J' u9 z
  117.     CanTxMsg TxMessage;  1 O- [9 g; L0 ^7 z

  118. 7 A7 `' v" O7 G) |, v
  119. ; A$ v) H+ T/ T) \  D7 k9 g
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00' W) ~8 M$ ~6 F- e: ?& m( G
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机1 J; u( z1 j6 j" H
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    ' P% y7 h. r: x/ ^# M6 P$ G2 [  b
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧1 H: _( @4 H& V, b; x: h8 v1 u
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节" k9 d( A0 C- \3 X
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据
    4 y! c& N* b! c# Z2 ~& J9 o
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据
    4 k! K# K& {2 z0 x
  127. 4 t! U8 m2 ?, c4 b" i

  128. - {6 ~8 }) W# ~* V& e
  129.     //发送数据7 I. S/ n5 p$ U+ S7 r
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  
      u/ B3 x1 {2 Y6 O( H. c2 v/ C
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    8 W2 S; r0 V* e/ J$ Y& x' v# d- u
  132.         i++;    //等待发送结束2 ^, l; Z5 j6 Z" r7 O' q2 \! i3 o
  133.     if(i>=0XFFF)
    7 a3 T' V4 Z5 w# E9 k
  134.         return 0;
    7 ^5 {! _, _* ]6 c1 }' S
  135.     return 1;7 r5 O: h* k; P/ P  I( p7 {: G
  136. }4 K, A3 V! e; j7 \8 S
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)4 I! o* [. W: t2 C3 C
  138. {
    / z9 O' Q4 u* }. d- ]
  139.     if(Rx_flag == 1)//发现数据' P4 R* G2 `0 S; e3 ~6 X
  140.     {( ~# c% F- C+ H5 l( T* l/ r
  141.         *msg1=RxBuf[0];
    & L* e- q% u, I! p
  142.         *msg2=RxBuf[1];
    % y: S$ K- x! H' J3 V5 z* ?
  143.         Rx_flag=0;//数据已经取走,可以更新数据
    7 m2 k% [5 b' w6 [: \
  144.         return 1;- ?/ a8 r7 J" M& x/ Y( v
  145.     }else) ?3 p! j8 H: p: E2 D2 J
  146.         return 0;2 p+ e% i! N9 d; y  t8 F
  147. }
    2 i; H6 I' b  p! C
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    ' D) a( \9 w: t8 ^, M! @% _
  149. void USB_LP_CAN1_RX0_IRQHandler(void)" k4 s3 F2 q$ q: U, m$ }, A
  150. {1 e. r7 Z2 d- `
  151. $ C' ~# I1 V( G0 Z( F# t7 R
  152. , K* D8 j0 D# m; ~0 B
  153.   CanRxMsg RxMessage;8 r4 n/ k  T  T
  154. / N: ]+ H" \+ L! B
  155. & \6 X- X8 Y+ [
  156.   RxMessage.StdId=0x00;
    4 y" N3 Y5 M; B* ~
  157.   RxMessage.ExtId=0x00;
    / {" X6 i+ T. ?" f' @1 G" C- f
  158.   RxMessage.IDE=0;
    5 P( e' `2 _- J/ j, d# ?
  159.   RxMessage.DLC=0;% Y  ?' E" x1 C, h8 U
  160.   RxMessage.FMI=0;& E$ p. \) i0 @% J5 B' s, t
  161.   RxMessage.Data[0]=0x00;; r8 ?  A' f' T! U% W0 D- n# P
  162.   RxMessage.Data[1]=0x00;    ) q% }) x( Y2 \: U, Q1 A
  163. ' C' }0 v! a* |! z$ J
  164. / C( _) \8 `8 m- P0 T  B5 v; u
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  0 x+ \  t& m/ a
  166. 4 y, x0 x0 c5 t( T
  167. * I7 |1 Z+ _1 b6 U( ~  V0 N; O
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    * ~- Q  _. R! L% q* \
  169.     {9 z# v( A  N3 V- `5 y4 }0 R
  170.         RxBuf[0]=RxMessage.Data[0];
    ( U" a, u3 ?+ k# Q# [. p- j
  171.         RxBuf[1]=RxMessage.Data[1];
    6 V) V- P& i2 ^. u+ v
  172.         Rx_flag=1;//数据已经备好,等待取走& @3 ?- x1 p$ @5 B: J) c
  173.     }
    7 |7 k) _; w# X5 D0 Y2 d( M

  174. 9 G& @8 C7 j" s% L, E2 T3 `

  175. ) T1 I0 g! ], W8 ?
  176. }
复制代码
" k. G5 ~# F% q+ \" C! a
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。$ d& l! r, ?% j) K& f" a
can.c文件:

  1. 5 G2 X9 y1 K$ @8 ]9 ]. \0 d2 Y
  2. #include "can.h"
    ! M+ {: {1 d) f4 a% q% Q8 e" h

  3. 8 n2 f. U  T4 x! i2 H9 }

  4. ( {/ U5 j- k, q- i
  5. /* 在中断处理函数中返回 */& W9 r) |8 H# n% I
  6. //__IO uint32_t ret = 0;9 Y& K" l# ]" e) O3 M9 x  `
  7. & {4 X  \# r: ?, S* k

  8. # O& h9 f: U0 O& C& c9 ~
  9. void CAN1_Init(void)
    7 a( [0 C/ s  k% ^
  10. {
      t: |, {% {6 u( N& s+ a4 a
  11.     ......//以上与从机部分相同
      _" b. j" w7 j$ y- o
  12. ' d+ f7 z$ E5 [. ~7 j
  13. 9 o' t( e4 B6 J" R6 H
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号/ c' O; ^8 ]" U9 c: }
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1# ]9 V! R. k: T+ ]: I: _! h8 u: r
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式) l4 M+ I5 `! l% x4 T- i2 u
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    ' f5 Y- @& C9 H7 E0 E' Z2 K6 J, `
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    . Q5 Q) o, s8 J; m* E9 ]. m
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值# U! P0 X5 Y- \: f$ ^$ A5 [9 R
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值+ f: ?* z5 W$ Y' L; m7 r
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    & N/ _' t$ j( ?; b8 r. N
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    , |- @: @2 k. i2 W& C# i0 C
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    ) |* |, V, a  D( _+ m7 j- j
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    . ^4 u1 s1 P+ j: e4 j6 y
  25. 3 x4 n7 I& H+ j. S) \; S

  26. $ h4 }7 w3 k4 Y* i( ?
  27.     /* CAN FIFO0 message pending interrupt enable */ ' o. V; Y& u% T0 p$ k
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    " r. q* @# u3 I5 Z- R! P
  29. }
    2 _4 T3 V* u. K5 E, ^
  30. & t" c( c' G+ ^# _' i, H0 x

  31. 9 R( O( {8 `) h+ z. Y
  32. //接收数据缓冲器; S8 v  i4 p. p
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.0 T, q4 N# J& H$ J7 m
  34. //接收标志位
    4 d1 X1 M, l6 h( j) L$ V) U
  35. u8 Rx_flag=0;
    7 y! @! h' g2 |5 |
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */9 a, s; D- `. ^0 Q
  37. void USB_LP_CAN1_RX0_IRQHandler(void)
    $ {' B3 \& c- [: I$ l
  38. {
    + `0 N! K( z( b, X
  39.     u8 i=0;9 H3 k0 O( o* N
  40.     CanRxMsg RxMessage;
    ) d; Z/ D$ G6 i( r( h

  41. # b/ ~& [* C* l5 B  l4 d
  42. % f- }/ g. k" d* X4 L
  43.     RxMessage.StdId=0x00;+ ~; ^6 `; N7 @, u; l
  44.     RxMessage.ExtId=0x00;
    ! V0 c) A6 m3 X5 t9 j* o9 p
  45.     RxMessage.IDE=0;- L" p6 c2 `, o
  46.     RxMessage.DLC=0;4 Q8 c: r$ I5 V; q* p* d) O! x5 q! w
  47.     RxMessage.FMI=0;
    $ ^+ s! i; u, P: T

  48. , b0 f' T8 }# `2 E- ]- `, e

  49. & [9 q9 R: Q8 a; P
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  . S- T. X4 m6 x. Q

  51. , Q0 Q0 C; l! X
  52. ' L4 c# u6 ^2 @4 G# Q8 c
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空  I& S% }* s. t8 G, D5 d1 b: P
  54.     {
    ; g1 Y: T+ r; V9 I; f, u
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
      M% E/ a$ ~; x$ }
  56.         {& F1 a) X% V) v+ |" w7 M  O
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];9 D3 P/ a8 f' p* v- ^5 {
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     7 ^6 r( X! N9 T5 t# H1 B: w, n( J) r
  59.         }
    + `/ D& @  {; K* K7 P* i9 o4 o
  60.     }
    ! p/ S4 J2 V& Y3 }3 @& R& _

  61. 7 T/ ]& ~" t' T

  62. % ]1 H! ~) v2 g1 F
  63. }
    8 I8 \9 E4 I; f$ s
  64. ; y1 |4 K5 K3 }: @. Y1 Z: F: l
  65. & w& h2 q! f$ M7 N$ J7 s# K
  66. /* 发送两个字节的数据*/
    0 `( ]9 E: |2 H  [1 }
  67. u8 CAN_SendMsg(u8* data1, u8* data2)" }3 g! I5 o7 G0 K9 l
  68. {
    / v: U0 M, B" m2 l# Z
  69.     u8 mbox;
    9 p3 s: V" v( Y* R1 W% ^
  70.     u16 i=0;
    + j0 w$ t5 m$ \% _2 S& ^
  71.     CanTxMsg TxMessage;  6 I# Q5 J, Y, @
  72. + R2 i8 ]- a5 M+ S, f5 C0 E3 U
  73. ! }3 V9 H! y7 h* G; x4 `$ }, U
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    3 J; r( I6 o) v
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000) e& M/ a( M5 O- y; W
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符" f: d+ }5 @7 M2 W9 ]( |
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    8 Q" A$ ^! {" z7 \8 e3 Q/ U
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    1 @5 a) b- ~5 N( b4 K8 g. |0 i
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据0 O2 B& R+ A$ {3 K4 x0 h
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据
    & d$ p) k8 E& ?3 M  |, r

  81. 6 N% X* c/ I; {2 q
  82. " h* y8 ]4 s# \  ^
  83.     //发送数据
    0 b  a$ D6 u6 f% R! {* h
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  . ?0 z5 ]' i" H
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    % r$ X7 f$ I7 b. X4 E+ g- X
  86.         i++;    //等待发送结束% g6 [7 U& l3 I& I
  87.     if(i>=0XFFF)4 L# _& V% e/ x
  88.         return 0;//发送失败! R6 t4 q& v# t' x" m& _$ p
  89.     return 1;//发送成功 2 `: U% R' d& ]; A8 ^& X+ A& w
  90. }
    & U3 B" K4 `9 Y6 u% ~  {9 O# _1 I
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    0 ?3 N: x$ O3 i
  92. {2 q; S6 z; c" _4 }7 w, a& _
  93.     if(Rx_flag == 1)//发现数据& l" f: T% G( z. v! d, W
  94.     {
    8 z% z4 X3 Z! `  J  M
  95.         *msg1=CAN_RX_BUF[0];
    ) g+ x0 T3 Z8 j
  96.         *msg2=CAN_RX_BUF[1];( U/ ]# c3 y/ p) Q9 u  F
  97.         Rx_flag=0;//数据已经取走,可以更新数据3 l1 @+ i, I/ F
  98.         return 1;
    ; i: O) t2 @# Z8 C. p6 \
  99.     }else
    * F. ?; I' m7 Y9 C7 \* R* M0 Y
  100.         return 0;7 @' X: F! J' r3 P
  101. }% h8 T( T0 O- M5 E6 n  p
  102. void Clear_canBuffer(void)( ?7 a  K7 r) D' |
  103. {- ?$ X+ e  l1 L8 O% ]
  104.     Rx_flag=0;//清楚接收标志位
    9 o, x6 F# u" Q" p- Q. C0 t
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区2 O6 \; w0 B0 g" d/ i/ }4 X
  106. }/ ~. \" S+ M6 Y3 _3 r. @$ p8 N2 i+ F
  107. u8 Check_canRX(void)" A+ X4 g" P9 N% Y
  108. {- @$ U: b8 M- ?2 f( F
  109.     return (Rx_flag == 6);
    ' F8 H. [0 c/ E& f" E
  110. }
复制代码

$ }. b, u+ D, W) K1 ^# ]
can.h文件:
  1. & L! \2 B6 D; ?3 @$ ?( w: d
  2. #ifndef __CAN_H
    6 F  {0 C7 k; d' g4 M: Z% v8 j
  3. #define __CAN_H/ }- L3 [; v2 x4 D, q

  4. ( M8 z0 k4 ~; E- s' U/ ^

  5. 0 p% w; M3 O- ^/ e' k* K
  6. #include "sys.h"
    ( V( T# j- o2 o. J. n! o7 r" Y9 k
  7. #include "string.h"
      v) ]7 m' g" a0 `

  8. 6 Q/ Y! \9 n3 X/ }; T! Q3 d
  9. . v5 A, G+ f! \2 h( M
  10. #define CAN_RX_LEN          30          //定义最大接收字节数
    + C* C2 V" w# S
  11. 7 i9 |, d: N$ t" g) X* X
  12. 7 K- B0 o: O* @: `0 Q1 D2 L- @
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 * I- l: m* C, U! A5 Z
  14. 1 a4 o9 M# c* j0 n/ v) {. f+ u

  15. 2 Y2 y8 n* r: C" c& a2 A4 u) X
  16. void CAN1_Init(void);
    2 W' D8 G% i5 G8 C% l
  17. u8 CAN_SendMsg(u8* data1, u8* data2);6 H/ J3 Q6 X5 e3 x4 ?
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    3 m& e1 K1 H$ U+ J6 g$ D6 L
  19. " @0 t- @- N7 B- H. B! Q0 A/ t! H
  20. % r  j& L9 g. a  H# [2 c
  21. #endif /* __CAN_H */
复制代码
; l( C" f% Z$ [/ }9 E; p) {3 G1 @
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

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