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

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

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

    . O5 M$ N* o4 {. x* U3 O
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
$ {# i. D9 o- m) ?    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
0 v! @1 t# Q: c6 X- M
PERMNQ{)L%G}{986WRA~Q]W.png

7 v- ^1 n$ D5 \- A. o" Q& k' X3 c
    在程序中就是:
  1. //要过滤的ID高位 ; P" K- A. K0 V4 g% i! [2 U4 H
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  ' M% _2 G9 X/ O
  3. //要过滤的ID低位                 ) M& Y9 u7 u2 _& z* O. P" ^+ t
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    0 W7 \/ g# G, R* b5 W6 i& F
  5. //过滤器屏蔽标识符的高16位值% F( w  }% q6 R$ B3 h5 I
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   1 N: E) G& H+ Y6 @9 k
  7. //过滤器屏蔽标识符的低16位值         & i9 N( i3 [, r( j# x4 I
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

6 @) q* f2 U. T: H/ L
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
  G1 ^  ^, m% b" V3 e8 |
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
2 k; o& Y8 ]8 f) H$ I0 B0 T主机:0x1314& t) m( J% }3 S
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:
  1. ) t# B. h& B( q, P4 M! H
  2. #include "can.h"1 Z9 [; h: ]; N9 D

  3. 4 P$ U1 H4 J& `( c: Q
  4. # n: g" F& H  ]2 d. i0 |/ a; E
  5. /* 在中断处理函数中返回 */
      q( i( G% t+ _6 P$ G# ?7 x! |( ?
  6. //__IO uint32_t ret = 0;5 B) G" O' S- ~* S5 @

  7. 4 P$ e+ L# n! O! e5 C, R
  8. 9 x8 U- V- Q, }% o1 j1 R
  9. //接收数据缓冲器
    5 b  o0 X) H8 K2 n) g6 S2 u/ }6 J
  10. u8 RxBuf[5];* l% d) `2 F" B, a% D# x4 r
  11. u8 Rx_flag=0;- V/ Q  K. T' E+ J% x1 w; V; O

  12. ' j" }3 M+ n& ?  O" o

  13. ) L2 v0 Q" Y* b# ^* V0 l
  14. void CAN1_Init(void)& t: |$ Y0 g1 P5 M! z* i, ?
  15. {
    . f( l/ Y/ }* Q) o/ |
  16.     GPIO_InitTypeDef GPIO_InitStructure; ) K- S' Y, b& v! I/ W+ x% K
  17.     NVIC_InitTypeDef NVIC_InitStructure;3 l  O* s4 F. b- g
  18.     CAN_InitTypeDef        CAN_InitStructure;6 K: I% E. l+ ?  T+ @4 k
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;$ h$ h5 A* Q- A( u4 K
  20. , s# }; d9 B; ^4 \/ V

  21. 0 ~* r& k" R, J2 T0 n
  22.     /* 复用功能和GPIOB端口时钟使能*/   
    : O! ^. Y. N, N, I' O3 K; Z
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      ; W1 s0 z3 n: [' U$ y0 b
  24. " B3 k9 |" ~+ r

  25. $ E) ]; q8 Z  y8 w, F. H
  26.     /* CAN1 模块时钟使能 */" r5 U7 i/ ^. a  F5 G
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); + s! s4 _: Z' O
  28. " _+ [, M! F- {7 a/ R2 S

  29. - E5 _0 g: V1 }) `( a5 H. E/ O
  30.     /* Configure CAN pin: RX */  // PB8
    3 w0 X) k1 R& z
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    " q7 c+ z* V3 o5 N# t) j' s) |
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入/ i4 ~5 K7 y4 d7 L- A
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    : c# c0 B( u: K( J  U4 e

  34. 1 Y; b+ n0 G+ V; d# |" z# ]0 L

  35. ' C- m" U0 h' ?0 m$ ~9 S( }
  36.     /* Configure CAN pin: TX */   // PB9
    6 ~4 \% w' s; m4 [% X) d3 C
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  b; `' n. X2 _/ b! g
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    3 r* p+ L% O* ]( x" n$ Y
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    / w6 J+ `, q# K5 }- d. O
  40. ( I1 |! w# c) i5 R
  41. 8 P. Y0 U2 |& ^& |2 L
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O2 Y5 _6 n: C! v& a, _
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);" E9 E$ |' _4 a- |6 n. N

  44. % B3 n; j+ l/ B, T

  45. , |) d" r  q$ _; s! }& P2 C( `- `) i% g
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    3 L/ ^0 e3 z3 t: W9 M5 s
  47.     /* Configure the NVIC Preemption Priority Bits */  
    . Y1 k, A8 q/ T0 E: z
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    - H+ Q8 f0 X# t8 o) g

  49. + [" ^. _+ Q  r2 F; v" m4 ~5 R

  50. ; Q8 }& x( J& Y1 u3 j& d: U! g
  51.     #ifdef  VECT_TAB_RAM  
    8 A/ g& J0 j3 C6 Y8 D3 a3 C6 C
  52.       /* Set the Vector Table base location at 0x20000000 */ 6 |5 M' I) G9 Y
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); + n8 {) E- D6 p$ a& B
  54.     #else  /* VECT_TAB_FLASH  */
    , G7 n: ]2 W( ?' ?6 G- g) I
  55.       /* Set the Vector Table base location at 0x08000000 */   B2 ~& x9 N! v8 ?7 }+ j, ^
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   3 r4 P5 L/ w: ~$ p6 N' Z# {
  57.     #endif
    $ H5 F3 v: c6 L! l# C
  58. # D8 y$ ~$ G7 \7 q" z

  59. " O8 I8 ?% S+ A! J; B! h( y
  60.     /* enabling interrupt */
    3 l+ x" Z3 e; r( K
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
      ]6 H4 ]6 V! b6 |% g# y
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    9 H/ A  l# {$ E1 X5 z1 d
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    9 h% e/ n6 ]  z) J- I0 F; B
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;$ ^7 T$ I% j+ v' d
  65.     NVIC_Init(&NVIC_InitStructure);
    , N* d; _$ V2 m+ |  C

  66. 0 b; T* O" R1 I; F5 x3 |0 N

  67. / f, b/ X! L7 X
  68.     //CAN_INIT();//CA初始化N模块
    / m5 I  n9 }# U( T2 j
  69.     /* CAN register init */- l" ?! L7 l2 R
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值2 d1 A; E+ v4 r; J% k
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    4 K# s: e' }/ O

  72. 7 V& J/ p) W( L8 C. f+ D: p

  73. 2 ]) u# R) e' v" H) V% q/ [$ u7 f6 @
  74.     /* CAN cell init */
    4 _. o+ E1 D# S) @. X& l
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    ! j% p' ]9 v) I$ T& u
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理3 J( Q0 Z9 d" u% s  n5 z2 x
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式$ W% b+ D1 f9 ]. `8 H. N" q
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    * K$ Y: p' {4 A2 {
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    4 O6 O  S3 r+ U' p  N, P
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
      {& p* ^/ d0 I& j7 d% l' `' F
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    5 @* l/ O/ `7 `* n5 _" f
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    . [  N+ R) s2 I0 K/ c$ B) o
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    / e2 _$ ]7 y( e  c3 E
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位
    5 K- {/ d" E, D% F4 S
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    7 w# _+ [1 d2 r& L1 V1 Y4 S
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    9 s- @4 R1 r2 ]  \/ H! C
  87. 1 {5 P6 e8 E% Z3 B+ `

  88. / s, E: {* J! c. M$ ]; k
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据8 c0 ]$ Q4 ~. e) }% [' u
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    1 k2 l$ N4 @1 {
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    & k, O- V0 k3 T' ^5 x$ M0 c
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位$ f* L$ V2 @4 ]; [9 p: p2 Y; S1 m
  93. 2 o! p; D( P% o! e) J* B: ]

  94. 7 w% M8 d0 @0 U3 S1 E
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    ; l5 a2 G0 {7 a3 W2 K
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    . p0 z( R+ |; S
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位 , z3 o* E6 x3 G% I
  98. % ?) |+ c3 ~7 t8 A& T/ B
  99. ) P( f2 q) q" n3 F
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    1 }- ]4 I6 i5 l+ \( D  O( K! O
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值# d% R( q* B4 {; q) l/ m
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0! F5 [# _- C2 G+ i" C
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    + `8 I: T# h8 W  J6 G: _
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器7 ^: }/ V: p& I+ c( r% n, i

  105. $ @; q: x+ E- D- ^
  106. ; D( \/ u8 Z' F( }: M2 P3 H
  107.     /* CAN FIFO0 message pending interrupt enable */ / e' J' b/ ^( l0 Z: F0 R
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断1 ]5 P# W3 ?' U
  109. }
    / _5 Z! S# h: X9 W6 n9 O* j' n

  110. 0 @3 O! B6 x+ J8 W! o% @' r) d
  111. 9 u3 R8 c0 q4 G2 [, a( ?$ p
  112. /* 发送两个字节的数据*/, c/ P; ~4 @. \+ g
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    0 e+ B( C3 S8 k# S. ?$ m
  114. { . e, `1 O7 \0 f; `0 v: u
  115.     u8 mbox;
    # q) C- l' e9 L" K$ b: U4 Z% O( a
  116.     u16 i=0;
    % N! V- Q8 o" H, l; M& F
  117.     CanTxMsg TxMessage;  
    ( h& g% X' B! k# _6 j9 c5 O
  118. 2 d3 A! _& c/ f0 `: a7 V; n( m
  119. ; v0 b8 U* V% l: Z
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00' s1 ?! ?3 Q& Q5 g" \5 a0 s& _
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机" x* L$ ^  M  A+ A/ J- E
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符2 G4 E0 k0 A$ L* P* R6 k# C
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧7 f+ Z4 E' m! N5 p; @: ]
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    $ V, T5 c1 X- V0 `: f+ x* h
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据
    . _: g7 i, u8 K/ o
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据
    * \& l1 O5 d; l0 [! S

  127.   }+ [6 f) t0 I/ G) D* W8 D; a" K' }
  128. 2 L' u! D0 l4 [2 Z5 m
  129.     //发送数据$ g: J3 k- P" `( S$ [; Z
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  0 @8 X9 C* g! W# |. F) R" u
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)); C3 F$ h3 g4 @* S
  132.         i++;    //等待发送结束
    $ V( S5 c8 U5 F7 D
  133.     if(i>=0XFFF)6 ~, H, O) g- ^, l
  134.         return 0;
    3 ^( ?! ]7 g" m
  135.     return 1;- Y, ?8 D5 M# u4 T/ ^- [
  136. }" l0 E7 ^2 [; z6 d4 u( k  v
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)8 H5 M/ h9 R" a( d" p
  138. {- r8 m" J/ P# ?6 \8 F! o
  139.     if(Rx_flag == 1)//发现数据% G0 i8 U  G, _  z/ |
  140.     {
    & a' ]- m& G! C! }4 ?8 s! }* C4 Y
  141.         *msg1=RxBuf[0];# F  B# [/ N& A% B, b/ `2 Z$ x+ G' L
  142.         *msg2=RxBuf[1];( m" T* N$ ?1 T: x# I5 l) _4 P4 _
  143.         Rx_flag=0;//数据已经取走,可以更新数据# [& O7 G0 c# q# |# O
  144.         return 1;* n! W. q9 X' \4 K7 `' X* Q9 ~1 a
  145.     }else
    , w6 J0 t# F! e& m, s
  146.         return 0;! I) T* \- f3 X; a1 K5 X
  147. }
    / J5 C7 w0 Y, z+ O3 O4 U# a
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */5 \7 [2 c- a. W8 M
  149. void USB_LP_CAN1_RX0_IRQHandler(void)
    ) ]6 P: ~* w8 P& A0 \
  150. {4 R5 U' I8 r2 a( q

  151. 0 P7 e, z$ @( J5 p

  152. , P) H! l: w: H$ @( o. Q4 O7 R
  153.   CanRxMsg RxMessage;/ V/ x  j9 U0 f. w) K

  154. 1 ]3 P4 T6 m$ m8 [5 y

  155. 6 ~& @* P; {: y
  156.   RxMessage.StdId=0x00;" v9 Q7 d; o, B+ L: H
  157.   RxMessage.ExtId=0x00;
    7 L0 H% t7 @; b9 Y
  158.   RxMessage.IDE=0;0 r+ f* [; d5 i: O* y! `* U
  159.   RxMessage.DLC=0;
    8 y# r: l6 L( E. |& X' C
  160.   RxMessage.FMI=0;$ n/ b1 j; @+ q. }$ Q2 Q
  161.   RxMessage.Data[0]=0x00;
      E, L' t) @8 x/ x; P9 v
  162.   RxMessage.Data[1]=0x00;    7 k5 I" U) ^; ~+ ]# o/ r8 T  p7 {8 ]

  163. , y# I* s$ T4 ?4 g

  164. # K9 q6 H+ ~% I) a7 [
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    2 Q! ~9 ~. l/ h+ G5 k  j

  166. 0 B! R- Z7 B; t( e, o7 z4 o
  167. * L# z8 r0 d. t- G, _
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空. ~3 j1 m' f' d2 q, Y$ [! Q6 e  S+ p
  169.     {% Q9 a# Y& _& A$ f  s7 @6 z5 [# \
  170.         RxBuf[0]=RxMessage.Data[0];
    4 w5 X8 r3 S. _$ W4 N# L
  171.         RxBuf[1]=RxMessage.Data[1];7 ], U; j) P; Q1 }, G
  172.         Rx_flag=1;//数据已经备好,等待取走4 P8 G7 F4 a+ z* X4 k9 W
  173.     }8 }1 p0 k6 {1 n. j8 F
  174. , Y. Z  A  E- `$ h& m2 c
  175. 6 ?. @  |+ v6 C+ v  a) ^
  176. }
复制代码

" Q# G. D9 k" b. E9 l# O
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
/ Z3 s  U2 o/ k+ [1 Ocan.c文件:
  1. 8 Q  b2 X9 {! ?! c  ^1 I
  2. #include "can.h"8 T5 `! ~3 A% O- h) k' L! t- Z

  3. 3 m! y! ]  g- R
  4. ; {! y7 k, B( C" @1 ^
  5. /* 在中断处理函数中返回 */
    # a/ e$ N& j4 G7 Q3 W3 ^
  6. //__IO uint32_t ret = 0;: J' l  G, @- i4 t, N" {

  7. / s6 r/ q; {/ Q! l5 O5 y+ V
  8. $ W. n- E) E3 ^; S* E0 q0 J
  9. void CAN1_Init(void)
    ' S% O- X- B2 b% p
  10. {& f! U. E% @  i9 y2 J
  11.     ......//以上与从机部分相同
    & ?1 k$ Q% G5 U/ D
  12. # W9 p0 b: z; r* b6 ~; R# ~
  13. * U9 k5 A9 y% Z3 M1 L
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号& L$ x# g7 L: o* ^  j! {& M' f- Q
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为12 `2 S) n) q( t
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式% A+ d2 K" ?; ]. G; i
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位- U( I+ Q# z3 c0 o) ?
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    + m! S7 o; \6 x
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    2 U4 T& T  K  {. u1 o( r, w; h( K
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    ! F  i/ C& T: z
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    % m3 H/ k( I% _6 r& b& o: @& W
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为06 N* x' e9 W) x8 E. \7 V
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器/ x  L$ T2 ?/ a+ v, y3 Z( t
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    - y: L7 F9 @/ [6 G3 {+ y4 i) y9 G
  25. ' g% f! e6 G5 }4 G* c7 q4 L9 f4 m

  26. ) e7 k& x! g& Z4 Y6 a# Z( g$ S1 f: x
  27.     /* CAN FIFO0 message pending interrupt enable */
    ! l8 R( S6 D, R* f0 C4 s
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断3 M/ z& }) I! c! }! a( d
  29. }9 f2 k& y# B% t$ {0 J. Z  x; K% D

  30. / j" a7 ^8 R0 K6 I: g% r' ~

  31. 2 E6 [8 E: ]6 d, |# S
  32. //接收数据缓冲器/ X- `5 B  Q+ P  H) s
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.* D9 F  L1 a) h% H- p% d  o8 L8 A0 ]1 r4 b
  34. //接收标志位+ A2 H" C9 `/ V
  35. u8 Rx_flag=0;- {8 v# Q% N3 L2 u# M
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */& T- g7 |% n  a- R4 F! \( f& o
  37. void USB_LP_CAN1_RX0_IRQHandler(void)
    8 o9 Z3 \8 I6 ^! j
  38. {
    8 `3 T5 c) c' u  _
  39.     u8 i=0;
    - k; k% R6 u# l  Y# L
  40.     CanRxMsg RxMessage;5 u5 n9 V6 {" A, O
  41. / o7 H3 Y( Z; t
  42. 6 E: ^" `, J1 |( C1 w+ u# J; O
  43.     RxMessage.StdId=0x00;. |8 n6 H# @$ O( {/ c6 c# B
  44.     RxMessage.ExtId=0x00;# o1 h2 O; |! a" K8 s7 n2 u5 t
  45.     RxMessage.IDE=0;
    # }3 ?( s& Y' Q& r# M
  46.     RxMessage.DLC=0;
    " `. r7 P& Q5 a5 }! _
  47.     RxMessage.FMI=0;" j! q+ p9 H/ o8 z  u2 y  [

  48. - C5 W9 F0 [" h  ~1 [1 n3 w

  49. % c# @8 h( \4 j" f. j7 R! ~
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    6 ]2 X6 ~5 ?3 c% W, ]
  51. & x3 P/ ?: U8 N/ N% |; V

  52. : _2 q; H4 K4 u8 m# e3 W
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空
    + L6 H* o. J& G% v$ a
  54.     {
    9 x, h3 _5 C4 U
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    7 B9 c. T- ]& M( D% I) j
  56.         {; o, J$ {& `! t+ f
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];
    $ y5 r) M+ R: k3 ?; z( s- B
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    2 V* x0 x; h5 V6 @7 b9 ^
  59.         }, ], u1 N7 {- ^4 v* ~3 t  Z6 W. ^
  60.     }" }% j# e! d9 ^4 ^$ w
  61. 3 ]% {# e7 p5 s/ g1 k& O9 X

  62.   s# Q. R7 }9 L# v6 L
  63. }
    5 e1 m; Z" h" ]$ ~2 S
  64. ! z9 P% O* \& E! V
  65. & [0 g5 k1 o( O7 Q  X  ~$ v' T6 }+ J
  66. /* 发送两个字节的数据*/( Q: ^9 C/ o- b; c( q  T
  67. u8 CAN_SendMsg(u8* data1, u8* data2)
    . `- w" J) Y* m& m( i7 n
  68. { / ~0 ]- U; E% [" V5 j
  69.     u8 mbox;% e& t7 ]- J; U8 ?* t. @
  70.     u16 i=0;
    / `8 |, w2 `- r  g) Q
  71.     CanTxMsg TxMessage;  
    / k! m) }+ u) n9 p
  72. - N* t9 B9 W$ x7 s3 r6 N$ U8 z
  73. / ~- B; q% i5 {4 T
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00& m" t+ t! [1 V
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000  l. d2 }" X; S8 X2 v2 ^8 f& F
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    9 B% e$ c8 Y- I5 `, w% q. F
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧& \( ^4 p/ x1 Q% t5 ]7 f9 k/ J2 ^
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    0 L% w5 A2 s0 @7 B& @: b5 H
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据# `" J, n7 l4 ]  L8 P$ i7 }
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据
    0 u5 p' W1 ]* a: Z: k  e$ L1 ?8 U+ G

  81. 1 V  e* q4 |, f3 h2 X

  82. % j* e/ N) h5 }* e) a% _* i
  83.     //发送数据6 B8 U% {! z5 Q. @3 Y$ E
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  % V. M8 J- Y" K8 i
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    1 w- x6 e3 Q3 T6 q5 F$ a) n
  86.         i++;    //等待发送结束: s  F4 {0 n  {( S7 g& i
  87.     if(i>=0XFFF)
    . S" Y; i0 Z: p2 `! e8 p
  88.         return 0;//发送失败( ^+ Y5 i0 ^0 A" P. d
  89.     return 1;//发送成功 6 N* x( A( N# \. H! ^6 q
  90. }5 ^! g5 W- k. V2 U
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    + x! B1 C* V) a4 r6 N/ O
  92. {
    + O5 z( {0 M: o) F- T9 p+ m* X
  93.     if(Rx_flag == 1)//发现数据% H! I9 L. `8 g' D- n" i( \# {
  94.     {. k9 a% k! O* w; @, r5 ~. K( r
  95.         *msg1=CAN_RX_BUF[0];
    , i! r" ]% C8 q" [: I/ O
  96.         *msg2=CAN_RX_BUF[1];
    8 |/ X6 @/ D5 {0 c/ r% }
  97.         Rx_flag=0;//数据已经取走,可以更新数据, L; s# p1 I" L( S' g1 G
  98.         return 1;
      R0 {& A" U  T# ^' E
  99.     }else
    ! H/ N6 r8 j& z) K# R$ b
  100.         return 0;
    * g7 V9 k  x4 x; U; t1 n, T
  101. }
    + U( u/ b9 C' ^/ T
  102. void Clear_canBuffer(void)- Z* W+ F( T# h. J$ V8 y% G
  103. {% ?; E0 o8 j- v2 N. S1 G0 _
  104.     Rx_flag=0;//清楚接收标志位
    , ]! n- C9 P* K9 k
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    5 `" O3 H9 B* w9 E2 C8 f  M
  106. }
    2 Q" ~1 O7 @% T5 F4 w
  107. u8 Check_canRX(void)
    7 [# G1 O# [8 o- x1 s
  108. {
    - F. Y/ E- {! n% `
  109.     return (Rx_flag == 6);" l2 j! C( \! E9 F/ \
  110. }
复制代码
' D/ N, b. Z% y' o  b& g/ |
can.h文件:
  1. 7 Q7 H# U$ |, [% Y. o9 g* b6 `
  2. #ifndef __CAN_H
    2 c9 M: z. a. {) d
  3. #define __CAN_H
    / x. \2 T/ O' v( y: s+ Z

  4. , x# J3 r7 R* j! `* D" j
  5. , c" q5 o& P7 J7 u/ J3 r( T
  6. #include "sys.h"
    & q' w6 G1 v. x8 G% ~( R1 o- ~
  7. #include "string.h"# V4 [: U& B, X+ j% }
  8. 7 z+ I8 u: t, q! R5 S% v

  9. ) T1 m2 D7 D' g- b" j
  10. #define CAN_RX_LEN          30          //定义最大接收字节数 , k5 e& j6 \& n% ]% T

  11. 3 o& l8 [: ]/ u* i, m- X0 {

  12. " V9 l  a  k9 `9 L+ i1 D
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符   K$ z$ g- Q- U8 e3 H( D4 D" D/ o
  14.   X, S% x2 {+ u0 U

  15. # O% P6 }: t" @4 E# _
  16. void CAN1_Init(void);
    ) A" t* {7 v( H
  17. u8 CAN_SendMsg(u8* data1, u8* data2);
    0 e# |9 T0 p4 V3 D) m
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);, y# Q4 G6 o2 @: V8 b, X
  19. # W( U, w- S" ?* `
  20. 7 M, ~% J7 ?* H; p4 {+ c1 a) }
  21. #endif /* __CAN_H */
复制代码

% S8 F0 T" r& D0 Q9 g
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

相似分享

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