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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧
    4 y* D; t% H: u9 O" S3 a6 N
  • 摇控帧
    1 ?) J' L' m/ W: ]9 x0 j7 E
  • 错误帧' a7 j0 g6 R, J  I6 ~3 D# G9 \1 u
  • 过载帧: @* t- J2 S, ~6 u8 r
  • 帧间隔

    / A% o0 y5 A. o+ ]
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
1 w# ~' R- B' p# U. P% ~; F' U    数据帧一般由7个段构成,即:
& Z5 U7 Y, H+ K0 ]9 E  [7 T(1) 帧起始。表示数据帧开始的段。
& t4 }/ {) Z! x1 ^) s1 K& C3 @(2) 仲裁段。表示该帧优先级的段。$ C( N1 [+ M% t5 J- m( n8 x
(3) 控制段。表示数据的字节数及保留位的段。+ H0 R+ V) U. C( \: |3 ]
(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。1 F1 f* Y# t5 Z$ p. q5 o4 @
(5) CRC段。检查帧的传输错误的段。0 D* r, d2 m2 {/ k; o
(6) ACK段。表示确认正常接收的段。  ^4 T! D2 B  s% Q; i
(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。8 i# R# i* t; v5 b: w
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

    0 j& g' L) q; y, g
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
( P( c  H$ J& v: c    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
- s( a, j$ |6 {4 q( Z5 e
PERMNQ{)L%G}{986WRA~Q]W.png
" b' R/ ?  u7 I( v. C- R0 L+ C
    在程序中就是:
  1. //要过滤的ID高位 4 l- m+ z8 k% [9 D- Y
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  * i. h- b% ?, R: k2 ]. v; J
  3. //要过滤的ID低位                 
    6 H8 |3 c( a% b
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; # {2 A/ f9 }2 f3 d
  5. //过滤器屏蔽标识符的高16位值! M/ W& ^' h) h9 T0 e
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;     }6 t4 x! V- a: ^
  7. //过滤器屏蔽标识符的低16位值         
    % R' A$ F1 a( \* ?
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
) y1 Y& E4 E) s8 @* Z! f& D! [
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。2 J0 Z( o/ j% s. P0 ~, _
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:8 R/ \9 X0 r; i- L
主机:0x13145 J: h) b7 T8 ^; i" X+ A
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:

  1. 2 l2 @' V6 I" }; S6 B
  2. #include "can.h"
    3 x* Y1 Z' u+ N' Z$ u
  3. - ~; k0 k* P! K

  4. , ]# d7 x* D& \2 g' \$ l! `. k
  5. /* 在中断处理函数中返回 */" n- {9 F5 d  `
  6. //__IO uint32_t ret = 0;) _8 Y! E/ }0 p# Q4 g8 O& R3 Z
  7. 0 u8 F6 p( K$ m( J1 C

  8. 5 G1 H$ f( Z4 ]
  9. //接收数据缓冲器
    6 o# m" ~' c' G9 {/ I& Z
  10. u8 RxBuf[5];  n5 l) |6 l  ^, O
  11. u8 Rx_flag=0;1 \) n0 ~& g1 `7 H! s$ T& k7 }
  12. ; C6 f7 ?  C, S7 y' p4 _

  13. * d+ A' b& `- `
  14. void CAN1_Init(void)/ V- S, Z3 ?* X1 m% l/ C
  15. {
    ' n. y4 u' [* u4 Z) @0 M
  16.     GPIO_InitTypeDef GPIO_InitStructure; ; t# R* h4 p9 X6 T9 R% Y
  17.     NVIC_InitTypeDef NVIC_InitStructure;& Z) _( d0 R% Y, F
  18.     CAN_InitTypeDef        CAN_InitStructure;
    1 u/ f% l- K9 ]& v; |1 r1 [/ J2 ?8 q
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    : T9 X! r% W+ D+ |8 x

  20. . Q' I! M1 \/ s; N3 G) j( {
  21. ' \: Q# s5 |6 |% U( t! F
  22.     /* 复用功能和GPIOB端口时钟使能*/   
    : J! l  Z/ ?7 S% s. c7 j
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      & ^" ~5 I4 w% T5 t, o$ A" \

  24.   K! V; T- W/ f5 K+ b

  25. 9 p* b3 M- Q9 ~$ P
  26.     /* CAN1 模块时钟使能 */
    ' c7 [: [, u7 a: R+ F+ Q
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
      H3 @2 Q( S) ]' ^7 ~6 K4 [

  28. . d0 s  I0 w- s, N: Z  Y1 c6 e
  29. $ N0 d8 w3 x4 U6 }
  30.     /* Configure CAN pin: RX */  // PB8
    : T6 n' c; f& @) j# L1 }; @! a
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;- E6 x9 {* s4 o7 W
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
    * ^  s! F- p0 D7 X: A
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);4 p/ E6 G& S: V

  34. ; Y7 T3 K0 A2 N" B2 }7 }$ x4 k. a0 |# l

  35.   z. K, F0 J6 @
  36.     /* Configure CAN pin: TX */   // PB9
    $ u1 }' C8 g9 i0 \  Y
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;; y& k" r$ m% {3 F: @9 w
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出+ C5 N7 [5 I% T! I8 o7 @9 R
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);& P, q/ k" ^7 ~
  40. 0 Z2 o0 u7 q# M3 _4 u9 F* L
  41. 1 f* S8 w% P. `
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    ) ]( [9 W5 a# ?2 ~- q
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    + h, r1 O* ?, I; _5 C% ~- u& c9 N1 i9 X

  44. ! B% m9 z1 y3 n, j0 {
  45. 9 J! e2 \) ^" s! f/ y  {! |
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    " t  b  \" h5 S: u8 `  ]- x, K* Q
  47.     /* Configure the NVIC Preemption Priority Bits */  $ D* g* N1 O7 }) N  ~" \
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    ' h( J/ R- X' b1 u( E

  49. 6 E8 `7 R. w4 W

  50. $ A% I5 h3 k0 p& U$ Q* p* L
  51.     #ifdef  VECT_TAB_RAM  / h  _  B8 J# b# z4 y( O
  52.       /* Set the Vector Table base location at 0x20000000 */
    # X3 L0 i5 ]9 J/ [2 ^& s+ J8 R
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 8 B6 {- K! x. n. F8 E
  54.     #else  /* VECT_TAB_FLASH  */
    : c' A$ r( D5 b) l- C0 Z+ D4 n
  55.       /* Set the Vector Table base location at 0x08000000 */
    . ?/ a9 o. t7 U2 i% j: {
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   & I# d) C! R5 u+ m/ {4 u
  57.     #endif
    ) I  c! H" p$ i( H

  58. , \: l* C2 a& n  J
  59.   X7 b7 p8 h3 p8 q$ k, C
  60.     /* enabling interrupt */
    ! z2 ~1 I, O# m3 _! k- l$ A
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
    0 D% B  X5 C) H( `
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;6 \4 ?  ?6 |- t6 I5 l
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;$ a9 A* O/ ?9 W# o' L
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 s8 f( g/ j; W' s1 \5 u; A- U- W
  65.     NVIC_Init(&NVIC_InitStructure);. a2 u3 y+ D1 q4 T6 G1 h
  66. ( [4 }1 T' j3 G; q/ {2 g2 c

  67. 5 O+ N6 O# x# X. f
  68.     //CAN_INIT();//CA初始化N模块 , k+ t, A) b+ i# d4 G" G7 @
  69.     /* CAN register init */
    1 x: a5 Y. @& Q7 n& C$ B0 `& U' n1 C
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值* {8 a# i( `4 _8 p9 n9 e6 l5 y
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    % i% W* Q: x4 }% d. v

  72.   q/ n# I0 h3 r( j/ y
  73. ! N% E# `/ g# H  d9 Y
  74.     /* CAN cell init */7 ~6 g8 [& H8 M6 n4 p9 j
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    * _2 `& e. @% z& g" @6 c: J, T. K
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    5 ]4 u' F) D: [9 Y
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式6 R2 u& p1 \5 \2 d6 E6 \' a9 J
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式, ]* G% c0 i& |  {& w
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    ! \2 [/ P: J# p! `5 t* p
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    ' e5 M  b7 B$ z: Z  A/ g
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    , ]  O. k# M# F! W  K4 @& k- \
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    1 r4 G/ Y9 l6 |" t) G6 S! I
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位5 V1 L9 q( P$ m7 m2 }. L# X# V5 A
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位4 `3 f' u2 h6 I) ?7 a% I% P; R
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60 8 f& Z/ @$ r9 ?  f% P# d7 ?
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    , [/ P/ B% Q& ]" ~9 k$ @
  87. / j: h6 y( A+ d) X1 k& B4 K
  88. ! y( c$ m8 N1 g+ V( e  R" @
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据& ^' e& E9 O7 y1 k
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1/ x9 i% d4 L  p6 S2 j) \
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    8 y% ^. o# D: g! _4 c+ M
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    * J2 o2 X! \. J) J& I. {

  93. - p/ F' M  s7 w! M: S

  94. ' @$ A& R5 [* _6 i* q' H9 G
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    ( {: D0 ^0 z: r7 L
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    2 e. j+ Q* p% }: \3 J# @
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位 % q8 T- F1 }; |8 x# t3 w) Y

  98.   f$ y# r3 o1 c) w  N% G

  99. ) C* P& Q' q& U
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    ' t9 p6 _$ b& z* Q
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    * I4 M9 d- q$ w" x
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0( X, [# m  ]: m4 D" y
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    / Q, s. N3 V: }  ?
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    5 u( ?8 D4 U1 D8 `9 p
  105. , E9 z* Q; \; Q9 ?( k5 ]

  106. 3 O4 g- G, r# Z+ [( W, H2 r
  107.     /* CAN FIFO0 message pending interrupt enable */ 6 z+ Z6 K4 A6 ]2 [1 W2 z; I3 W
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    ; S5 T6 n8 L3 X4 c. ^! p
  109. }/ e: |+ u' n$ ]& }& {
  110. 2 T- x5 F& T! l( u3 M" i

  111. & L3 U2 ~* p* g6 j  i
  112. /* 发送两个字节的数据*/! W7 K, t9 y2 |+ c
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)$ d1 E. M3 n$ E6 z1 S' s* t
  114. {
    , h1 w0 |8 b- L7 t8 M2 x3 o5 c1 k
  115.     u8 mbox;
    8 h! ~9 L# k9 N9 p1 G0 i
  116.     u16 i=0; ; s7 K$ K  s: D
  117.     CanTxMsg TxMessage;  * @0 g. B6 @6 V8 x; }& l8 u" T5 Q3 H

  118. " o1 I" ?5 P$ V
  119. 7 q8 F9 k# o( e' ?% i, K
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    3 }. C8 {9 z! a/ l' y. S
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    ! u# n  M& C* E5 n
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符$ Z# m) Q% b0 f. w8 r; D
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧5 j0 ], m1 z- M+ F" Z  P) D  V
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    1 D* M/ `5 d: b- n. H. I1 ~
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据+ C" q: i- C% k4 m- N
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据 & J$ q% b" b+ _: T+ B
  127. + A; U, a( q4 C
  128. . ]$ U% x. m+ f; ]$ ?+ I
  129.     //发送数据
    ' h. s# d* S5 O" a+ y3 }+ J
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    8 ]- D" I, R0 P- ^( v
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    . L- n. x8 B  y' [$ N! G. j
  132.         i++;    //等待发送结束
    ! b, x; `$ P& T  Z. O
  133.     if(i>=0XFFF)3 p4 z* G6 P4 r( g
  134.         return 0;
    6 L; b( e, Y6 r, \
  135.     return 1;* M; \8 C: ^* V- J) @( k
  136. }( s3 [# O! S2 a# c2 s
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    * D* O* o1 S- i: }0 m4 _! V: Q$ H
  138. {
    & _# E  J& o6 R8 _, r
  139.     if(Rx_flag == 1)//发现数据
    9 v9 I! e- O+ J7 \" g
  140.     {
    0 k5 B0 l* v; ~8 k
  141.         *msg1=RxBuf[0];
    / F) F, K5 v! A
  142.         *msg2=RxBuf[1];
    0 y. w; }' y) u: G  B; H
  143.         Rx_flag=0;//数据已经取走,可以更新数据4 c9 ~) z, K+ |$ G- R. Y4 ~/ d
  144.         return 1;
    ' O' K3 V' i0 r  [; |5 _6 W1 V
  145.     }else
    # G+ }* F0 J# S6 k, ]: `6 ]7 }
  146.         return 0;+ ^2 `; u/ j5 Q7 u( i( v0 L; d
  147. }: m$ B# H1 r; R/ v% g# ^
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    . F+ B$ I7 E5 q, y5 B) q
  149. void USB_LP_CAN1_RX0_IRQHandler(void)' _9 i4 x+ Z( t  y0 X6 i2 J3 Y
  150. {) f% ^* D2 A4 x" M1 z& ~0 n
  151. $ x6 m& I! f& S" l4 \) {+ w
  152. : ]3 j& X' h% d& @
  153.   CanRxMsg RxMessage;
    $ F! @5 U4 r4 t$ `1 q
  154. 4 i; _8 f( H* G" l' A; B
  155. & p) F9 m+ v* P) D* `
  156.   RxMessage.StdId=0x00;8 _+ l7 h  G( Z; _# l1 n
  157.   RxMessage.ExtId=0x00;" q' e. _- J; c; E7 f3 t- V
  158.   RxMessage.IDE=0;
    ) H9 d' \1 X; ]
  159.   RxMessage.DLC=0;
    ; R4 H  V3 k$ J5 e
  160.   RxMessage.FMI=0;
      N6 [9 a4 [) y; Y  t% [, t2 b
  161.   RxMessage.Data[0]=0x00;  z- a+ ^  d8 M3 `  o
  162.   RxMessage.Data[1]=0x00;    8 m; q, L1 X# d. I) A$ X
  163. $ r( e8 Z! A9 ~) v$ k7 x
  164. 5 f, e- Y0 x8 I6 H: \
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  2 B$ K5 l  l5 O

  166. 4 v( g; i3 A/ d( ~& j& F: Q
  167. 8 F& y1 i1 j, p
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空9 b( w# z- s; \& h  q& o
  169.     {& q- _7 H- v8 r4 |9 T3 c) Y0 e
  170.         RxBuf[0]=RxMessage.Data[0];: ?" U; D& r" v; }' d
  171.         RxBuf[1]=RxMessage.Data[1];
    " T% n. P6 ~$ p: i
  172.         Rx_flag=1;//数据已经备好,等待取走4 V8 |6 K: W% v. N: ~
  173.     }
    / R6 Q8 i  h, N  v* R
  174. 4 X! @" P" Q* D  I( i) M7 y

  175. 6 r) I! V6 P! L7 H8 V, e
  176. }
复制代码
% T6 K1 [+ t: m9 |8 p
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
' O5 u( r9 V. j+ i. W# i0 ]can.c文件:

  1. ) G' q) {# ?/ D1 o
  2. #include "can.h"
    . j4 F3 N1 ]+ h. ^9 N

  3. & @* `7 z. W, Z4 h' R) K% A' N' p
  4. 9 E- C' L: s' k5 {: |# u. i
  5. /* 在中断处理函数中返回 */
    + b5 @. c9 }+ n. u% Q
  6. //__IO uint32_t ret = 0;
    % q2 |; f* A  S9 R; H
  7. 4 ~& f  q# c2 t" t
  8. ' |; {7 H; l2 d
  9. void CAN1_Init(void)
    1 q. y1 e  J8 k, v
  10. {
    : {; w% T0 X& M  z0 K
  11.     ......//以上与从机部分相同
    , M5 d$ W' J% }+ |
  12. $ d+ v: O9 p; i

  13. ' n& E3 U& q+ [6 J
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号1 g" y# \( Y- m& K
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为16 P4 |, H( U8 q
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    / `: ~( u& U4 u. H
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位6 x  u% f$ G% C, ?! L; t  |: I+ Y
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值! b" T2 C; I, Q% l, F
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值/ V1 f6 \6 K9 x8 e/ y# S
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值; R2 U2 f: r. F5 h& h! r
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值4 |* {/ x0 M7 _( P# I/ z
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    4 P% M* r- ?: T0 v
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器2 _2 h% d  L$ u: v
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    5 q5 P8 W4 ?6 [* x# m
  25. * V/ O8 V! t5 E6 \: K: Y5 ^
  26. 5 W3 c5 H4 g  s' X% P: }
  27.     /* CAN FIFO0 message pending interrupt enable */
    " _* I# F- p( p7 o; o2 f
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    + G9 M2 N* ~& o* R- T& ?9 D
  29. }
    5 p) F& A( }4 i3 i; e

  30. " p5 r: ^. _" d0 ]9 l- M% B
  31. + C! j- H. w* L& g- F
  32. //接收数据缓冲器
    4 L  L+ i  Y" P: n1 ~% r
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.& U" m2 s: V, E* J, q' N
  34. //接收标志位: C; T* b. l# p; `' j! z* ?
  35. u8 Rx_flag=0;
    4 s' T% P# q$ i0 w$ [8 z/ |
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */  P6 ~6 d6 I  S% T
  37. void USB_LP_CAN1_RX0_IRQHandler(void)  `' ^+ {3 x3 n. s& Z8 @, H; o0 U
  38. {
      T: u  H/ S! Q7 O9 k
  39.     u8 i=0;) p! a9 `1 T3 S) m  Z: I
  40.     CanRxMsg RxMessage;
    # T7 k4 T5 q( S8 g: H

  41. - y! M. ]( F: J. C% ~, {. A
  42. $ O& U1 ~8 D" w: i  u
  43.     RxMessage.StdId=0x00;
    7 O7 I! i: U: ~, u0 H4 b3 H
  44.     RxMessage.ExtId=0x00;3 C* T" w9 E5 h4 p
  45.     RxMessage.IDE=0;  b* o5 P# P# E" p
  46.     RxMessage.DLC=0;: q: o5 O  |' c
  47.     RxMessage.FMI=0;
      ?7 l+ P+ j/ l% O6 T& @' F
  48. : Z" S) u5 C* d+ D9 u5 ?7 O" W

  49. 0 V# o3 A: S7 w5 a& }$ `7 W1 N7 k- M
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    ; U/ t0 |- q- I0 J& x/ \+ U( U/ j
  51. ; w3 P* o5 Z7 b
  52. + b  e' f: b1 n4 e$ i
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空4 F# [" y: z. o: w: \. D
  54.     {) `! Y( v5 n* D% W
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据9 O" m8 M) \# B$ @2 F! f
  56.         {
    & {2 T( x9 j- ~8 D& r% f
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];
    0 W( e2 h, r, N! K0 M6 g
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     1 w4 ?: ^7 A5 b5 O- J
  59.         }
    , d+ w( b6 B+ P- F* e6 N& D
  60.     }8 l$ _. p2 v2 B2 |6 H/ S  t& a& D& g

  61. & y$ o: m/ i( N6 I7 G. j

  62. ! @' v) T% L: p' J
  63. } ( n& @, f8 J2 u. x5 _6 I
  64. 3 M) m3 g- m* z- s1 B& B6 `) b
  65. & f/ U$ v9 Q% y
  66. /* 发送两个字节的数据*/
    6 s4 ^+ d! A% U8 f( Z& g  C' V" i+ p
  67. u8 CAN_SendMsg(u8* data1, u8* data2)
    ; z8 v5 N2 e. o& `
  68. { 1 |" L2 S1 t) N
  69.     u8 mbox;+ a) Q; c8 j0 F& U8 L
  70.     u16 i=0;
    0 \% c. U" o1 y2 w. L! F% D0 _, [
  71.     CanTxMsg TxMessage;  2 y# A; H9 m- {1 ?9 R3 j, T
  72. , y  U, B% `! ?# G6 G' f( B" I* f

  73. " Z' `) f4 V' e, ]
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    * a% m9 |2 `6 D) H
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    % h) C: J- c. t) _
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    " C% q; E8 ]6 R; \. d/ G& j
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧7 \: b/ U1 G+ o( T" ^
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节7 D1 ]' t* w! C# \7 g$ ?$ }: C8 H
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据
    , g+ {% G$ \! _( u
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据
    ' N8 O3 ~* X! h) e8 ?& a

  81. 4 q+ R2 i. f2 N

  82. 2 W8 s- d+ K* k0 q6 h
  83.     //发送数据0 V4 \) R3 Y# h) Y7 ?" ^/ r
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    ) ]9 _% O0 r7 L/ z9 |5 Q0 n
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))& j9 B! w; Y& ?, `! H
  86.         i++;    //等待发送结束
    $ @& [, \9 `6 W( y" k, a6 Q
  87.     if(i>=0XFFF)
    0 j" |7 I: |2 W! k, |- _+ A) e
  88.         return 0;//发送失败) g* Q* l0 A: W& u7 f$ o
  89.     return 1;//发送成功
    , a- _+ r* {# x: e: P& D) d" j* ]& P
  90. }+ V* V1 G' y0 T3 }+ c( u
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    6 T$ v9 m1 z# x1 P! C
  92. {
    : L. f6 k7 v6 N4 T8 }: @  E
  93.     if(Rx_flag == 1)//发现数据4 w- Y2 j8 @2 p2 Q3 p" x2 o! `, b
  94.     {
    " W% @$ B: [; |/ T5 K- L) w
  95.         *msg1=CAN_RX_BUF[0];+ _/ [) @! z0 w) X3 {
  96.         *msg2=CAN_RX_BUF[1];
    . I, F- N" c* e! [" Z& J
  97.         Rx_flag=0;//数据已经取走,可以更新数据* _( A$ U% c1 @
  98.         return 1;
    $ M8 V3 [7 n4 U- |) U9 y
  99.     }else
    ( ?' B! m2 Z  O1 G4 G5 T
  100.         return 0;
    , h; ]* j2 h$ @/ ?; l
  101. }
    ! o- D/ @  G: @. K" j$ l, d
  102. void Clear_canBuffer(void)9 M5 t  M8 K5 ~2 N
  103. {
    9 @9 A6 |1 |: o! w; s" y0 p
  104.     Rx_flag=0;//清楚接收标志位
    ! M: m+ ?" C4 s, i, |4 P" R2 O! Q7 d
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区8 N5 k& N1 h5 Q
  106. }; z2 G$ s! N3 b
  107. u8 Check_canRX(void)
    $ _7 ]: w; ^0 }! G) ~1 q. k; m
  108. {9 T! B0 z" n1 J5 {, L9 d2 h
  109.     return (Rx_flag == 6);
    - e! |0 a5 D  P3 F  U- O
  110. }
