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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧
    . g5 f' Z! p7 y
  • 摇控帧% g3 E% A  |% T5 ]2 _
  • 错误帧
    ( H5 b1 Y; S/ _
  • 过载帧
    ) R" J9 d( k+ ]+ }0 a* ?
  • 帧间隔
    " S: P4 ~/ o6 j0 U5 R( f1 s
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。! ~% y3 |6 Y5 h( K* q* e
    数据帧一般由7个段构成,即:
/ o+ I' g5 E% w. v( N& F  H8 n(1) 帧起始。表示数据帧开始的段。: B& M9 N9 G& m9 q9 H( ~
(2) 仲裁段。表示该帧优先级的段。' I& n* I7 |- L6 l- a
(3) 控制段。表示数据的字节数及保留位的段。
4 H9 h& r+ ]9 [$ _(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
4 `( K: p6 n$ y: f(5) CRC段。检查帧的传输错误的段。7 \3 k, j0 v9 ]; N4 v0 Q
(6) ACK段。表示确认正常接收的段。2 ^' |% h, M9 u3 ]: ^- o$ W
(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
5 h+ @8 o% q- f$ q& O$ l1 j4 K7 t8 N    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

    * h! g) D2 F" A* ]
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。* i- e& e' l2 `: r' J2 e
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
8 A7 Y, G" V$ J5 R# W
PERMNQ{)L%G}{986WRA~Q]W.png
& L) e! G: c( U
    在程序中就是:
  1. //要过滤的ID高位 : y2 Q% S( _, w- `2 F+ x! C- [+ ~4 E
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    : U: O, Z; @* V+ [9 _4 ^5 Q: \
  3. //要过滤的ID低位                 
    4 R, h( D# M. g
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; 0 ]( d& L, y) E3 _$ e& C2 {
  5. //过滤器屏蔽标识符的高16位值
    ) X* ~2 ?! r! z& d
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   $ l* ]. f. K7 h, J
  7. //过滤器屏蔽标识符的低16位值         
    ; {( ]6 h7 b1 ?' o$ G1 ^
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

$ e* k& u9 u& [! |. D
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。; q8 S& n9 r3 n6 D
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
( I- L# E4 W5 L7 }3 Q+ P( R主机:0x1314
% B- j8 n+ u: j5 }5 h, ^! E1 L从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:

  1. ( S. ~* C" R: R
  2. #include "can.h"
    & k; T' p: _: I% j
  3. ; l' Z4 q# D. G# [( S
  4. + \7 O4 C9 Z# ^# ?: y8 S
  5. /* 在中断处理函数中返回 */
    8 |* e3 a9 J& D% ]
  6. //__IO uint32_t ret = 0;6 C. G2 B! ?+ }3 D

  7. & u6 O& L. T, X! s  S$ v

  8. 9 w1 [& R, e$ g5 p# Y. d3 w
  9. //接收数据缓冲器/ r( [8 F- T: F3 R& O
  10. u8 RxBuf[5];6 [3 e* |6 x. @
  11. u8 Rx_flag=0;" l$ `% C3 y% U! ^: z% `
  12. $ T6 {7 U" ?( H' T8 w
  13. 0 ?$ ~1 g$ @& C+ n
  14. void CAN1_Init(void)6 Z0 o& Y7 C3 V3 R2 M- m
  15. {
    / g' r1 i. r) A' F/ T6 b  p% a
  16.     GPIO_InitTypeDef GPIO_InitStructure; 7 U+ q* e# K" N" Z( r
  17.     NVIC_InitTypeDef NVIC_InitStructure;
    5 E2 T5 y$ `, b8 j- L
  18.     CAN_InitTypeDef        CAN_InitStructure;
    2 e+ ?& R9 t" y
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    % n9 n: k% v; c. i

  20. " l+ A8 \- V9 f

  21. 9 H- l. q, H8 G3 E. ?( m4 m, j4 _6 m7 i
  22.     /* 复用功能和GPIOB端口时钟使能*/   
    ( I$ V$ D5 E+ Z  L; f
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     
      O( ?0 |5 ?! Q, w5 W

  24. + n" ?6 S8 r6 e9 g" a, E
  25. 9 C  d# l. H" \; p9 p: e
  26.     /* CAN1 模块时钟使能 *// s0 X, J" g& U  g
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    1 h# v/ @1 }% R6 x" ?' X6 ^
  28. ; Q* h1 N$ C, Q  F/ A2 Z5 o

  29. & y, f; }% E$ o. H7 O/ |) i
  30.     /* Configure CAN pin: RX */  // PB8  e$ K0 G$ L, b1 e9 m$ b
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    ' I; n" n( D, {! v- t& V  q
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入
    9 Y9 Y* e9 @2 K( ?. M$ @
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);0 o# _, G1 S% D; |, h3 N$ R, m

  34. 9 Q4 W$ P9 B3 W3 ~' l5 e- R: b

  35. 3 {  W' |" s% J3 m
  36.     /* Configure CAN pin: TX */   // PB9
    : \. T( }1 U) L# s. x7 ?$ o
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    9 ~& K8 i8 u0 i7 ]* G+ y
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出* w6 i, h- j# O) G  O6 s1 |
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);, L5 ^% j5 D5 u* M
  40. ' v; O: N9 }9 d6 V9 W6 U) h

  41. : I( l$ e' z2 A; T4 s7 U
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O5 c' o/ Z5 p2 F: T
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    9 ^' j9 B* W1 d! E) M

  44. ' m) ]7 j$ [$ }. P3 R

  45. , I. t1 J- H9 j, E) y, J+ d
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    ( t2 S: w% k" ]- W/ u
  47.     /* Configure the NVIC Preemption Priority Bits */  , n* }+ `. M, P, U( b
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);2 o/ e0 ^7 g: o/ Q; P1 ~
  49.   ~8 _, a0 X3 b1 O$ e& k- i3 q6 [
  50. * X" p" O3 w% u% b- G( d8 |
  51.     #ifdef  VECT_TAB_RAM  . E7 f- e5 c5 h7 S2 U" p5 F
  52.       /* Set the Vector Table base location at 0x20000000 */
    6 P6 w! {2 z4 N: a+ ~5 R" g
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    / E% ]5 x1 e/ i6 m# q
  54.     #else  /* VECT_TAB_FLASH  */
    / s2 h  j7 C. ]! k+ r; F
  55.       /* Set the Vector Table base location at 0x08000000 */ + N( x; k; Q+ S7 `6 l+ P5 Q& i
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    $ a  K9 c1 d, i# Y  G, G- G
  57.     #endif+ i: [" f* O& Y; f. B" A

  58.   c( u- ?: g/ e& u. f2 B  D

  59. 0 j7 ~. ]' U9 }  l( v4 H# a/ m# H
  60.     /* enabling interrupt */& m! ^! r* E2 t! W
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;" d( Y* f. X8 K- u1 j
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;1 N. b- L( X/ b
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;& S, C' j! }) K5 x" F% Q8 g
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;9 D: j1 b7 W6 N5 S
  65.     NVIC_Init(&NVIC_InitStructure);& z; F, O) y1 K

  66. ) x1 e5 Q7 k+ h/ ]

  67. 1 {- g" R0 d2 ~) }! W; L8 U& s
  68.     //CAN_INIT();//CA初始化N模块 8 p! `1 o' b; a( t, R
  69.     /* CAN register init */: w4 ]9 K) q% U5 J7 Z
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值
    7 p; Q( u( F9 }8 X$ ~: V5 S! \
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入/ @7 |, O+ t- V- o) C

  72. + _7 N7 J& {1 D6 h! l0 C
  73. 6 U! v1 F( V$ N7 {
  74.     /* CAN cell init */
    ' _: z, p! B6 n0 B- v) j
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式  Q4 P2 C! S  |# L7 W+ Y, C6 U
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理0 E" a7 ^' C0 @+ g  b
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式" I( N* K% E) v. p0 p9 h
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式  g$ Q; \4 }# Y( ]3 R  D' P
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式2 e7 O& C* X& E! b
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    9 G: d1 }3 d. \. u! ]1 `$ b
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    # A2 T* z+ ?, N5 @0 P/ E6 D$ b
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位" H2 `; n: v( M: k" d
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    / k7 J/ _, `+ g9 C
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位4 }; `; p' N5 ?# ]% M
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60 & g& L7 J7 i6 n8 x/ h% @* ]! m
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs. [2 k; p8 ^2 n9 Y8 B- e4 |
  87. 0 p- j. e  l  J% X! w9 j  x+ H8 ~

  88. 6 E' [9 O$ a0 E1 K$ g
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据2 L& _9 F3 R7 C" W' i7 j
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为18 d+ v6 m" c- Z- Z5 g# v. o3 `
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式9 S7 k& H( ^! @5 q8 B0 g
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位1 B9 L9 N4 Z2 F5 L; J4 k: r

  93. 2 f7 {" b4 s$ n  X) }" V& Z  e' U: W
  94. / v$ k% ?/ E- z* a
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  
    % G" N5 ~# _+ p
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    8 F0 J7 Z# Q8 R2 o
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    . O5 R( H& z& B3 t6 }, ?
  98. ) [' _: \! j2 Q) i1 }
  99. 6 ]. t# S2 c. t  @' ]
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值$ W$ ], X9 ^9 H6 ?$ z
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值
    ' H- L5 e$ A* o" H7 p2 b6 Y
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    & O( C# L9 p, G5 V4 s/ W2 j
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    1 f# f4 A, ?' f* D* c
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
      [( m& _! ]( C( Q3 Y2 O. U

  105. # ?5 X/ j/ z) T. w* Q
  106. 6 H; ?& Z! r- c4 i
  107.     /* CAN FIFO0 message pending interrupt enable */ 0 W+ G7 C! y7 I8 Z# m/ h4 h8 d
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断( A9 A" O8 L- w: F
  109. }
    / \; k8 y( q  H/ \

  110. 9 m' `/ N6 ?6 _

  111. # m  ?# q4 a& X3 @# C. s; U
  112. /* 发送两个字节的数据*/
    9 V! P# W/ Q5 S$ K
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)# D7 d1 h6 G4 W6 J0 v! _
  114. {
    % c* p0 K4 _9 t) ^: f7 z/ E: K, V
  115.     u8 mbox;
    + O1 S, T% D& ]! f0 V9 W
  116.     u16 i=0;
    $ v/ |7 M, [2 I, a, H  V0 C
  117.     CanTxMsg TxMessage;  - h8 U" I0 p2 c& B) v' ?) E, u

  118.   [, X7 {  S( B

  119. & S6 \- J( y* u8 r  r; T, P
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00
      `2 z$ Y5 W4 y2 @% B$ E
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    . _% C" V- s8 C; U! q
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    6 {1 e+ t7 T7 u$ x# k
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧2 C; f4 \# i0 w/ Z4 h* Q
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    * P) A) a; r1 c, U( g  f9 g+ ]
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据( o0 A6 ^/ q+ k, Q
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据
    2 Y% N/ N( F+ L: V2 n3 Y

  127. ! J' h5 @+ e( ]- `
  128. 3 `! o' @" }5 n' D6 |  D; H. B  c
  129.     //发送数据
    2 {6 n9 p, J7 D
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    8 A5 k; G2 z5 k9 \/ p) m; m, W! a
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))6 R& B/ w4 O" f9 S6 a
  132.         i++;    //等待发送结束
    & o7 f/ [+ F4 [$ L
  133.     if(i>=0XFFF)
    ( S: K2 c- Q# D/ ]
  134.         return 0;8 D6 U( W% n0 C- X$ n% I! t* p5 |
  135.     return 1;
    # z( l+ }2 d& Z3 {6 [
  136. }# u& t) M1 k+ W* r3 b$ q/ _
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)3 y) b4 L; A: p3 o! B6 g
  138. {
    * A! G, R% A( ?+ ~
  139.     if(Rx_flag == 1)//发现数据
    4 x1 ~: f/ g0 K7 ?2 |- ?! U
  140.     {
    7 O* H0 m1 A2 [# V# I
  141.         *msg1=RxBuf[0];
    ' }" t4 \9 F4 u- X' Q
  142.         *msg2=RxBuf[1];6 L3 O. R; D: S% p3 E
  143.         Rx_flag=0;//数据已经取走,可以更新数据' ?5 P& a1 J0 `! l' P6 r  w
  144.         return 1;
    4 {7 E1 v6 [* G- c- ]1 U9 u( w
  145.     }else
    ; C# {2 u7 ]8 t% r3 {) B1 O
  146.         return 0;& K) G7 L* w+ Q3 V& \, s  m
  147. }
    0 D  T- A: K8 c  f$ ]" i3 E
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */5 l, t9 \: Z! W! \
  149. void USB_LP_CAN1_RX0_IRQHandler(void)
    + I1 R1 A2 v8 i
  150. {
    " ~1 p3 p+ d- H" x# z6 Y$ X! \. g* M
  151. & D8 ?- _, P; V( B9 H

  152. % {4 d5 \: B; @8 M+ V* C1 _/ ?, u
  153.   CanRxMsg RxMessage;4 C# g, g0 X( `) }! ?. m& V4 {
  154. . u0 {) S- ~" h# V

  155. $ M+ x; K3 j) Y5 }
  156.   RxMessage.StdId=0x00;
    + c5 i- W1 H( q  y% j4 t
  157.   RxMessage.ExtId=0x00;' o/ Y: {% S/ }0 [
  158.   RxMessage.IDE=0;, \! Y  `2 F! ^* {+ s7 O2 J
  159.   RxMessage.DLC=0;  w% k4 }" @( g, k
  160.   RxMessage.FMI=0;
    8 p9 Z$ q" Z! y$ O$ e& d
  161.   RxMessage.Data[0]=0x00;  [8 l8 \( _6 M# z" J
  162.   RxMessage.Data[1]=0x00;   
    1 V' r* U5 B. I$ g) _  A) r
  163. ! u5 i+ ?8 u) ~; M
  164. 8 u. t$ m5 j+ t+ z: I
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  # @, N* r6 s8 y8 @3 M- e5 ^

  166. 2 |  P2 t3 t  T; E0 e9 K) V- }& }
  167. 6 L+ C) w7 c( d. r. o& M
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    ) w6 _2 p- X! O9 l. f/ c; Z- {
  169.     {
    " `% A# ^' F, G3 f. S8 G" K7 W
  170.         RxBuf[0]=RxMessage.Data[0];- O  v0 i' h1 j
  171.         RxBuf[1]=RxMessage.Data[1];. y# R5 @7 p9 n& H' q
  172.         Rx_flag=1;//数据已经备好,等待取走
    % C+ `0 Y8 w+ u$ b
  173.     }: x+ s2 @" i# B% @! {) \
  174. # q* G+ o7 I0 w0 U/ g# e* P/ t' w
  175. 3 O* S8 r% }. i7 g+ E
  176. }
复制代码

- y2 `/ b( S) Y
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
% T! j( Q5 t( q6 }) B7 L' wcan.c文件:
  1. 9 i$ L1 Z. q# [( n! U4 Z; c0 B
  2. #include "can.h"5 Y/ T" K, r1 H; w$ X
  3. 2 _2 A; P) G; \  Y# j' b
  4. ; }- ]5 D) p$ B0 @6 t- v0 b- P
  5. /* 在中断处理函数中返回 */* {" O8 M' q: i" Y' A
  6. //__IO uint32_t ret = 0;3 B; a) k: j2 |4 R8 T) z/ t

  7. 3 D9 B' w% ^, _' s, h

  8. , i8 C+ _- V2 t/ X9 R
  9. void CAN1_Init(void)
      U$ n+ r6 M4 V1 t! S  H
  10. {) ^! t& C0 |% Z& p$ Y2 i( u( w
  11.     ......//以上与从机部分相同
      f& l' m  c6 ]( H+ |3 x0 i4 z
  12. 1 N2 I* ^! I( v6 g
  13. . B, j+ x9 l9 m# }- A3 `4 Q
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号/ ?# B: M; P7 ?# C0 f2 j
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    3 e  q) J4 i( d# N0 ~4 h
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    * j# J) B! Q0 \5 |
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位, b9 Z5 h# K  Z2 P3 ?
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值# K5 z% h; Y8 i, P# S# G' a
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    4 `8 `3 y4 [3 g- O& z% ]
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值" ~6 R, p( g" b  m8 W% d2 j
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值- f" `4 q7 h, s! H! e0 R( |+ P
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0' O+ o! e* a) i
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器/ A) g& K' g! G" H% b$ K
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器0 v" Q! ~4 g+ ?! `  F9 }# U

  25. " P, X: X7 o# H
  26. + r, j: W% Z6 u) W) n9 J3 D  q
  27.     /* CAN FIFO0 message pending interrupt enable */
    * r% `. _& O. r7 h. j% Y, J1 y
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断+ Z9 ~8 s+ Z* ~& J/ N
  29. }
    : n. U, L7 z0 A. [, o

  30. / X1 i! e1 i/ }) Z1 u
  31. . l$ P6 ?1 y7 T
  32. //接收数据缓冲器2 a3 r* w8 [( G' |8 k5 T- |+ j
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.: `4 v" d2 m, Q! Y$ ?' `& S
  34. //接收标志位. T$ O& ?7 c4 ]- u5 v7 E$ p
  35. u8 Rx_flag=0;% z% `; U( S$ j4 P: {9 J  u
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */9 n/ ^; i6 @: X! h6 B2 j
  37. void USB_LP_CAN1_RX0_IRQHandler(void)/ t4 n! j% d8 |) v6 W5 t8 }
  38. {/ t7 ^9 M9 p; z0 w( g4 ~9 D* j
  39.     u8 i=0;4 k9 [- _* ~5 K& P
  40.     CanRxMsg RxMessage;
    " b8 J, ?) ~' R$ X& u

  41. , V9 U7 N( Q2 I) @* @

  42. / l! f) z- p& l0 ]: ^: ~
  43.     RxMessage.StdId=0x00;
    ; Q/ J& i0 h4 K+ n: P
  44.     RxMessage.ExtId=0x00;
    8 W, u4 v7 S" U1 q4 R/ l  A7 h
  45.     RxMessage.IDE=0;5 l2 N6 i* ]. e2 ?$ O/ E
  46.     RxMessage.DLC=0;$ @- B2 r4 H' U- ?! M8 g) j3 S
  47.     RxMessage.FMI=0;$ j4 m# S8 O4 W8 ?, p( ?
  48. ; D; J* j$ D# ^( X2 M4 p: H7 y  r

  49. 6 ?6 r3 S8 Y0 n* t) G" Z- y5 o1 m  a
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  ' e( F$ U- r9 r6 x  n6 c# \( D9 R

  51. % Z- p7 @1 P3 ~: r
  52. - N) U8 K, k. m/ Z6 U% a
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空6 X% O6 z0 ~: ^% R7 F
  54.     {7 a7 Y7 q7 ?7 i5 K* j5 N0 o. c
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
      e- O$ P3 C8 r# }8 ?
  56.         {8 c) Z1 t4 F" i( w7 i' Q
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];
    # P3 D, c& z" O
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     ! f9 ~$ F5 B8 n% X
  59.         }
    , a# `/ o* G0 ^8 d  B7 ?8 j% r
  60.     }% @0 G6 O( }9 {" t7 v5 u, E" \8 n

  61. ; j+ z' D* v/ a$ d7 h! Z9 A; B

  62. 7 H/ o' d) k+ q4 s
  63. }
    / |; V0 V, B3 h' B! ?. W4 s# W

  64. ( @$ v& C' N1 P
  65. # B: l! w: J/ \6 e9 V
  66. /* 发送两个字节的数据*/4 \+ s, C7 O- D9 L2 J- {8 a3 P$ V* O
  67. u8 CAN_SendMsg(u8* data1, u8* data2). U* j$ d% C( z4 d3 ~1 Q
  68. {
    . b* ^; Q# E, P8 m3 k' a
  69.     u8 mbox;
    % R2 o6 |0 ]" c. e/ V& I4 I3 b
  70.     u16 i=0; & o1 x$ M7 e" B% b
  71.     CanTxMsg TxMessage;  
    : P3 e6 g3 T4 x& d4 ^; U; O/ P
  72. ; ~  w) b7 j4 b6 X/ h( B
  73. ( x  v. A0 `' X" j8 V
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00( Y0 b$ I7 D, ^0 A8 r" m
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000' ]. f5 k( Q/ P$ q. q$ N0 Q2 m
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    8 {8 K0 V7 q$ w6 f/ ]  B9 X
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    - d- t: q! y4 G$ _7 f& z% C5 l
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节6 ^0 q' v0 U! K% j+ t
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据& J6 n* S5 Y0 Q" G1 u& i
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据
    ! [" Y  I  {9 W) O

  81. ( X8 w; A8 w3 f4 w+ P9 a
  82.   ~; ]# S$ [2 I3 G7 n2 ?
  83.     //发送数据
    0 e2 @7 n6 g$ B; u
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    $ w2 a, d: g5 j. V7 g* T! e6 L
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)). G9 D7 m3 Z  M+ b* f
  86.         i++;    //等待发送结束
    3 Y  \" l9 B- V$ N: ~
  87.     if(i>=0XFFF)$ T" w* c, D; c$ J3 I) O& @
  88.         return 0;//发送失败, H1 ]( J" R* W0 G
  89.     return 1;//发送成功
    ) B6 @1 x# B: N# K+ @
  90. }
    7 o! k( t9 v( Q9 k- \8 E
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)( {, W+ \0 x' f
  92. {
    / A9 ?3 Z. D5 Q* z7 l5 ~
  93.     if(Rx_flag == 1)//发现数据
    ! m' ~0 {( y  u4 s# x0 c
  94.     {/ D( i, N( O5 ~, _, v- |
  95.         *msg1=CAN_RX_BUF[0];
    " l( R5 T: I7 I& f! Y" u
  96.         *msg2=CAN_RX_BUF[1];
    ) s* k" l$ \+ E
  97.         Rx_flag=0;//数据已经取走,可以更新数据4 {& i0 b* x9 U/ s& q
  98.         return 1;# n, M' \2 D9 u, m: W0 M
  99.     }else: x6 T( k5 Y% I# R' }
  100.         return 0;0 y# H2 u' I3 q$ M0 j! q. Q8 t) f% I
  101. }7 N2 k: S5 C, ~2 w  y. E0 `
  102. void Clear_canBuffer(void)
    1 U/ i. U5 d( a- y& Q
  103. {2 }& c% _2 J* }7 U& y
  104.     Rx_flag=0;//清楚接收标志位
    0 H- {1 Y9 G6 s5 a0 w
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区  h; y- R: k, d; v
  106. }
    1 c; L: [' b' L
  107. u8 Check_canRX(void)) O  S5 \5 D# k' f. @2 ?
  108. {8 W9 m3 S3 O! t0 I7 ?1 g
  109.     return (Rx_flag == 6);
    - i( u: g* @( \, t5 ?" ~
  110. }
复制代码
2 ^9 J* s6 i1 v' _6 n1 k+ l: Z
can.h文件:

  1. 2 n: j/ ^" M' z# L
  2. #ifndef __CAN_H7 E* Z% B- W4 i0 {9 {. f
  3. #define __CAN_H6 P6 y5 f8 R3 ~
  4. ( `" a& O# _& w" [, X; u

  5. : Y) r+ j8 P3 r; r0 t
  6. #include "sys.h"
    - Q6 J+ |) n: p3 Y! c
  7. #include "string.h"% a  y0 K  N1 e1 _# u' |
  8. ) a9 Z4 r) L4 q" e  Q6 F7 F/ v

  9.   J$ v2 J. `4 h; x/ N# m* x
  10. #define CAN_RX_LEN          30          //定义最大接收字节数
    1 w' L$ ]  x9 c1 ~

  11. 3 ~9 d5 Y( `1 Y! J+ w) r

  12.   _& x; j5 x- B' b6 ]
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    5 F0 I& O0 I7 n0 `3 y

  14. 0 K: C8 K; m3 h+ b" f2 v: T6 a

  15. 7 f* q' q( e- W' s! l
  16. void CAN1_Init(void);! h3 r6 ]: G2 c. k3 E; [
  17. u8 CAN_SendMsg(u8* data1, u8* data2);
    1 }# p3 Q0 ]3 ?5 i* D
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);$ G5 ]1 n0 G! p; ?4 |0 X
  19. / q9 \8 y' n" p* a. H1 `9 u% F
  20. ' X) y# A- S  F3 p" y4 i3 J# e
  21. #endif /* __CAN_H */
复制代码

( ?; o0 A1 m+ K* p
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

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