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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧+ |  x* A5 T( b) H" n
  • 摇控帧
    3 P. s3 V; |3 n0 o" G4 }5 O
  • 错误帧
    * t7 i6 {0 ^5 T" K2 H- N: F
  • 过载帧0 b6 ~  A8 s  _$ [/ J0 A% _( Q& b
  • 帧间隔
    8 Z' p. i( J& X5 s
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
. [5 U! ~1 ^& D5 e: H6 v, [7 [; d  G    数据帧一般由7个段构成,即:
+ @8 ?" d5 u# z$ o5 p) h(1) 帧起始。表示数据帧开始的段。
0 ^$ Q4 n8 L; [3 {' @(2) 仲裁段。表示该帧优先级的段。
7 _/ e  [- G- F7 `- p/ R(3) 控制段。表示数据的字节数及保留位的段。4 e! N& ]; X6 s- G
(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
* o) A" K# C% B% V& v(5) CRC段。检查帧的传输错误的段。. p' L* e0 B$ D, j
(6) ACK段。表示确认正常接收的段。# S! f$ O* u( F5 H
(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。: @8 a' I0 z0 G/ ^
    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
    # F9 Y$ ^! a0 C5 F% j8 @" w
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。6 X* w6 Z, h" U
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:. t8 N$ R# |  V* _9 \; q+ M: ^/ R
PERMNQ{)L%G}{986WRA~Q]W.png

  s4 o; z( o. o% |0 @# h7 R
    在程序中就是:
  1. //要过滤的ID高位 ! \8 g" R. |# d" d' F
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  5 |4 A" G( T+ ~& g7 ^
  3. //要过滤的ID低位                 
    * m( }2 L; N" F! v8 q9 s
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    $ w; @2 S0 N+ L
  5. //过滤器屏蔽标识符的高16位值
    " _8 ~, B/ x$ }/ N) Z
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    0 \/ k) b: M9 ?3 ^& X
  7. //过滤器屏蔽标识符的低16位值         
    ( {3 W; \/ B: Y: j8 {  ?
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

4 S. ^8 m$ i0 c% {
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。& F; \& ?* R7 l
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:  a' |4 l& S: ?6 o6 g
主机:0x1314  @& Q& c# y+ N: ]  P
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:

  1. * s1 {  ^3 j5 X% t
  2. #include "can.h"" c6 n/ K0 v% N; w$ u$ [

  3. , W3 a! S2 J. E: U0 R3 {

  4. ' w. ~1 ?& C; R% N6 M: c! A" j2 |
  5. /* 在中断处理函数中返回 */4 m% J8 _, n- z1 A: J1 r
  6. //__IO uint32_t ret = 0;3 |" ?, t/ N7 y+ C) l7 Q! q# z

  7. $ |2 e9 ?  C5 @3 j5 ]

  8. 4 K5 n" Y& f- M7 h
  9. //接收数据缓冲器, f4 w2 P  v' y; c
  10. u8 RxBuf[5];* d, H/ `1 e! K2 N
  11. u8 Rx_flag=0;+ j8 L% E8 m( P6 f1 X
  12. ; ?) m7 h, K9 d$ m

  13. ) y# V' F, w; y2 |5 @. v* [
  14. void CAN1_Init(void)/ s( q) x1 m# R" A- g- H
  15. {/ T- H4 v8 H, Z
  16.     GPIO_InitTypeDef GPIO_InitStructure;   Y* n6 B' D& A0 t9 A  V* E
  17.     NVIC_InitTypeDef NVIC_InitStructure;; I1 r  w6 v* {9 o* `
  18.     CAN_InitTypeDef        CAN_InitStructure;$ _( M; N' b$ Y4 G8 @) H. ^
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;7 h2 @- ^: t$ U- J3 Z  M/ J

  20. % t% S0 F7 U5 H8 X% h
  21. % E" F+ u9 X) v  a3 }  S  U
  22.     /* 复用功能和GPIOB端口时钟使能*/    ( @- g0 W# C' o! n; D$ M. h9 p4 N' D
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      . ^9 `8 Y$ o% Z" n# d

  24. 7 Y8 s& T2 K# B4 e5 E' y8 S6 x

  25.   n+ ?+ ~; O. K
  26.     /* CAN1 模块时钟使能 */& ?; n; x% |$ b/ j. y  G4 g( v
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    9 j* r- e$ T( \8 Y: Y7 S

  28. 9 \1 b( ?. {2 k- h  C
  29. , G' S5 a$ o  A, u4 T3 |& _% c/ c8 d
  30.     /* Configure CAN pin: RX */  // PB8
    8 a! N6 ^1 Q0 O- r# m$ M9 G8 M  Y
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    + }7 z* q! e0 c0 ^( N' ~
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入& q+ K3 s" W  X) O7 U( z9 Q. N' @; g
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);2 B4 Q: O' N9 `. y

  34. 2 U$ T  j5 N1 h1 y  [! s
  35. # h: a7 A: u! X# y% o6 t: z: r
  36.     /* Configure CAN pin: TX */   // PB98 X# F6 ~9 i' @
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;" D- i: x$ h% B- U
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出0 I; y: B! m6 l( B4 U
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);3 G$ y9 ?  j' J2 T

  40. ; a% ?6 R3 M' ]! S" X' p7 f, j+ |

  41. 3 H$ l. A' M, t- T6 K6 H: v8 W; C) H7 |
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    , R8 m7 j# h' i* h9 i
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);- b% C1 K, }4 {6 X
  44. ' [( i+ \6 Q0 g2 k2 b
  45. " B. D# N! l! o1 ?7 K1 b
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   + v# `, W, Q7 s$ I
  47.     /* Configure the NVIC Preemption Priority Bits */  
    # q. {+ o8 }, Z* \' `6 R4 ]+ D
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);+ Z  Y7 O# D# C& x1 v4 a

  49. & Z3 G# x. ?/ S+ _

  50. ! c- h  E: G5 N$ }  _6 h  j. b
  51.     #ifdef  VECT_TAB_RAM  
    2 }' x/ {( ]; @8 K, W
  52.       /* Set the Vector Table base location at 0x20000000 */ " {* U6 _2 d' b' G9 c
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    ; y6 |; S# b, f0 ?5 [/ L  |
  54.     #else  /* VECT_TAB_FLASH  */
    * o1 s5 Y7 g1 |9 k+ P
  55.       /* Set the Vector Table base location at 0x08000000 */
    ) j8 u5 X1 A, m. h7 l4 F* `0 X
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    # z& v4 U  b: P! w
  57.     #endif
    ) n2 b* ?# c1 e) k: R: |( N

  58. " p9 h  }8 q+ J8 p8 P. Z0 p# u

  59. # b  |) o! }6 d6 K: v: D/ [
  60.     /* enabling interrupt */- `4 @5 J3 ]4 ?" m
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;6 R' [, O4 \) ]' _  i1 \( V% P- x
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    1 O( C! _2 _! j3 Q! |2 s8 o
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;8 v* a  M  n0 O8 G7 ]) U, v  j/ E' t
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    / z/ g( @* l# o9 N. _( @$ ?1 R
  65.     NVIC_Init(&NVIC_InitStructure);4 z" a% w7 {+ G4 v! b
  66. % o; q1 v- w$ L7 ^% u

  67. ) Y4 y1 L' C& M# A
  68.     //CAN_INIT();//CA初始化N模块
    7 E* {% \) m: d  W: Y, `
  69.     /* CAN register init */& O. \' W( ^7 b% n/ D% u4 b' Y* f4 F
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
    9 h0 s8 G7 I$ ?) T' A
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    3 Y3 G9 E* p9 N1 I) D& z' o( j) H" g9 p

  72. # m; Y! p+ [/ ~+ q5 @7 J

  73. ) B0 `2 f# E' x! _6 j& P5 P; V
  74.     /* CAN cell init */; g: K$ h" i# L; H$ ?( @; h
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    ( u) d$ R4 S- i5 _. u9 z
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理  s# u  Q: |! X
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    5 ^/ _: I$ _1 T
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    ' E* ~  g1 k9 ~/ ~3 `7 D
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式* ~$ E7 K, k/ v: F& x! s
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    " a/ d# T+ e1 ~5 ^& F7 u
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    8 o; h2 l& U, h3 I7 P! u$ S% z! `$ {
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    9 I+ ?4 b9 M" x9 |: w
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位- z( W. L7 u3 y) p% j1 w
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位
    - a: Z5 M# B$ n7 }: H* B
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60 ( c1 m: I* ?' @1 t
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs) P6 _/ p; j0 z, }7 `& X
  87. ; M0 J  R' C  ^
  88. # m! v$ l% K: E; Y
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据- t, c) i! }; [% e3 r
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1$ ~+ R2 q' s8 D
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    " n5 h) x: s3 l# A, }* ?
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位! q3 Q; P: D2 _9 s
  93. ! t6 [+ f$ y+ r. f4 }
  94. $ T8 f3 L, j- i) Z  E! |6 w
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    * S  I4 `( e9 s: K# s% v
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位 9 o" s, B. n5 A! D7 E+ U$ F
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    6 m& D  ~/ \* z3 \7 C; \, Y

  98. + o) t8 g* g/ P4 k, @

  99. 1 i* i6 ~, x7 c8 q' J
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    : w$ g2 o1 }" D* I/ ]' ?8 C
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    . f7 ~/ R/ q" o, }! ?7 O2 R
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    + V9 ~: V# k. y" b
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器2 X# l$ V' x* p
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    " n8 F( z. |0 J- Q; O  C3 Q0 [

  105. 6 V6 D; n7 X, R& ~: ~- f2 [0 q
  106. 6 C- ?, Z: I  H+ h7 m# A6 y  i
  107.     /* CAN FIFO0 message pending interrupt enable */ ' ?% G& i2 G/ b* |; _1 B. E+ {
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断5 h/ C7 @- |4 K- c
  109. }: e# o' A. U- v* L
  110. 5 ?4 G# o: g( ]3 k3 g

  111. 4 J7 j6 u8 g2 y3 ^# g, Z
  112. /* 发送两个字节的数据*/
    1 |7 A. m/ ~$ ?8 \* b6 g% ]& ~
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)( l( `) s8 \1 Z  N- f/ ~
  114. {
    3 m2 h- E6 ^; ?! v- B8 O! I
  115.     u8 mbox;
    0 H2 c8 `- P5 b0 H0 B7 ^5 B; E- k' q
  116.     u16 i=0;
    - @( _9 L) E$ q  B. g& Y# z- d
  117.     CanTxMsg TxMessage;  
    ; E8 b" X! t, W6 w( X

  118. / U( p0 h/ P! j  y
  119. ' N+ j  m. N: ]* v4 ^6 z: R
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    $ ]# @/ P3 T; _. V4 s) v
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机/ }( U" t& N- N) Q# S6 H% i- ~
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    9 D- `8 ]% K) l( W: o3 o
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧- O6 N, T+ Q4 g
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    3 U  U. D' g9 r& W# K* j$ `
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据( N/ b: e0 `' [. l1 o6 M
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据
    / W# q& z& g7 o0 l' {5 Z
  127. # ~( f3 G) Z: R5 L

  128.   \# V5 x, ?' {. {, s0 p9 Q# n
  129.     //发送数据
    5 e4 ~& ?! U( ?9 R: \; Q4 C9 o
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    : j& M2 q! J; V& q% ~" u7 E
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    $ K8 x# z$ j# X; j' w6 \
  132.         i++;    //等待发送结束# G. q; t' D6 \% y3 ]  F0 V! h4 F
  133.     if(i>=0XFFF)
    ) ~: {+ g9 p5 M& A
  134.         return 0;
    8 P8 f: U) e- y5 O
  135.     return 1;
    ( H( K4 e5 n: y1 Z, G9 t
  136. }
    6 I* t) F& r5 i; ?
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    ! g% B# ?, n! j8 P+ b( r- S0 U
  138. {
    0 n6 E$ }/ W9 M3 b% C/ j
  139.     if(Rx_flag == 1)//发现数据9 ?* Q, G5 l. U& O' s% m
  140.     {
    8 c- b/ p; C( n) q0 P% X
  141.         *msg1=RxBuf[0];
    9 c7 p' F9 E- I
  142.         *msg2=RxBuf[1];% n3 H3 R6 G8 u
  143.         Rx_flag=0;//数据已经取走,可以更新数据
    # e, O  a7 h$ H4 _
  144.         return 1;/ H7 Q5 ~9 t$ ^6 F6 t
  145.     }else1 F9 d. ]5 e( b* ]
  146.         return 0;
    ( q) Z: `6 a. J( c) U1 V4 e
  147. }4 b% Q7 W& I- T
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    ' o. m) W* v/ o+ S! s) W; k& I' j
  149. void USB_LP_CAN1_RX0_IRQHandler(void)
    , b* G1 A  t. \* h& l8 N  \: o
  150. {
    4 u+ A$ V+ F, J/ C0 U
  151. 5 r4 W2 M3 V1 V- `  W7 M
  152. 1 c& ]( m+ P5 k9 I, D6 B
  153.   CanRxMsg RxMessage;
    * T# a6 q* S+ G- r: A7 \$ K  G! [* S

  154. 5 c/ o7 t* P: d: ]; b
  155. # N1 r. Q- `- m3 y% E" q5 J5 s
  156.   RxMessage.StdId=0x00;" g' [2 r% Z3 }7 \$ {$ q3 J
  157.   RxMessage.ExtId=0x00;
    5 w2 C" I& J3 L, Q
  158.   RxMessage.IDE=0;
    . h% h' q# ^1 [( q6 T
  159.   RxMessage.DLC=0;' x9 i% ~9 U1 X
  160.   RxMessage.FMI=0;
    0 \, w- ^( H' e
  161.   RxMessage.Data[0]=0x00;
    & Q5 V9 _; t; N/ u* o9 ]
  162.   RxMessage.Data[1]=0x00;    3 L6 b2 ~* f) y2 {% Q* D3 f

  163. 4 h1 c9 `" P: o
  164. " e+ j, Q- d$ N$ h
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  ! N  H- T3 t8 y; s' |0 i  W3 }

  166. ! h7 g, h- W! ^

  167. 2 Y, @& J7 w2 h) V, N. i5 _2 c
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    / |0 Z+ D4 d3 [$ K! D! N" H
  169.     {+ l8 n( Y2 B- T: F# ]; ~
  170.         RxBuf[0]=RxMessage.Data[0];  o8 T% \2 |* C
  171.         RxBuf[1]=RxMessage.Data[1];0 r. d, S5 ]& R6 R& W
  172.         Rx_flag=1;//数据已经备好,等待取走
    . ]. l( b% p) s  q3 i* \
  173.     }& f3 U/ I) L4 c7 w* W: P
  174. 3 y) x/ `( A, t7 r3 S
  175. $ N2 A$ a2 C' h: N
  176. }
复制代码
; O) V1 t: V0 P
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
7 {, H% ^/ K& h" ecan.c文件:

  1. : N7 v1 u! }, l5 s3 p5 z  q7 c& e
  2. #include "can.h"- m  c8 j  S4 a+ x- ]. ^

  3. ! }$ M2 z: T6 ^9 J$ z) x8 X

  4. 0 b: }, ~5 y1 q7 I4 V
  5. /* 在中断处理函数中返回 */
    ' l; y: Z  j( ?8 j- T
  6. //__IO uint32_t ret = 0;8 D" x2 Y5 [2 N) ^: a

  7. 2 C/ Z0 H5 L; n$ A1 Z! K

  8. # Z) @; z7 P* e' R2 [2 k
  9. void CAN1_Init(void)$ \) z2 G( e: M
  10. {! l9 f7 n" `3 B! X+ @# g3 W
  11.     ......//以上与从机部分相同
    8 U& N' k. J; L# \2 [, A
  12. . I( w  g0 J0 J  ]1 r( l9 V
  13. 0 |) P' P% N; x! R+ d6 _3 J- R# K
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    8 O, @* n% J3 h
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1, j& r$ J; p1 i# e' M' i
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式1 i9 X( P1 S9 k4 q$ W( B. j. N
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位% A5 F; |) \! u  R
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值' X0 [2 X3 |1 e3 e
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    ) V. V" E+ q3 }+ u* j) e* O' b
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值2 {% u7 K+ R" j* N; P
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    . b& X+ w. C# n( e- `" ~
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    : C) z' ^$ t) M$ W- w/ y6 d+ W2 i
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    5 s- O5 q. s  [7 o1 A9 M( l" X
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    ' _# T5 b  h1 \$ W

  25. - M! m6 {  s7 P) L% N
  26. 7 s3 t$ E" Q  t' L; H7 E
  27.     /* CAN FIFO0 message pending interrupt enable */
    ! c. q( q3 ^; Z! {2 S2 Z- I
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断* _6 W( E6 D6 a, S4 @9 S/ E
  29. }
    4 u8 r1 x& P+ m# C" S
  30.   H/ c% [8 `* _, Q

  31. / E" A- E2 r" q8 _
  32. //接收数据缓冲器# d  h6 y3 L& d! O- k# |# k
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    ) F& l" ]2 C& ]" V0 G8 ^- E
  34. //接收标志位  ?/ e* W1 T: o- e* R# q
  35. u8 Rx_flag=0;; s1 d! d. b; |# l# R
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    0 U  k7 Q- h0 @9 x0 d
  37. void USB_LP_CAN1_RX0_IRQHandler(void)
    ! P( V/ c" r2 k# F+ G! {- s
  38. {) c- \. ?' [& a& ?/ J) T
  39.     u8 i=0;
    * L& {+ ^( d( S; g: ]
  40.     CanRxMsg RxMessage;+ V8 D, C/ U4 I+ s9 T  m

  41. 2 z$ I- Q/ N* m, H. T
  42. 7 J: A6 X3 N$ D! G, M; T
  43.     RxMessage.StdId=0x00;
    $ o4 F$ Z+ {! }+ l% {. F. o! H
  44.     RxMessage.ExtId=0x00;
    5 C; ~2 k* y4 `5 k8 \8 w$ }( n
  45.     RxMessage.IDE=0;6 [6 d: f- C7 i7 n
  46.     RxMessage.DLC=0;6 E0 M7 K4 n& ]8 G* @9 Z* W+ Y
  47.     RxMessage.FMI=0;
    & V7 C9 `/ \! D; k* m( v

  48. ( U; c* K2 N- u( u! L
  49. 8 t7 N- O9 ^5 j1 Y( I; O! @
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  % E9 v/ t8 Z6 `# @6 ~
  51. $ j- W0 C% k; |- _5 H
  52. 4 l9 F5 ]) r8 \  o; `5 R* h
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空
    ' Z* n: [/ c' o9 a
  54.     {, ~: c) g  y, p2 `1 ]2 k/ W0 W
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据; B* g/ l1 }* e. R7 Z
  56.         {
    " z/ E  s1 l9 g* j" d1 m
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];8 @* Z: i4 y% s0 `
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    1 D5 u2 f3 X* K
  59.         }
    # F' H) U1 E7 E6 e4 y4 W: V/ _, A$ d4 T
  60.     }3 C+ \2 j/ p% C; j, ?, G/ P1 y
  61. 8 `: u3 c+ d1 V! P

  62. " I+ u0 W% E5 r$ q2 R/ d: O
  63. }
    $ Q4 b: \) I( x2 c& O. I0 ?* q
  64.   O/ U9 L/ n9 w9 d. e
  65. , h6 m3 o& X* W5 M& D7 I& u
  66. /* 发送两个字节的数据*/
    3 q5 Z. K4 d* p+ X9 E& T8 v7 J
  67. u8 CAN_SendMsg(u8* data1, u8* data2)' h7 k3 V( p* a
  68. {
    ( _3 F7 V1 \9 B
  69.     u8 mbox;/ y( p# N6 t* m9 D/ J) y
  70.     u16 i=0;
    # A1 e% _3 M2 I) c* p, K) B
  71.     CanTxMsg TxMessage;  
    7 k, M# N" u# x' Q. D- x7 R
  72.   \+ k+ F. i/ n- ?% f7 r% c9 s

  73. ! \+ \2 k1 T6 Q7 ~. y
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    " Q8 S* ]3 X/ j9 j+ A9 D) @6 Z
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    ) ?4 M. g% _+ V' o
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符4 T2 p6 u& E. f* K+ ?$ X; n
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    0 P1 o& p  B) D! o. K# v4 x3 z5 p2 i
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    ! Y0 {+ t& D7 m4 c/ @" E  x. I
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据
    0 p' H1 ]3 I1 c: J/ U+ K" j* l/ n
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据 & |0 D7 e& D! r- g, @: V- v' U

  81. - z; t  q6 ^( s6 p! j
  82. * E4 `! h# r2 n& G) a- r
  83.     //发送数据$ _9 Q  t( M6 {- C
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    5 v6 _# C8 L* p# I) @
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    2 b5 b5 V! M1 S! K
  86.         i++;    //等待发送结束  Z: ~1 l- V. R- y1 z3 y% p* g3 s
  87.     if(i>=0XFFF)
    % u: {: a5 c; A& G2 r2 s( R
  88.         return 0;//发送失败8 b' D6 j& h6 A1 R
  89.     return 1;//发送成功
    7 h1 H/ ?9 N8 ]0 t0 }! T
  90. }- O9 M0 o$ e4 F" }
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)5 x" K$ N0 T! O$ e3 Z0 Q
  92. {1 N( @* z3 Q; t" v# R# f! m
  93.     if(Rx_flag == 1)//发现数据
    3 @. D/ k' i+ _: u6 E# ?
  94.     {" C! K: S7 A4 m+ l+ H
  95.         *msg1=CAN_RX_BUF[0];6 `9 W0 v+ g) _6 \' }0 Z9 T$ s4 m
  96.         *msg2=CAN_RX_BUF[1];
    8 A& {- j( j$ r/ w
  97.         Rx_flag=0;//数据已经取走,可以更新数据
    + ]  ?9 @5 p' }+ _& x
  98.         return 1;
    . @, b4 E/ H: M1 d& A
  99.     }else
    / ~7 P  J2 n6 v3 b+ l) u' T
  100.         return 0;, p( ?7 A8 X' E7 ?* J* I* \) Q) l
  101. }/ n  h; ]% |5 U" M% m
  102. void Clear_canBuffer(void), q9 `0 L) t+ D6 ?$ K  V
  103. {
    2 `1 Z9 @; K7 k  H# t' f
  104.     Rx_flag=0;//清楚接收标志位) T% ~1 a3 ~1 ~4 j# L, E
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
    ) h& s) E% r' |1 R
  106. }6 Q: y9 b2 b6 S
  107. u8 Check_canRX(void)0 G% M& [' {5 Z% U- a' c+ B; ^
  108. {, K' m: f$ A. }
  109.     return (Rx_flag == 6);
    / h8 @' G2 S5 ^5 w. I. V& I
  110. }
复制代码
! s: ~+ z' x/ t, z
can.h文件:

  1. . U! G9 e- |) D5 R* N
  2. #ifndef __CAN_H
    * D1 r( x# v# C' n* R3 |$ }
  3. #define __CAN_H7 h/ B1 }1 O; {! b- s" f' t6 ?

  4. 7 @# }+ s* M. |1 q' m

  5. : i- T* f- g/ _) z# d
  6. #include "sys.h"! Q# q$ Z6 r! G' Z5 m. u
  7. #include "string.h"
    $ ^/ A( z% U: r6 U# A3 w

  8. / p# W$ v# ?, p7 U
  9. & n" h! ^1 _6 ~% ]5 w- _9 {
  10. #define CAN_RX_LEN          30          //定义最大接收字节数 * A. F; l9 h! Y3 v

  11. " m: x# `6 f- C4 y8 S5 M  G. ?/ p- P; f
  12. ) f! |7 F# A6 A
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    ) D; m9 p" U. G: o/ K9 A
  14. ( M6 x+ h& N: h1 ?, y

  15. + d5 o; O* U% N7 U
  16. void CAN1_Init(void);
    " v, C; m+ L' Z
  17. u8 CAN_SendMsg(u8* data1, u8* data2);
    4 {  B( {/ Z1 Z. l
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);' _1 f' ~5 R# y
  19. ; _7 o  C! B' O# l, u- {
  20. % J7 d2 F2 y; E3 ^  v; l
  21. #endif /* __CAN_H */
复制代码

- U  o' d+ X7 X8 j7 [# W7 L4 R
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

相似分享

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