请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU小助手 发布时间:2022-6-7 10:05
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
}2%6MKU]I@$GZ9X6S6IVP$L.png
# E' N" {- z. d
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧  D4 W& L" V% Z
  • 摇控帧
    3 P, `- E/ L- e3 I3 v0 a: s
  • 错误帧! H7 n0 b2 @7 V* O  t! e4 K5 ~" F
  • 过载帧% ]5 D4 X6 n$ p5 }
  • 帧间隔

    0 v' u. P1 \- l
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
9 u4 ~. O/ b+ F1 `) I    数据帧一般由7个段构成,即:5 `7 X6 i- v* c! y6 v5 T/ Z2 e3 t" @
(1) 帧起始。表示数据帧开始的段。0 D- p! [& P# O: E; r
(2) 仲裁段。表示该帧优先级的段。
: R" I0 g( Z7 F( l1 E& |+ D(3) 控制段。表示数据的字节数及保留位的段。
9 w' \% x; ]! o" X  p) i(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。, m" H: y5 z/ z) A7 L1 M
(5) CRC段。检查帧的传输错误的段。; p1 U" [: v; Z3 a9 x/ P' ^
(6) ACK段。表示确认正常接收的段。2 P' r' w% o$ A: S8 K: ^; U
(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
3 ~2 f1 f3 V" ]: _    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

    ; U; z1 I1 b) b2 x- b/ r1 j7 \
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
! B, g! j8 {# e" i4 \    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:

2 X* f9 P! j6 ~
IDZ(%0[HG8QC`YFQM3K90ZL.png
8 \8 i- e, l' e
, |6 F; }7 m; [5 u
    在程序中就是:
  1. //要过滤的ID高位 + T7 M, c& F# H6 z; A: }
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  ) ~. @9 T5 M$ M; L' T
  3. //要过滤的ID低位                 . A7 z# K% {" R, b6 f8 l8 L1 n
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; . h$ I" k& S7 U; S2 Y# U( I9 d
  5. //过滤器屏蔽标识符的高16位值3 y5 L, D' T! T( W9 \  a8 q
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;     \1 R' C& s+ [0 q1 O( }. O9 c
  7. //过滤器屏蔽标识符的低16位值         
    # m5 r5 R5 }/ A! R( d, H' G. d
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
0 O- K% ]9 x. H! J
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。& x: F% i- [% ?# l6 n. D
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
) H& G  c2 W# U
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:0 M% d' I/ W" `
主机:0x1314
/ j* t. F& v6 h% D从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
! i1 F% s0 N( `$ `, O2 g  ^
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
5 x' e8 Y9 H1 T2 G; i: X' Z- i
从机相关代码
can.c文件:
  1. #include "can.h"
    ) c4 |6 H9 F* W, T

  2. / s& z5 }7 Q: d/ e0 U" C( I

  3. 9 D- ~" b) j5 h4 _2 t
  4. /* 在中断处理函数中返回 */
    , f; k+ w- `7 V! R" `' u$ Q
  5. //__IO uint32_t ret = 0;
    6 Z+ D* P- W1 T$ r

  6. 5 ?1 k  {0 R8 Y4 i

  7.   j0 O9 v* `" y1 J6 P8 t
  8. //接收数据缓冲器
    : U7 Y9 g8 O& k% g, ]9 P
  9. u8 RxBuf[5];0 `/ J+ i. K8 P
  10. u8 Rx_flag=0;8 X; c  _& c: H% Z: x
  11. - I; M; p6 L& _! v; Z3 v! u
  12. - `+ _0 e/ F6 S3 M1 p
  13. void CAN1_Init(void)
    + _3 s3 t- o" W# Y8 t. ]
  14. {4 M% r7 t  h4 {3 D' V# U
  15.     GPIO_InitTypeDef GPIO_InitStructure;
    + P& R, ?; O! [
  16.     NVIC_InitTypeDef NVIC_InitStructure;$ V7 k4 G9 d$ v5 M6 i
  17.     CAN_InitTypeDef        CAN_InitStructure;  Z. ?( K6 |) g
  18.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;1 Y& D: Z* g; `% ?3 ?$ y" e9 H% v9 Z
  19. # B' e- ~' y# W5 C, S: Y' _
  20. 2 D6 ]" g+ V( L4 V
  21.     /* 复用功能和GPIOB端口时钟使能*/    - s- p, i+ T; _$ q4 O, f
  22.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      4 `# ^. i( [% r4 _& `8 D

  23. $ v4 q9 a7 F# I* d
  24.   ~; C3 l1 F6 b5 t
  25.     /* CAN1 模块时钟使能 */
    : f# n/ q  }2 {4 V% ^: `
  26.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    + @( q$ V# m' K% `, B
  27. $ _+ K0 N3 N1 l) p& p% o

  28. " S5 U7 A; H8 K- |6 @& R5 R
  29.     /* Configure CAN pin: RX */  // PB8, Q& c- Y$ K: N) h) B
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;: {+ F  {3 c! r+ X' Y' e: f- \
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
    5 d% s0 |3 [! C' R. O, ~5 D: Q
  32.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    / R# b9 B8 f& p, ^8 K. G: @

  33. + Q1 n8 c$ {, e. P
  34. ( M8 a% W' ]3 f9 G& H! q
  35.     /* Configure CAN pin: TX */   // PB98 C9 ?& @7 R  ]) k
  36.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;- U; D# j) }, ]) C
  37.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    3 U) s' w; O! P
  38.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    - P. C' g3 d9 U
  39. $ U$ [2 o( w6 V

  40. 8 ?4 G- s; b9 `9 `. n  @
  41.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O' q, }$ [4 d. _0 v  ]+ O; p2 W
  42.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    + G  p! x  N+ {) n5 r
  43. : V0 [8 H# z; \2 n3 ?# O
  44. % J1 z3 B, o( C7 |
  45.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    ; m* C. k, A+ R4 z8 m: e/ \6 a
  46.     /* Configure the NVIC Preemption Priority Bits */  
    1 i2 g5 H2 q5 O# M5 q
  47.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    : t* V; m8 z! J2 u7 I; q

  48. $ p7 G# ]. s( P# K# \) M; |8 a! f; _
  49. % a9 w! C0 h* Z. v
  50.     #ifdef  VECT_TAB_RAM  * [+ E1 R; `4 G; D" a8 v
  51.       /* Set the Vector Table base location at 0x20000000 */ $ N3 G$ t. |( O8 H
  52.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    - q+ e4 k7 {! [0 q3 O% ?
  53.     #else  /* VECT_TAB_FLASH  */
    - ^: D7 W5 o3 Q$ y# ^+ m: E
  54.       /* Set the Vector Table base location at 0x08000000 */
    # X, D0 M4 P5 m3 k2 C- d
  55.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    6 P, x0 Y4 d/ G; O9 b
  56.     #endif# P9 `3 H1 \4 H3 @# M# N

  57. ( t7 ]) ~0 T8 B' a  Q

  58. + M# ]" W  b" S% S4 S
  59.     /* enabling interrupt */
    / ^# P. e; v' L) k
  60.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;+ z& A$ M" h- ?- p% Z4 U" r% z
  61.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;5 i% u5 |  }/ [% r# Z% x# _
  62.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    8 Y  |4 L6 {$ b' h
  63.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    3 p, G$ A; I9 ]$ N. e! t! j
  64.     NVIC_Init(&NVIC_InitStructure);
    , L' I1 d2 E; P! e2 k* K5 Y# I3 _

  65. + E4 O0 c/ [8 q" k, b1 Y
  66. , |' U" d* F# R& H7 p( r. V
  67.     //CAN_INIT();//CA初始化N模块
    7 q( n8 k3 H6 p
  68.     /* CAN register init */
    1 O. d. h+ k; x* m0 G
  69.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
    ! k& n( [- |0 o/ z
  70.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    + w" f% p5 p' C

  71. 5 a6 Z1 g& M; }/ W- @) R& r9 b

  72. ; k0 V, b2 `! B) j4 B! P
  73.     /* CAN cell init */6 e# o, |9 z9 w- o$ p8 C3 I. I* Y
  74.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    , R$ {2 g6 o7 E- k: [; H
  75.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    ( s3 ~1 p1 o3 g- c+ \6 Y4 E) Y0 m
  76.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式( p, g; r/ @1 l$ F  Y  o' }* k7 Z
  77.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式7 Q3 P: W5 G7 H# D
  78.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    $ q) q- O$ \5 h2 H+ V# E
  79.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    8 K% w# }2 V" ~8 L2 M6 ~0 [8 U
  80.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    ( j& C( _& P- O3 d) C) |6 B! x
  81.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位+ K% |+ `; Q! y% C0 ^
  82.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    1 @4 s7 J  m" k9 N
  83.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位* P8 ~+ m0 l3 d  j$ F
  84.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60 ; _" H& d" ~9 o
  85.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs# ~( E- ?& p6 r) l8 t3 p" m# }
  86. ' l( @0 z/ L  o8 w/ }; B5 a

  87. ) x7 s6 P1 v; D5 v% ?
  88.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据$ t% N9 U' Y7 W+ |
  89.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    & f( Q( w# N1 ]2 T' @5 q
  90.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式0 ?) _' g; F3 \* g+ g- k$ J8 h
  91.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位0 x+ e3 J: s+ j% z: L( k  [

  92. ' u+ |: v# w2 L- Z1 O) c

  93. # _8 X2 n4 ?$ F) L
  94.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
      L$ o. E7 b% l9 w
  95.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    % Y+ x1 @4 s  {1 m1 P
  96.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    % K; s- U" W6 |* S
  97. ( M* I; ~" t  B: L) E) I, M) c# s

  98. + W& p! l+ A# u# [
  99.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    $ l4 b0 d* z) s* R0 {1 k! _& l$ X# m
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    8 _; U. J) g) S
  101.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0, m: W5 V2 {6 c- s0 ~, U
  102.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器# B" w7 t# B6 o: G
  103.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    4 ?6 D, F$ H: \" \
  104. / v# O& ?' q) A5 q9 ?
  105. / L/ J8 N( w9 _* i, ~5 F
  106.     /* CAN FIFO0 message pending interrupt enable */
    4 T+ D/ a" i' H! b; D5 ~7 }
  107.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断0 g2 Y( Y4 g# H! s
  108. }& y! c% d; M8 F% a
  109. ( X* y; r2 i9 m) |; [; {

  110. 5 ?1 c3 L) _$ H! e' Y6 x% f* E
  111. /* 发送两个字节的数据*/; O. n: p1 J. X/ i$ ~4 x
  112. u8 CAN_SetMsg(u8 Data1,u8 Data2)5 i9 R1 j% `3 q1 ~
  113. {
    # E1 T4 a* }: \/ L. K: y
  114.     u8 mbox;3 [: Z$ O( G+ @% @+ {1 d
  115.     u16 i=0; : M+ ?: g2 O$ }2 O6 Q! y! z
  116.     CanTxMsg TxMessage;    l: f5 O$ @; n  L0 P. {% e
  117. 4 R# Q( E! T8 b! z0 N& T
  118. ; y8 x* L: N% o3 s
  119.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    8 H, S+ F& P1 X5 a  E8 n
  120.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机9 F) ~& W) V6 i3 n/ G5 K0 H4 j
  121.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符7 K% C8 k. {9 ?+ t
  122.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    1 \' S9 O2 P; ]) {
  123.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    7 c" K& M: N% B# }/ H
  124.     TxMessage.Data[0]=Data1;    //第一个字节数据
    9 c, Q3 d7 B9 O0 X+ t, M5 m
  125.     TxMessage.Data[1]=Data2;    //第二个字节数据 0 L! [0 `* w% Y9 d2 H7 w

  126. % {; {) l0 Q8 t* e5 k

  127. + W- s7 [, P8 Z2 d* Q
  128.     //发送数据+ Q3 w& |3 [1 I# W
  129.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    % O7 ^) m) i( @+ V( P3 r
  130.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))3 {" {: v1 m1 Y7 B
  131.         i++;    //等待发送结束/ P0 w) f( _1 d) }8 E" d
  132.     if(i>=0XFFF), Z& P! O) X$ b- ^) K( ]
  133.         return 0;
    . _& j$ u, B8 X- h( a. D6 Z# ]4 c
  134.     return 1;3 ?6 ^# y  z1 {$ R& ~! U' F' W6 k. ?
  135. }* A2 b* n6 z: w9 y. Z3 v2 w
  136. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)  K" ^/ f+ c6 B* }
  137. {+ ~2 L9 j/ E; K+ d9 r3 [( a
  138.     if(Rx_flag == 1)//发现数据
    2 G8 M5 A8 l- D+ W  F
  139.     {$ I4 ^4 K) f' a/ Z% j( A7 d" W. C
  140.         *msg1=RxBuf[0];: B3 [9 [4 b6 U, m. {5 Q& I
  141.         *msg2=RxBuf[1];
    6 o" d+ f+ p' N: Y+ M! Y
  142.         Rx_flag=0;//数据已经取走,可以更新数据
    " x* R1 u' S7 P7 t% n9 c
  143.         return 1;& X& Y. f) }+ z1 L# ^
  144.     }else, v5 A6 T/ ~  u
  145.         return 0;5 v2 }+ k' o% K% K8 t: Q' ~) N
  146. }
    ) k4 A7 V% R/ P5 @5 M/ g1 Y; T% o
  147. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */6 `  a; K/ W* Z3 e2 ?
  148. void USB_LP_CAN1_RX0_IRQHandler(void)% @& j; N. }" b: G# U
  149. {& [5 f! O$ U2 q6 b$ v: w0 ?

  150. 5 y4 [) q. m/ Q2 L' T' H' @

  151. ( u' Z- E: g1 s5 P% h
  152.   CanRxMsg RxMessage;
    * \' d, N! b" q; Z. I& T
  153. ' b9 W( r  C" b" K
  154. % c+ w/ S; s* H( w
  155.   RxMessage.StdId=0x00;
    % k8 @' T) W1 l
  156.   RxMessage.ExtId=0x00;
    % c: `" b5 B. K( D% w6 \
  157.   RxMessage.IDE=0;
    ' b& O; l0 D% t) c/ f6 y; k4 ?; v  [+ O. ?
  158.   RxMessage.DLC=0;
    ; x9 N3 V/ J$ @4 K- b* V
  159.   RxMessage.FMI=0;8 W4 t4 R0 I" @/ x; y
  160.   RxMessage.Data[0]=0x00;' L* a: H. o% @( h1 _2 ~
  161.   RxMessage.Data[1]=0x00;   
    7 \4 s/ [' ?* i8 c. b/ B: j3 ]

  162. % }( `  H* p, Y4 I- n. ~! z" W

  163. ( e( v: u+ V/ Y, U$ O
  164.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    * I$ s. L) t: ^

  165.   ^" h5 N% u! J+ {1 @
  166. 3 I' l( ~3 N2 |1 J, e
  167.   if(Rx_flag == 0)//数据已取走或者缓冲器为空8 R* \0 j! c# e- s5 N
  168.     {
    ; @# B2 W+ q! K2 ^( N
  169.         RxBuf[0]=RxMessage.Data[0];. a7 ?. z, ~& P& D. i: d
  170.         RxBuf[1]=RxMessage.Data[1];
    + ]- g/ o" [- n3 N$ U4 h  D
  171.         Rx_flag=1;//数据已经备好,等待取走
    + E" a1 H  y* R; l1 l2 J% q
  172.     }
    $ B) l9 @- H! o" B( |
  173. 9 `/ F5 N! H- t# _. q
  174. % j! l  [1 J8 A5 ^, m# m4 e
  175. }
复制代码
5 H# M5 ^; ~, L3 u5 ]. P: z: `& v- U4 }" X
can.h文件
  1. #ifndef __CAN_H! Y. U7 T4 C! R0 s! N. u6 o* K
  2. #define __CAN_H
    ; E3 f+ q9 D3 M$ V

  3. / E8 i8 l( z; z/ k% U; Z3 H

  4. ( d) b; ?( c4 u) K
  5. #include "sys.h"
    8 H9 f: |. |4 @) e% o
  6. 3 X( L; D" W* m" h1 j4 y3 X0 g

  7. , J$ L# v2 y8 ?
  8. void CAN1_Init(void);! K# r2 k3 N: k9 N
  9. u8 CAN_SetMsg(u8 Data1,u8 Data2);. u+ s2 M2 L. Y( O0 w/ e* d
  10. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    6 J, D( t# A) o
  11. " Z! s) n: Q# s& n  G

  12. : K8 U( c4 j* ~
  13. #endif /* __CAN_H */
复制代码

3 {% g8 K! O' U* S4 u3 E, x8 v
0 G$ h- q& ^2 Q, i4 \1 M% `6 A( p主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
4 ^; _& A( x7 t2 ^) |) g6 ucan.c文件:
  1. #include "can.h"
    & x, x" r# c: J: {9 d5 Q5 }& b* T
  2. 0 h* `! }( m. |
  3. % h, _) J0 n8 ]- j1 @" d. ?
  4. /* 在中断处理函数中返回 */' _6 c  U( q5 u2 H$ ?
  5. //__IO uint32_t ret = 0;6 z# @' p5 X; S& S3 r; N' s' C

  6. - R1 S: k* L2 ?; T9 i. {9 b0 I

  7. 3 L6 m' F5 s& B" T9 j
  8. void CAN1_Init(void)) z  o& \" C& j6 ^3 Y" o
  9. {
    2 a" `6 D$ B& s- T/ V% p
  10.     ......//以上与从机部分相同
    1 k" H- k% M- d% }  i
  11. 9 \2 m0 r6 c3 B% `" R( n

  12. 2 b" i2 y+ H, d
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    ! T, q" c6 d  f, L
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为14 r; U8 M, M# j/ C$ ?3 _
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    ; U1 g1 t. M- q* Z& N! H& w
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位& n. a% [. Y+ z+ t' d
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值3 {5 Y# r% ?. U
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    ' @- V- n  G& s3 r& f9 _. D
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值/ {# |5 ^. G" r1 c6 v+ F' q6 L/ J2 b( M
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值$ s9 Q# Z+ D( ^2 n; g, m
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0; B( j% ^) s: ?" o
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器+ ~2 d* `7 t/ W; I7 b: M: Y: t
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器  c# r; v( b/ ?. P
  24. : S' C! c* W6 h% J# K3 f7 [& R- I3 }8 P

  25. + _9 f4 j. t! T6 I
  26.     /* CAN FIFO0 message pending interrupt enable */ 5 x  y7 Z% Z. Z8 h& T6 H) g
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断/ Y( o) |5 x  k- _8 ~
  28. }. ^  @4 r; |* k7 S

  29. * Y% P  O  }$ v( g2 N, h5 p
  30. 3 w& j$ c. R( V& {$ f
  31. //接收数据缓冲器  A  y# G3 B" F3 L
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.& T# E7 C7 z2 x% k' [/ d& f
  33. //接收标志位; w6 J6 P7 P$ K! r
  34. u8 Rx_flag=0;
    4 ?. `$ d' A% M! {( l& h0 C
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    & Z3 ?$ d9 g) R) N) u. Y
  36. void USB_LP_CAN1_RX0_IRQHandler(void)
    - d5 X! ]" O: \0 Y
  37. {$ m: R" X9 N* E8 Q1 _) x6 E+ d: k- n
  38.     u8 i=0;, k2 P6 x- X; J' g
  39.     CanRxMsg RxMessage;. ]) a# b! j: k) B7 z  V$ |
  40. . g' r+ f. ]! @* A% U
  41. , n6 `7 ~* ?* A  U9 G
  42.     RxMessage.StdId=0x00;
    2 N4 h2 y! X5 R2 }: G; ]
  43.     RxMessage.ExtId=0x00;' w' t2 ?" S! L- K1 d
  44.     RxMessage.IDE=0;8 `$ f0 N" S# c# F8 v
  45.     RxMessage.DLC=0;3 S$ H; a7 n0 R" N' j" z
  46.     RxMessage.FMI=0;
    , ?, v" G' M4 s: R# t6 P3 M2 _

  47. ' H( \* e6 u) N2 x+ k( K' B
  48. 1 D) p3 ^8 S. O4 p, [7 g
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  + k$ O  W( I; e- {; `& t$ ]

  50. 3 U) o* d6 e4 K2 R* e
  51. " p% `" B6 {  S
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空- Q. ?5 H. K- @* u- B5 O$ ]1 {* G3 e
  53.     {1 e2 Q! h- ^1 C$ U  F. q1 ]
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    " r; X& t- X' o* J' Y' ]# M8 D/ T. l
  55.         {! H; F$ T: t# t6 V
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];
    3 p1 V: y1 O4 f' d
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    ( F# b1 ~7 L4 A6 i
  58.         }
    ! Z' ?3 j4 K  Y# n+ [
  59.     }
    + X, r2 V7 r2 C/ S) p* s

  60. 6 K. f- D, H2 ^* r
  61. 6 o) B! q8 d" q/ C7 F/ T  q! g% Y
  62. }
    0 I7 u# m5 S$ B3 ^# \# W

  63. * S, @+ s, {' T7 o' v: F7 I
  64. - E3 a& p) M7 G/ d7 {
  65. /* 发送两个字节的数据*/
    ) V% F4 W) @* d. i% ?
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    5 F9 t3 u5 G/ j4 Z: C
  67. {
    5 C$ h! Z9 h. p' A2 I
  68.     u8 mbox;
    , L  p* h5 Q8 a8 u
  69.     u16 i=0;
    # T; x4 |4 Q$ k* L6 |3 b( ^
  70.     CanTxMsg TxMessage;  
    3 Y/ K3 b6 E+ L
  71. . R) R" l4 c" c7 R8 M4 x2 d2 H) U
  72. & y" Y( U- ~1 U
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    2 I3 T( `. n9 K7 W# z& C
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    6 d: i1 c: u5 b. W
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    4 b$ v) ]( c% ?6 z; u# H: ]
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
      V$ i4 t. i9 a6 ~$ |! C8 B8 I. U
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节" D& h; ~& E1 ?; F: w  m
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据* k3 w" \# _; c
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据 ( Y' P1 A0 s7 E5 A; \& U5 k& i; p
  80. 6 O, z4 ]# |( A! N4 n% |
  81. ; l) s% c- y1 t7 ~8 _* B
  82.     //发送数据& R3 a+ f0 \$ T- |/ [1 _, I5 I
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);    r* o, }* \2 _. P3 r
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))6 ~+ R& j. V! N* s' X/ Y# v
  85.         i++;    //等待发送结束! R+ M0 j, G+ F- m: b
  86.     if(i>=0XFFF)) b% a* K/ B1 c4 @. h/ w
  87.         return 0;//发送失败
    4 k/ w2 {" p4 }' l6 H4 Z/ z; R  }
  88.     return 1;//发送成功
    ) h8 L- M1 B8 F3 i2 u
  89. }  u. M8 ~" W- i
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)& p' T( U2 X) |4 t5 ]2 _
  91. {
    % i% p' W7 R5 t  `
  92.     if(Rx_flag == 1)//发现数据
    , }1 q( t% E2 y, ]: {! N
  93.     {  A( G# o/ b, b
  94.         *msg1=CAN_RX_BUF[0];. ?) g. C3 ~& b4 l8 D
  95.         *msg2=CAN_RX_BUF[1];
    * N* c- q. y; y3 ~
  96.         Rx_flag=0;//数据已经取走,可以更新数据
    ( u- A% W1 N' a
  97.         return 1;
    # a" t9 J) {8 ~( R- R" f+ o
  98.     }else7 K/ \( J& r& H) ?5 b
  99.         return 0;
    7 W5 u: }. ~- ~3 l( y% P# b1 P0 _
  100. }7 `9 N3 c9 t7 @  u- F( ~
  101. void Clear_canBuffer(void)
    * [2 U# n' p/ J/ \3 r4 d9 E6 w
  102. {: h2 U+ L( C8 w* b7 |$ M
  103.     Rx_flag=0;//清楚接收标志位3 y6 q' e& \/ N
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    8 u+ q0 e5 @4 B: O; |) G9 k- t: F
  105. }( g& a  u; k& x; _3 E( r! k
  106. u8 Check_canRX(void)
    & j  L6 k! \, {; f" Z$ p$ s
  107. {1 F- P$ O: p' P
  108.     return (Rx_flag == 6);7 {) e8 G8 a0 d$ y; G
  109. }
复制代码
! X- o0 \6 T* Y
can.h文件:

/ i, X/ r5 ?. |, z) x, Y* Q1 k1 Q
  1. #ifndef __CAN_H
    ; R6 d9 A9 k. ^
  2. #define __CAN_H
    ) r4 ~+ O0 ]' J. l6 ~

  3. : k5 t! I3 b+ p& K2 L

  4. / l* I( }0 N) H' {
  5. #include "sys.h", }( P, L( b: N/ y  r* _
  6. #include "string.h"& I" Y7 Z/ i1 L
  7. # x/ w1 `* x0 v% B& S# D6 q
  8. ; l7 f2 g  W! y5 f
  9. #define CAN_RX_LEN          30          //定义最大接收字节数
    2 S9 F, g2 j% O9 R0 T9 q& g4 P

  10. & A9 @; g( r) a% ]; o$ H5 S3 H

  11. 0 S  c; {  }3 z% f+ g
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 1 \+ ^% _( E9 f4 D* k
  13. / A" ?! U/ q( k4 w! v

  14. & F- R7 a8 n  Q6 v
  15. void CAN1_Init(void);
    ! U  p0 U* k6 Z+ ?( `! ?% I
  16. u8 CAN_SendMsg(u8* data1, u8* data2);
    - U# E) q. R' g! d, S8 }
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);* w& s2 i. `9 }3 o2 h
  18. % c8 K8 S% z3 g( y! a  a

  19.   h; L9 [7 Y. W
  20. #endif /* __CAN_H */
复制代码
. c0 z. d  B5 g" U
# l) e! P0 A: I- Z8 ]
收藏 1 评论0 发布时间:2022-6-7 10:05

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版