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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧
    : F% Q& e" I5 V$ s3 y* L* X
  • 摇控帧; `3 _) o3 `; `
  • 错误帧
    " V0 G) o& ^/ s! r
  • 过载帧
    & X- l) h" Q7 V0 W" I
  • 帧间隔

    7 a, J( n0 Z$ G' \' a( X8 w
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。0 c7 K( g' I( b& W
    数据帧一般由7个段构成,即:
  W+ w6 }2 P) s3 K(1) 帧起始。表示数据帧开始的段。
; L9 T6 f/ i+ D- ](2) 仲裁段。表示该帧优先级的段。
; C3 _9 ]) ^! r% g(3) 控制段。表示数据的字节数及保留位的段。
  M! s" t! H8 ~9 j' V+ W! J0 N(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
% i  {, A8 j- T6 Y$ z(5) CRC段。检查帧的传输错误的段。
  i+ \- n$ ?/ }$ f$ s6 w(6) ACK段。表示确认正常接收的段。
0 v3 E% f3 E* }/ o0 Z(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。6 z, G2 y- n' C% w
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

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

  1. $ E+ a0 R8 v& l, A4 F
  2. #include "can.h"  m/ i) @6 h' c% W; ~8 t" c

  3. 1 v" W5 K5 g( [# c7 q; ^2 v6 d+ s

  4. $ l; u! U/ S- B, a/ g+ Y
  5. /* 在中断处理函数中返回 */
    # W" ]5 I0 b: |  X9 H1 K) Z
  6. //__IO uint32_t ret = 0;, f& V0 b4 K' Y) q! ?

  7. # }0 X$ K7 u$ V; @* r* q

  8. + W' C) v& C( K
  9. //接收数据缓冲器
    ) \6 O& [( B6 K: |- b9 R- x
  10. u8 RxBuf[5];: w( V: V3 J  S! ~( G1 ~, I
  11. u8 Rx_flag=0;4 v$ h9 L7 k3 w$ D0 F  [$ O) o) V

  12. - s! k$ N: r- ~9 D
  13. & w$ N7 G; _- f
  14. void CAN1_Init(void)( L! y' u( _3 c' p
  15. {5 v! q( ^+ r9 a: `. k
  16.     GPIO_InitTypeDef GPIO_InitStructure;
    4 `3 R( \3 N1 y. V8 A4 @, x. G6 V# t- d) J
  17.     NVIC_InitTypeDef NVIC_InitStructure;' K. K' A6 _" r  v' i/ ~1 G4 t
  18.     CAN_InitTypeDef        CAN_InitStructure;
    ' q, N, P  T$ ]( m5 z
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    3 L3 a. S& l, t
  20. # }9 r7 e5 u6 P: H6 F5 j  x

  21. ! L' T' e, R6 Q- a
  22.     /* 复用功能和GPIOB端口时钟使能*/   
    % ^; D! H  F. p5 N& C  }
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      ' t3 R- o& ^6 g/ o. m( ]6 V

  24. 5 a7 ~" f9 \6 Q$ w& h4 K7 u/ ]
  25. , R' R+ y' j$ e' [4 Z8 Q
  26.     /* CAN1 模块时钟使能 */
    # |7 U' F4 n. c  n. G
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); 6 Z/ d/ D9 u  g2 e+ N* `  K+ z

  28. % O9 O; H" C# {0 C' t' I
  29. ( ]% S& @) |1 D3 h4 d7 l2 i- ~: L- A
  30.     /* Configure CAN pin: RX */  // PB8
    , Y+ M# a! {) G  F' V+ z: V% M
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;+ Y2 o" Z0 Z' v0 n2 n1 W
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入& x( o3 e2 e$ o$ l% {
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);/ X8 Y5 F* f) _, r
  34. " t; V: h3 a# a, R) V0 F% \
  35. 0 D3 a% v8 Y: U, }' U( s/ b7 o& w
  36.     /* Configure CAN pin: TX */   // PB99 w5 J+ t/ A+ G" K
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;8 V0 _1 k5 c9 G% K" I5 m7 l
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出5 w' X6 C" q$ u
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    7 }' q7 A8 x* Y

  40. 7 r) e0 F' t8 P: A, X
  41. ! a- S4 B$ {+ f; R4 z& b, F( e
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O* y- r$ d/ ?" p1 ]/ |' \
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);' u7 n+ R6 n' I+ x( C8 v0 l

  44. 6 \% u5 a9 l9 k

  45. $ Z, e& r3 ^: ?8 }' C- Q
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   8 ]3 ~' b# V7 W* c, m9 v1 B
  47.     /* Configure the NVIC Preemption Priority Bits */  + j) g4 P5 X: J& e& i
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);. ?( G% r* y; l# J1 O
  49. 7 j# ]$ {, J& s  {$ J& O

  50. " r- R( l/ T1 c$ ~4 _3 T1 G
  51.     #ifdef  VECT_TAB_RAM  : y6 L. x  R2 J5 D  P* P
  52.       /* Set the Vector Table base location at 0x20000000 */ # E8 Z; h/ E1 I3 }' d
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    4 Q6 q2 S! _# x, F6 g
  54.     #else  /* VECT_TAB_FLASH  */
    : L7 X6 |0 |+ {- y4 R
  55.       /* Set the Vector Table base location at 0x08000000 */
      O3 Q! a" {* ]3 m2 t: E9 c# Y1 H# G; i
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   + U3 {4 x  ^" \+ |9 _% u# c/ u9 y
  57.     #endif9 e9 B$ E2 w& ]! O2 Y2 ~  @0 ^  U

  58. ' F: X! ]9 A/ v, n/ r5 x% R

  59. & G4 Q/ c. P) d/ B) [3 [' `
  60.     /* enabling interrupt */$ G' `8 w* f7 _0 W5 H1 w
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;" B: ^2 H' G  ~2 W4 L$ p6 i" v
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;: f' `  ?$ b4 w( u4 k* A1 p
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;: @/ X* |. {) ^: @: K/ c# C) G$ p
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    $ B, S+ U- J; ~! R
  65.     NVIC_Init(&NVIC_InitStructure);/ G6 E$ a: V' d4 _) e
  66. % \+ B4 M- u: c3 q" |& m# h
  67. 9 {5 r* w: h) D" y: F  E' l
  68.     //CAN_INIT();//CA初始化N模块 - `; j9 u8 w4 F$ [# k
  69.     /* CAN register init */
      \) g, E9 r- W3 R
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值$ ?8 ~" E' V) a5 s/ f
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入; j* m+ u% `% x# C! T3 M' X

  72. 5 d: w# }" p9 Z# C- P3 H& c0 e/ g

  73. : d  Y) M4 o1 `$ u) M" r
  74.     /* CAN cell init */
    : K% [& E* V2 T4 T2 W% `- Q
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    3 E) W. J6 u/ q: y, p
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    & Z6 z8 F+ B: N" E' N& x5 `
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    : l/ j7 ^) ?% E' ^' t5 e
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    0 k3 P0 }" D3 _$ h! h7 w- D; T$ z
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    8 U. N: c+ e) b
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级7 }- Z6 [7 }+ S& n
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    % r% r' l. o; U2 y- T. {
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    + c7 Y1 D3 g9 x2 ?0 }
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    + ]! d) W% _1 n6 }, z, X% n
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位* w0 T  A5 R* }1 }9 x' ?" z3 w
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    / z$ h7 o! ?" S) X# }5 {
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    ( h4 Y! d3 q# z4 e! a. f) \
  87. ' ]# f: |2 h4 }; i

  88. 1 x! H' T1 {) m! K: c9 Y/ V
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    ; y" Z8 k$ v% F$ Y
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    ( v* @7 [( O. z
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式8 E& z* ?  b* u
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    " }; f  j0 U- Q; X% P! P$ ^

  93. # k% T0 z8 A, h4 p& E$ T

  94. 0 q: Y. ]8 c& j7 C; {6 {
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    6 ~# B( p7 z; z( ]
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    $ n% r( I2 M( d+ Q+ w
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    " P0 e. l+ l" p; z* U: Z
  98. / ~$ L8 S9 G9 @
  99. 1 _1 z$ `: Y  y  C2 j
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值  {- ^2 y& \- [9 g8 I6 B$ V  g
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    3 s1 Z4 p2 d! \7 D
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0; N- F- o$ v# ~, S. A' ?# V
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器# @5 R+ {- F  R; Q
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器5 U" N( s: _: e8 c

  105. 1 ~8 \* `. P) G

  106. ( y* w0 [: {& K7 |6 b
  107.     /* CAN FIFO0 message pending interrupt enable */ " [* c0 R3 |( @& @& X
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断0 V1 m9 x  F6 F- w/ I+ g" f6 j
  109. }
    4 @' D& u1 R6 w0 P& U% ?2 ]

  110. 7 U( ?7 M, }' t- Z5 V
  111. 9 c% B$ N8 D% @+ ^- z
  112. /* 发送两个字节的数据*/
    ; I, m# X( C4 m$ T) K  H- z/ O7 ^4 U
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)( I8 z. P. a+ R- W
  114. {
    ' f& _2 N' B" X6 v
  115.     u8 mbox;! Y  q. e" Q0 E
  116.     u16 i=0; % ]- \/ l8 z% E9 L, c. |! g+ s
  117.     CanTxMsg TxMessage;  
    ! d2 {! C+ z( k6 X9 w3 m- `7 K
  118. 6 v# T8 T! D/ B' k+ d# N) g3 Y' ~
  119.   y4 H! u6 G2 i" R2 C& o
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x004 P5 E% y4 a; @7 @0 T. w
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机  }3 m$ e( X' f7 k9 g3 s, ]" n
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    5 {" L/ R# \- t- W0 X/ ^
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    # V3 ?' a/ Z6 e7 x; ^( g
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节9 G0 \6 }  q! d0 Z
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据
    . |$ B* g" w9 y; Z: s( u1 O
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据 $ W$ f5 J  [) ?/ l$ {

  127. & \6 x: i0 b# b; |2 H

  128. 9 ?& b7 P1 ?( v$ E
  129.     //发送数据
    1 g9 `3 P; ?4 z7 b8 _  n
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  % g! H. Z, N0 ^$ ?* O
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    4 ]4 d3 j' O7 x2 d' q0 ]
  132.         i++;    //等待发送结束
    + F* j; P: j8 N6 t) V. d. r
  133.     if(i>=0XFFF)5 D5 J! D+ s: s
  134.         return 0;) {6 A7 e  u. ]$ p' A8 ?6 d
  135.     return 1;8 {7 @# T7 ]7 \
  136. }3 A$ y; t9 C0 p6 k
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)& J9 ]2 u6 o2 l0 G3 C8 t  \5 J
  138. {
    2 J+ Y' v4 e3 S5 [* x* B) O; n
  139.     if(Rx_flag == 1)//发现数据
    8 g+ z5 U0 u% H; p% D5 i  c
  140.     {, ^( J; B/ ?: h0 m. R
  141.         *msg1=RxBuf[0];7 |" a6 S3 i  J- v% V
  142.         *msg2=RxBuf[1];' {8 e) G: B3 d6 `' k# r$ `" R
  143.         Rx_flag=0;//数据已经取走,可以更新数据  }2 q9 L& d0 b! {
  144.         return 1;
    ( _% M4 \3 l! U) A% w% p1 u
  145.     }else
    . W7 a& W5 X  l0 H
  146.         return 0;. ^1 S8 U* N7 d" m1 q! T
  147. }
    ; B3 z4 c, X! R, ^, `0 ?# K
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */3 }& }& t8 m9 p9 ^
  149. void USB_LP_CAN1_RX0_IRQHandler(void)
    , r7 U' l9 _5 B/ Z; w1 ~
  150. {! E4 N5 G" N/ m* _

  151. 5 ^  J& d' s  `, v0 ]/ f2 g5 E

  152. 7 t6 H! G: h& I6 z6 u) d
  153.   CanRxMsg RxMessage;3 Z3 I" `: S4 H# C) n- i" J

  154. % @* L6 b5 ?1 g

  155. : z' V" q3 v* s+ h8 U* }2 b* @& g
  156.   RxMessage.StdId=0x00;0 @' }9 u  n) D4 N8 L
  157.   RxMessage.ExtId=0x00;5 A) g( f6 [/ n& b7 H
  158.   RxMessage.IDE=0;2 _+ k9 m% _8 w) w0 R( _% `: Y5 E
  159.   RxMessage.DLC=0;
    + v- a- @* x4 `/ l  q
  160.   RxMessage.FMI=0;  p1 R; {" \  ?5 X9 Z- A
  161.   RxMessage.Data[0]=0x00;8 H3 g; V" ^& w0 n1 [
  162.   RxMessage.Data[1]=0x00;    . U7 G/ b. [# _- m. p+ R, f9 [
  163. 1 y/ `: D9 s7 _8 t/ D- b4 X4 }  k* i

  164. / D, e( j& q4 t5 Z
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  - X0 _9 _4 t. ]
  166. ( Q, m4 ^2 c( K8 F* j

  167. 7 s$ K2 ]: [$ P. N
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    # d& Y3 e9 _. l5 F6 M+ {
  169.     {1 t9 z  A, X9 f$ n+ u
  170.         RxBuf[0]=RxMessage.Data[0];
    3 Q6 U0 D% H+ A+ ~  A6 B
  171.         RxBuf[1]=RxMessage.Data[1];  T, d* M# a) @/ \1 r. L; N
  172.         Rx_flag=1;//数据已经备好,等待取走
    ( K2 f  ^; H& M: b- L& s4 F) K
  173.     }
    / [' X% [6 y6 L# \

  174. ( ]# F& z+ ~. f) [6 T

  175. 8 W/ x2 e( k0 @" r# o
  176. }
复制代码

1 X; _( ]! C4 ^2 Z) P
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。0 ]% k& z) e' D
can.c文件:
  1. # c$ _3 |% [# r3 _, g/ d8 T  N5 i
  2. #include "can.h"' o  N9 }+ s9 c4 F9 t" F/ V
  3. 2 w( _. U7 J) i  R- u

  4. . @+ ^9 l, l" c' o# O
  5. /* 在中断处理函数中返回 */  l+ E1 Q' ^6 X0 u8 s! A, d
  6. //__IO uint32_t ret = 0;
    1 w7 r' @8 r) L) \/ g! _
  7. . r3 V0 b1 }! f( K

  8. , U5 ]) c7 D9 w7 c: K
  9. void CAN1_Init(void)
    ' T! x3 h$ M' M" q2 i2 F
  10. {4 E% ~7 A8 k$ B
  11.     ......//以上与从机部分相同
    . h+ ~. N0 `/ T7 g" j

  12. + Z" l/ Y5 E6 m$ V. N) L0 I$ F3 o
  13. ! E9 I" |! T+ v
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号  k9 u; I0 t* k0 c
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1, d! A1 ~: |, G* j! V4 H4 n" G
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式5 j  {/ O0 c- Y" X2 X2 ^( P+ {  t* ^
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    0 E/ n/ a6 {* o9 C& o1 k# O) F
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    8 q" g; V% w" n+ `: \
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值1 p; V) o3 `8 ^" q: b) y; t
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    1 G" ]1 T1 y' N: s" t( D# I* o0 c8 h3 Y
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    + T2 p+ u1 @. l& E
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    9 f2 v. R4 }. p; t
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    8 N( [! l# a( E' w! d) a$ R
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    . y) y" h  y* ?' y" _5 J+ v

  25. ; ~4 |9 ^  u$ t! A* v) _

  26. 7 D8 b5 p; \, j6 d* U
  27.     /* CAN FIFO0 message pending interrupt enable */ * r) r+ A0 `; @3 a/ E
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    ) v6 ]& Z' ]' \4 l7 a2 ^  g" }) n
  29. }* z+ D/ \. f2 p/ _8 h

  30. 0 R& h5 k6 b8 _# P
  31. 4 [' J# y3 U& r5 m* p
  32. //接收数据缓冲器
    , q! |; ^# t4 k+ B! W7 x: [
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.( k* t) c3 g5 T2 A7 X9 m' A5 u
  34. //接收标志位# x4 z# g, d' x6 j3 b+ m; j0 N
  35. u8 Rx_flag=0;( }4 q' P2 @) e. @7 R( _
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */" h4 L. G5 O) U' w) [' X- E" Y- h" j
  37. void USB_LP_CAN1_RX0_IRQHandler(void)
    / H0 s- F2 P; \6 c! c" f
  38. {" D# B' I  e4 h5 B
  39.     u8 i=0;
    ! H; X0 m# E& c. R% u
  40.     CanRxMsg RxMessage;. Q) f9 q: w- k6 N8 J% ~* Q

  41. 8 P7 V, p3 u4 k" b7 @& u

  42. 0 ^0 P( e5 G( M, s, w
  43.     RxMessage.StdId=0x00;
    . q" f8 U& P1 v- K/ T
  44.     RxMessage.ExtId=0x00;& q/ ?9 f7 q) K  G" ~3 v1 U2 P
  45.     RxMessage.IDE=0;( A* u3 N5 L4 j
  46.     RxMessage.DLC=0;) z! H4 S8 d1 n# r: h+ m6 I% |+ l
  47.     RxMessage.FMI=0;
      n+ Z% k8 y, ]' k- l) g5 \: T
  48. : k% `6 M) R$ y" w0 P1 {6 [
  49. 8 k& [2 Q8 _; x& @8 m; [  v( o6 V$ a
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  % d1 e2 R3 m; i$ B" }( Q7 d

  51. 5 F& t; h) y6 a8 h% P% M
  52.   y* C! H# d$ N8 I7 u& F% i+ c
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空& v/ J) @* `# y% [1 W6 f2 A
  54.     {
    ( m3 ^& |1 R  h
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    8 M, W: r: @9 z- r
  56.         {, G$ T, x4 A8 L" c6 |+ o
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];6 C( ^" n# v( T  c7 U& H
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     % @# O  a  K9 o8 ?& {* R9 B
  59.         }
    9 A. L: W1 b. g$ F) m; L2 @* ]
  60.     }
    1 K" ?+ Y9 B5 {
  61. " @  W, V% e( P
  62. ) O2 P4 l+ V9 i1 d+ \8 ~0 }# ?
  63. } $ g+ `6 h' B" d" s- S1 L% P
  64. ; Q7 \5 S$ i4 c% B' z
  65. . }3 _) Y, Z6 u* R
  66. /* 发送两个字节的数据*/4 L7 K3 ], H3 `" r2 j8 T7 c% ~# w
  67. u8 CAN_SendMsg(u8* data1, u8* data2)
    1 ~9 z2 i' Y8 }& P1 L# G5 ?# y& ?
  68. { - J2 S4 u% n6 x/ }' M
  69.     u8 mbox;" t) l4 Z* _" M3 s$ g6 j% i- W
  70.     u16 i=0;
    + P+ t2 t6 q, A: `
  71.     CanTxMsg TxMessage;  
    - [8 X4 g! p0 |1 Z$ P: R( a

  72. : Q8 `# {7 Z; x- a
  73. ) i' \" W3 l6 G* p$ Z
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00% J* K( K( `! \" R
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    0 B% Q% N, K3 X8 G9 _7 T
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    % l- @' F# X# z9 P
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    / `. A8 d  R: T& q
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节0 s7 j# d, h' X1 G' a( c3 ]
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据
    5 e$ ~" ?# ?, p% j1 U- h
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据
    * K0 m& U/ R/ A% z

  81. 8 K2 E3 m, }; L  X1 J; @; b  q
  82. 3 z  ]. {0 s5 `  }$ I3 t% Z
  83.     //发送数据/ y0 `# r) V5 @
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  8 u  v% N9 H, C
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))& G# k3 e+ C8 J
  86.         i++;    //等待发送结束
    0 y! V2 r; k  @( ]* ^
  87.     if(i>=0XFFF)/ B) ^7 Z( r1 H2 j' O
  88.         return 0;//发送失败7 N8 R0 M& P% p6 f# n$ W
  89.     return 1;//发送成功
    * o, F0 r# Q  ?- b
  90. }) J- _4 ^- I( z6 c$ {
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)$ ], x: U1 R# R. L- x
  92. {. l1 G) F- f. y6 B' n
  93.     if(Rx_flag == 1)//发现数据1 _. b) i! e$ G( J- \6 H% C7 {
  94.     {
    + p# @& c5 h3 c
  95.         *msg1=CAN_RX_BUF[0];
    / r! R. g7 T5 k7 S! Z* W1 D
  96.         *msg2=CAN_RX_BUF[1];" T- p) i. N1 }2 t6 R
  97.         Rx_flag=0;//数据已经取走,可以更新数据
    1 @' q9 K. V- T% B. f/ I
  98.         return 1;% M8 L0 u/ I" I* A* Y8 h
  99.     }else9 H. X: U+ u5 K8 x. G4 o. e
  100.         return 0;; |2 H7 G' o; h* k; t
  101. }
    6 M+ n3 r0 i9 N4 n' x0 q
  102. void Clear_canBuffer(void)7 C7 e1 V/ [' n; I$ Z+ V% A! d! W8 j
  103. {
    ) n: v  p6 O  e( V* _! l9 ]
  104.     Rx_flag=0;//清楚接收标志位
    7 Y5 }% B' @* r
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    $ {) [) f9 Z0 n$ N6 l7 V
  106. }
    / R2 S2 o3 W. q* M/ n
  107. u8 Check_canRX(void)9 `5 f0 Q# w  H. f2 e) |# |
  108. {' w! |2 b  m0 U% E" o
  109.     return (Rx_flag == 6);1 Y% \( w* c& t9 ]8 y
  110. }
复制代码
, G& w& h' z% O& G( D
can.h文件:

  1. . L! s9 u; g4 N* r$ L/ N0 p
  2. #ifndef __CAN_H
    5 c+ V9 f1 q- r3 V0 R" {4 w2 b+ W
  3. #define __CAN_H
    $ Z1 U6 `0 _# ]/ d; R  S& e- f! i
  4. ( j7 B" R8 y' G2 O4 R" s' R

  5. 8 @' S+ u& @  _' }9 `
  6. #include "sys.h": B, C. p: ?* B0 [$ |& b% U
  7. #include "string.h"
    # n& K! w: s+ c( c* ?2 l# Y' `$ r
  8. 3 i9 V% \% \* t! M7 c0 S3 V2 x
  9. 4 \; q9 ?' j$ w3 F& B
  10. #define CAN_RX_LEN          30          //定义最大接收字节数 & V! n' f$ O/ U' g! J( r

  11. ( v% k2 @/ }# ?& y- ?$ Z2 {$ D- Q
  12. 2 ^  |" m5 @6 M9 h# s4 v/ Q
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 . R2 l, n* v8 u+ S& |# l
  14. , ~! {3 f$ b  m7 F

  15. . @  D) R  p  n- d0 P. t- i4 E
  16. void CAN1_Init(void);5 H: F: ]' k2 a" x. S' y
  17. u8 CAN_SendMsg(u8* data1, u8* data2);" V! x! @) T$ `8 m
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);# [3 L/ T6 k& z: s; \

  19. 7 q5 o- |  ~* t# I
  20. ) f* A* c0 u* I0 b
  21. #endif /* __CAN_H */
复制代码
4 }- [. @6 {( p7 x6 z
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

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