复制代码

" e, _3 g& {3 I% X  L4 V  t  L5 q
can.h文件:

  1. 0 i- d$ h4 R* \
  2. #ifndef __CAN_H
    3 L8 s8 N* J* |9 ]  L- l
  3. #define __CAN_H
    $ b4 L; c( w* H

  4. - m- t- Z& b1 |/ Y9 p8 x

  5. , d- `% w# A9 O" Q# M) |
  6. #include "sys.h"
    # f1 m2 x) F7 H4 k
  7. #include "string.h"' O, D' W; Z0 i! J: O5 [

  8. 4 E$ s' E- c2 Y' P5 i/ O1 c
  9. ; Q4 t2 a' E* k0 ?/ S
  10. #define CAN_RX_LEN          30          //定义最大接收字节数 * ]  c- x- W) \* h& K9 D3 V0 h
  11. 8 [9 y/ W( L- _

  12. . h' N* _1 l6 H6 ]1 a) P) V: A
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 . ]/ H' p9 l: H- d$ h
  14. 4 Y/ i5 d( ~4 e. n9 R4 v

  15. ) D5 A( r: y& K- l
  16. void CAN1_Init(void);- K. q, F% G, I4 x) a  w+ W
  17. u8 CAN_SendMsg(u8* data1, u8* data2);
    3 k* V; o" i& X: ?
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);, H4 c, c5 T( K" a+ F
  19. 5 r- ^$ |- |6 Z. ~* _. o: U$ A
  20. % O8 H# c/ [# A3 i' X
  21. #endif /* __CAN_H */
复制代码

5 s4 }" B) p! {; _
赞 收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版