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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧) x. `5 f9 o* K, N0 o, ]
  • 摇控帧: t* k) b" a3 y6 J
  • 错误帧
    ; \) C- z/ U" k' ~" w8 g
  • 过载帧
    & f) ?7 C# l3 r2 V0 ~3 r1 @
  • 帧间隔
    1 O2 U6 c: n* C1 d9 L/ H/ [
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
. h/ F+ l( V0 O( a+ B7 ?    数据帧一般由7个段构成,即:& [$ H/ X( P: U: v$ a
(1) 帧起始。表示数据帧开始的段。
$ \8 h* W3 n- |) ]  _(2) 仲裁段。表示该帧优先级的段。
2 W2 g, z6 d! s2 G5 G+ w(3) 控制段。表示数据的字节数及保留位的段。
; b5 Z! X" u7 l0 ^(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。% W6 v9 \& @2 h
(5) CRC段。检查帧的传输错误的段。
9 m, v, q$ S+ L, j" p: }2 j(6) ACK段。表示确认正常接收的段。
6 t2 z  y1 X! y$ K8 `) r% r- M$ d8 z(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
; i/ C" n& o" v) |( n% ?, h( ~    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
    % N( Z9 X& G1 A  U/ y8 y
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
: b/ b4 M/ [( y  o3 p2 K$ d- S    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
' A0 o) k, i6 O6 a
PERMNQ{)L%G}{986WRA~Q]W.png

) W/ u) t# M5 f: k
    在程序中就是:
  1. //要过滤的ID高位
    8 o8 @; Z2 U( a; a. s9 ^9 I6 o
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;    w8 k) b0 u  _  ^
  3. //要过滤的ID低位                 + P! I4 |1 l. r0 J2 I
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; ! P4 {4 y9 @3 H" R& L/ D
  5. //过滤器屏蔽标识符的高16位值
    9 q: X( y- t- G! M8 H. r6 u6 X2 Q
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    + k3 L7 w. }0 t' W& @
  7. //过滤器屏蔽标识符的低16位值         1 d  c- r2 I& D  N* r8 w: O
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
" o9 h$ o+ q9 H& u4 J6 M
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。8 A' V0 q( q# D5 g, t$ i  g7 }
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:7 G# R! ~3 B7 F0 x) a9 N1 J
主机:0x13143 c& d  \4 o2 F5 f7 h& ^0 k
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:
  1. 7 l* K* Y2 G7 n' M
  2. #include "can.h"
    2 p  O, J2 A7 V, W9 i

  3. 4 n7 Z+ t7 t8 ]" n

  4.   b" m7 Q5 c2 X- M$ g6 \( U1 k9 G
  5. /* 在中断处理函数中返回 */
    / @9 A4 h) y2 p% P3 @; n- [. Q  O
  6. //__IO uint32_t ret = 0;
    * z) f3 w9 U5 Z& P6 `

  7. ' y1 B3 N1 V& K3 |& {7 m8 @
  8. 7 q( i9 r1 }" s4 a$ w# W; A9 e
  9. //接收数据缓冲器8 n: i0 h( n* p
  10. u8 RxBuf[5];' w- g: I. t9 @8 b- H
  11. u8 Rx_flag=0;; N" m' I; E3 z5 E! T9 w/ d

  12. 8 [# T8 s; p( q; b- d2 G$ t
  13. 8 W8 V) a( W3 L. I2 U8 ]3 x
  14. void CAN1_Init(void)
    1 Z5 M, w: ^+ Y% H5 B6 D! L  x2 E
  15. {. X; l5 D7 O; A4 c; k; N  \
  16.     GPIO_InitTypeDef GPIO_InitStructure; % n8 F$ X& b- r6 g
  17.     NVIC_InitTypeDef NVIC_InitStructure;# B+ }0 y+ t1 i0 ?; `* J6 o6 a
  18.     CAN_InitTypeDef        CAN_InitStructure;
    0 X9 c- {' k: j& G
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    3 ]0 {+ _1 w- s# H1 u* A: w" j) v
  20. - g. F" w0 u4 c( \6 Z+ T9 _
  21. 3 L) b6 b4 v2 |, L/ H% Z
  22.     /* 复用功能和GPIOB端口时钟使能*/    4 l6 a; b  f8 K8 @& n- p
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      & T: }& k; n: ~8 c. B* G: p8 M

  24.   g8 L" z% z" H; k* E* d: L
  25. - ~# z! I0 y* o$ Y4 P2 j0 r
  26.     /* CAN1 模块时钟使能 */! H6 P' T3 L( b2 j
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); $ Y& R6 T- @4 I( `* }- V! E

  28. ) I- a1 R+ g) _4 z3 P) H% K
  29. 1 z& V3 @+ a3 ~: @' Q
  30.     /* Configure CAN pin: RX */  // PB8
    7 g1 b5 R9 E" ~9 }! Q
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    6 c6 s$ [' S% R! P1 V4 m! h+ n
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入/ u$ x' r5 t" y! |
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);7 F) A4 B7 {# q8 N+ c$ ~+ ^
  34. ( Z  h5 f  X! @
  35. - P# o! d% E. ]3 n" r, S5 z# A
  36.     /* Configure CAN pin: TX */   // PB9: y2 `2 s* \5 D" w; t
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
      r0 I2 ]+ _1 g& S) ~7 O3 I; L; _# b
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    % E0 j$ ^3 d8 V  R9 W
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    8 X9 c! {8 B$ v  n, V! _
  40. 4 A% E- h9 s1 Y$ \" @

  41. 4 Z1 o$ S1 O# K! Y: t
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O3 I5 K) r- w- K; `0 u) ?6 E7 _  c
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    6 N( R$ K( j% t9 {* I& _

  44. 4 i, ^1 h3 G" U9 ?" P

  45. 5 Y$ D* c1 x/ T4 p1 _
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   + {  b: [+ T- }' s# P1 E# ?
  47.     /* Configure the NVIC Preemption Priority Bits */  
    ' \* G7 @* ^% _% K# X; N3 t8 ^
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);& a( S) Q7 J4 G1 n5 M
  49. 8 t- _# K; o# v( P* ]% h$ _; k  c
  50. ' A& C- Y/ k6 J5 R9 T' Y3 \
  51.     #ifdef  VECT_TAB_RAM  
    ; ]! B. w2 `( d  y. Z  H
  52.       /* Set the Vector Table base location at 0x20000000 */
    * |1 ?- u. c8 H. b. R8 C7 Y7 I
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 5 g% x4 n8 H, y
  54.     #else  /* VECT_TAB_FLASH  */0 B8 W- i2 l+ p
  55.       /* Set the Vector Table base location at 0x08000000 */ ) G6 ]7 i9 B2 L: U" K
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);     f% m8 q, }9 p; a
  57.     #endif% Q, P* y' p3 O8 \$ Y
  58. / V4 V$ s3 Y/ e

  59. , v2 R) I" W1 r$ L7 F
  60.     /* enabling interrupt */
    2 n0 ]  y+ J$ s+ d# C  i
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;& N! j) W% q+ c  O5 A; M) M
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    ) ^9 _/ h. J; e' ^* i* A
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    % B; P3 K' h6 P8 N- E
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 d. P8 [0 J7 x  q3 E
  65.     NVIC_Init(&NVIC_InitStructure);: i6 J3 I: v  p9 @; h

  66. 4 P$ E: w* Y8 o: b) e% X

  67. * ]4 m! ?6 p5 C
  68.     //CAN_INIT();//CA初始化N模块
    6 }6 I; ^. a# V; K
  69.     /* CAN register init */; t6 f3 y0 n% |: F5 \/ ?; H/ w
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值' B' w  F' l, K5 N% O
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    8 }6 m/ z' `  x# V) j

  72. # L6 O% l1 P6 o3 `
  73. ! `( f9 F8 v2 X, W& I
  74.     /* CAN cell init */1 ~/ w3 Q' V6 z" O! T, N
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    6 L0 U) t/ j$ ~# P9 z% o; t1 E
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理2 h1 V& q. F: T
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式, ~. X6 G) ?* V/ I% ^) Y0 j. l
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    ' J8 t  {5 j( m: ~2 B5 n
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式- \$ k4 B4 |1 Y. j7 z/ ]: X1 o
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级- q9 b1 \" s5 B- |
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式8 l5 H8 w4 @! h. t; b7 S+ K
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    1 m9 p/ z8 {% ]* Q1 R' Y6 w
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位2 |( R, l0 ]" h; i; J
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位' C) |3 l& z$ S
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    7 w* R- R; b8 ^# z2 B
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    , q  J7 X! Z7 k9 {( n1 N) K# }

  87. 4 \. Y( m8 V3 h

  88. ! W8 W" Z/ P) z  d
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    : ~+ q% |. L" w3 E, Q4 e" g
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1/ S) m- f6 E3 K9 v4 u4 t0 q
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    & x* ]/ t  V, }0 n0 [8 g
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位3 D3 F/ X4 t0 u$ {" G
  93. + M5 p( f5 {/ e$ U2 m7 T
  94. ; k0 j( o8 U% Z7 J
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  9 e; d5 s7 x0 m" ]9 G
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    # X% h: c* r2 c% H$ n% \+ ]
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
      V7 w% N- e- `& v$ f
  98. ; a0 N/ ~1 r" \4 \" a2 o2 }- K
  99. 8 }' h# S+ e6 d2 O7 A& u9 X
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    , n4 ~: j" W5 U8 I; w, l% l4 h
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值. k/ S. Z/ a4 s- P1 P1 x
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为07 t& |; r+ m6 Y. `# C
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器% Q' v- g8 v, f" Y' Z- g
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器% a& I+ B' i/ o/ R; Z

  105. & p& J* z3 G5 ~. ?8 q4 A% f

  106. 4 z# l7 V! v1 g6 [0 p, t- y7 o
  107.     /* CAN FIFO0 message pending interrupt enable */ 4 M. U! r& @7 h  A! r9 ~0 v
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
      u8 ]5 E& @6 |
  109. }6 P( T( h* }+ ^+ N& P4 o; M

  110. * k9 F/ J- A8 I5 J6 c3 g
  111. 1 H+ c/ s* v) m( U; q  \& e
  112. /* 发送两个字节的数据*/+ B" G, i8 @) g( ]
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    ' c( W9 t: g  a
  114. {
    8 N0 I" b( C- [1 L1 L% M/ |+ O+ X
  115.     u8 mbox;
    5 R$ a  b! f4 P* K
  116.     u16 i=0;
    # d- H2 K$ W& `1 q1 h+ |* _
  117.     CanTxMsg TxMessage;  
    1 q( @2 @: k2 D! S. g+ a

  118. - w, Q0 K  z7 x1 k
  119. - A, _2 ~2 y' m9 d1 ~# M! G
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    0 g* X3 S5 r( p* v( T9 t
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机6 d1 i# O5 L! f) j$ k" m
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符% h/ P+ z# e7 e
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    , e, {6 p% W5 b: C
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节/ n, n3 u2 E' b" A# }: A# s
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据' j; G* u5 W, E/ w
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据 ) x* o2 n* k8 p5 }& v/ S$ R
  127. 3 w" Q$ Z4 U# t3 V
  128. + Y7 T  ^' X0 _- v2 I# P% B
  129.     //发送数据5 h' F* O% E. S& D
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  $ e5 r3 j+ y: A, a( f3 k1 S
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))' Y( A9 n3 a7 r
  132.         i++;    //等待发送结束- J, f( y% ^% O' @4 `
  133.     if(i>=0XFFF)/ I& u$ H& y* s4 F" f2 i* v
  134.         return 0;
    . x  d: u6 K; u; m) U3 `# t
  135.     return 1;
      w0 N5 b/ ^  J* [. I0 N( U2 {! U
  136. }
    " V6 J4 w& B2 C
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    ' N& `+ c0 ^( P* z
  138. {
    + M7 s# D0 I3 V
  139.     if(Rx_flag == 1)//发现数据
    9 b& |$ o2 t8 ~$ k
  140.     {
    5 C+ A/ b  L8 D6 e3 s  D
  141.         *msg1=RxBuf[0];
      r* M2 N" w9 S2 `
  142.         *msg2=RxBuf[1];
    , B8 Z. {! T# X- |" v
  143.         Rx_flag=0;//数据已经取走,可以更新数据
    4 |' B, y2 u' f# Y8 s. }% {
  144.         return 1;8 n* t) `2 Z  [9 t3 ?) s
  145.     }else
    ' e0 B/ v0 d* r8 l
  146.         return 0;
    4 w* z( f6 d4 f: m
  147. }
    2 [; i9 Y' E2 g( j. P' U
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
      g6 D" S, [& T: a
  149. void USB_LP_CAN1_RX0_IRQHandler(void)9 H+ [. w" t+ F% H& d2 N$ y
  150. {# H3 o+ a0 x/ i  C. t% E* d8 w

  151. 8 C+ W1 G6 I: F& z

  152. . B( |8 z/ S& H
  153.   CanRxMsg RxMessage;
    . I1 Y7 z' v7 N- y

  154. ) N% `: {/ T' x; j  \

  155. & a% v3 x/ f2 }
  156.   RxMessage.StdId=0x00;
    7 s$ \, b/ |5 j; U, B9 Q
  157.   RxMessage.ExtId=0x00;/ o" Z% a) }( g3 y$ ^2 j0 l7 [* o
  158.   RxMessage.IDE=0;
    0 ]- D; D4 \1 s$ ?2 N& [
  159.   RxMessage.DLC=0;; e4 K; x2 ?! B: b, ^2 T  y0 m$ `
  160.   RxMessage.FMI=0;1 f+ t# d# ?; C8 F: c2 R4 J
  161.   RxMessage.Data[0]=0x00;
    7 H3 Y$ t* l" v# y+ h1 P
  162.   RxMessage.Data[1]=0x00;      L  z. g' W; M
  163. 5 v* z4 n" ^7 c1 t

  164. ' y( s8 H4 T- l( J
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据    z8 i( O* H& e! Q* |

  166. # m: v- f! o7 G  V9 f( v! ~/ i) r

  167. 9 x) d  w3 {0 f- W; [, m; E) w
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空
    ! o% _9 K0 ?/ ~0 ]4 }
  169.     {( Y; J7 i4 d6 c7 \% u
  170.         RxBuf[0]=RxMessage.Data[0];
    + |/ _* n+ t' `$ j% R* G" {4 s3 G
  171.         RxBuf[1]=RxMessage.Data[1];  r9 u1 }& h' R8 y: h
  172.         Rx_flag=1;//数据已经备好,等待取走* u7 g- \# a0 v! A# m! \  N' V1 _
  173.     }
    / a; ?$ n2 B, h/ x; r; v' \3 n7 @
  174. ; N6 H; R# ~. a' v$ e7 ~

  175. 4 m% G3 e+ G5 J, \: Y
  176. }
复制代码
; c4 A, L+ G$ H# R, B. v
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
$ n8 J1 y, ~! E+ ncan.c文件:
  1. # a( F& w1 E9 A% M2 w5 T( Y+ e
  2. #include "can.h", j" Y# m1 z( A% p5 D

  3. 0 U( {" ^3 p1 q6 M) t- ~/ P
  4. 9 h% ?; {7 P' J  y- q
  5. /* 在中断处理函数中返回 */
    0 x8 n1 k% m: N, Q% V: \8 K
  6. //__IO uint32_t ret = 0;
    , e; a' ^7 T/ j; ~6 s+ F

  7. " B$ @& d, }) t3 ]2 r

  8. + a+ o8 T8 c$ [, l6 J8 |
  9. void CAN1_Init(void)
    9 m" R' a% s7 ~. @
  10. {
    % W- l4 m3 f/ L: H
  11.     ......//以上与从机部分相同
    * H4 r: D; y# t6 W! l
  12. 2 O* R1 y! u2 f; V7 }

  13. 2 _/ U0 _% x+ k( g0 m
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    2 e) a& m  S5 ?" s) S
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1# s: L# P- j9 e
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    , W- m. c1 X1 |; w4 c
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位. r) Q8 d' I( e) K& l4 k
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值; [1 o  p$ K& s$ ]9 n* o( x. _
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    + c5 v4 N+ _8 V+ z
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值/ E$ p# H- n% Q
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    / T$ M! h3 \: M$ A6 h. f: E
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为05 @% D& x5 Y- ~& L# D- {# c- C
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器! P( K- ^4 P8 u9 I
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器0 X/ r3 z# C" c

  25. ( T: C( g# ]+ v! w3 c/ r& d, Y
  26. ! j/ Q5 s- k. Y% r3 G
  27.     /* CAN FIFO0 message pending interrupt enable */ ! |' x  X) V: _6 H' U/ J# F* f
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断, y, L4 \- @5 ~* g) y  v3 Q
  29. }
    ; I& T  A2 Y, P! j( ]* j2 O% ]
  30. . j* i* f: F, r
  31. ( \9 J- Q3 _7 l# w, `) B- l$ n. S% b
  32. //接收数据缓冲器- B% S% b3 ~+ e$ W& o  W$ y0 L; Q
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.% ^7 }7 ^* ~. u8 w, c% ^% T
  34. //接收标志位
    * t' ^7 I7 [% P
  35. u8 Rx_flag=0;
    . f- s; `. t; f7 f0 e
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */! n9 i/ i2 y" n4 r' b0 b
  37. void USB_LP_CAN1_RX0_IRQHandler(void)
    7 f# f/ j5 h# F
  38. {
    0 }8 F' J" n2 f: ~$ |/ k9 B
  39.     u8 i=0;; a  r. f6 L1 o: u6 Z$ }6 f
  40.     CanRxMsg RxMessage;1 V5 \0 r0 [( u6 G

  41. & h3 S6 X, r1 l0 Q8 {& [

  42. " Z: v, L5 E( |" d  k/ |, L1 i5 d
  43.     RxMessage.StdId=0x00;
      S: [0 L6 [+ b9 {9 ~. H
  44.     RxMessage.ExtId=0x00;: c& Y* w/ G9 j' E
  45.     RxMessage.IDE=0;3 P7 K* G6 ?7 I" y/ T4 ^
  46.     RxMessage.DLC=0;' h! n$ A- z  _6 \% z5 g& D1 ~6 d$ F
  47.     RxMessage.FMI=0;
    + [: i# P/ j! u. f3 _
  48. 7 X; B" N3 F- p- T- P( d1 \# `

  49. 8 v! `/ ~! K# k# D# A# V' x' t
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  9 Z7 E/ f# B( {4 E' F- A( H
  51. : h! p! ^" ^, s# \: V7 U' b, \3 O
  52. 2 y, l, J3 p9 q% ]/ J% ~
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空; F# S- k4 S9 v/ E0 h8 m
  54.     {" G+ o' U7 b( n0 @( w/ l
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    ' h4 J  J9 I: D( |
  56.         {: K- f* ]! k$ |6 E$ z, M
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];: \8 P* d  e, B3 E* x8 e
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    : l. ^( p; V0 O8 r6 v  y6 O; w4 y
  59.         }2 R4 L5 O7 X- J/ S& C
  60.     }  e) W4 h6 j  }; r  J) J
  61. 1 a! D. C3 t0 e

  62. # z( }; X+ T6 `: q! S( K: T
  63. }
    4 g9 Z% p4 O0 i4 T" u* ^
  64. ) v" N4 b  e$ z1 c+ Y

  65. : N, o6 s" Z/ Y2 j* b/ M
  66. /* 发送两个字节的数据*/; H( l! [( k! F, N2 W) ^7 O
  67. u8 CAN_SendMsg(u8* data1, u8* data2)
    6 P* B, Q1 m3 A- W8 Q
  68. { - f  ?( c; [( p7 p" L5 [! }: U+ |# X5 b
  69.     u8 mbox;
    * D2 {# H/ f" F; x
  70.     u16 i=0;
    7 {, P8 ?2 b: H) I3 |0 F
  71.     CanTxMsg TxMessage;  ) U3 }# y8 ^5 @; Y( K9 K
  72. ( ?8 d, O8 D" z7 |8 n1 f' {6 u; n% l
  73. 4 G- S( s* a) q5 S% P, }9 r
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    5 w, D. y) q+ m/ r+ [# R
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    1 i$ r& ~. Z5 q4 X, z
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符# q- q( Q/ `0 G7 W1 t! k  o8 @
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    ' M* t: ]+ N6 I+ d
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    . o% o+ f* V- k8 r. b
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据
    # _, L, W! F0 x# B5 m5 ^
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据 0 X& g+ Y& r2 g3 E0 M7 ]2 L8 F: U
  81. $ l/ B( ]  D1 G, x% u

  82. 3 W- V# I' q) U7 b) i- `
  83.     //发送数据
    ( b" @2 H7 [! q# x
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    9 f( S/ h, v( M% v: I
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    , p* m; M5 p) N: Y
  86.         i++;    //等待发送结束
    , L4 Q2 ]/ a7 U
  87.     if(i>=0XFFF): J# d$ h, \! U2 u/ S, ~% U
  88.         return 0;//发送失败7 e/ l7 h1 E3 T8 J  c
  89.     return 1;//发送成功 . v$ v! G% M' p6 S$ t+ D) c
  90. }
    1 z  l. t% e: g3 n: X
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2), H2 r& `  f: e1 {/ p4 u" {
  92. {
    3 J5 o1 q# Z& [( e& `7 U" r. u
  93.     if(Rx_flag == 1)//发现数据6 T2 Q9 V2 L- I6 ^, T+ t& v0 n
  94.     {7 u: g' N0 c6 t
  95.         *msg1=CAN_RX_BUF[0];" G% x' X& D, ]8 W
  96.         *msg2=CAN_RX_BUF[1];
    * f. Y; i: ?# c7 _" p
  97.         Rx_flag=0;//数据已经取走,可以更新数据
    ( ]8 ]3 }( C3 O# Z2 P* S! h2 t
  98.         return 1;
    $ q: {6 Z& j  ]8 |* Y( F
  99.     }else
    & x/ A# w9 A9 u# J
  100.         return 0;3 e4 N& E; G/ n6 N
  101. }
    9 m1 |" q+ A7 _  ~
  102. void Clear_canBuffer(void)) i0 q1 p9 I7 M6 n7 q& U
  103. {' o8 P, g) X2 U# X+ y1 |9 A, E5 B
  104.     Rx_flag=0;//清楚接收标志位2 M. V$ }8 h& W! W4 u* X* ~) R% r) J
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区/ P9 n' g0 Z, Y
  106. }, l- O& c& Q$ `4 c8 q( X; s& d' B
  107. u8 Check_canRX(void)
    1 q, V/ l% e5 S" L6 ?
  108. {
    / K# I: n* v+ H7 i. Q
  109.     return (Rx_flag == 6);
    : Z% c( W; Q* b  J, y
  110. }
复制代码

! T/ x) n9 y! o0 Y2 `! k+ B
can.h文件:

  1. . N; A- ?9 f& U  I. `4 R$ \
  2. #ifndef __CAN_H
    7 w' B0 T) k% I3 ]6 p% s
  3. #define __CAN_H4 h7 X, E3 m/ z/ m( O5 X
  4. + `5 }7 q4 A0 h; D, S

  5. ) B# \3 k+ r& Q4 ]* t+ ^$ v# J
  6. #include "sys.h"' r; e. V+ U  q; A! A
  7. #include "string.h"- }$ d4 y) T7 I

  8. , k4 E" ?: C9 o+ d: ?/ `/ g( q

  9. , T: _; Q4 ?! M4 X
  10. #define CAN_RX_LEN          30          //定义最大接收字节数
    6 X( n/ Q1 P- I  q. c

  11. # R; f* I5 w$ y$ e" _7 x

  12. # {( W; d% H5 W( a; }
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    3 Q0 c/ a/ I* @" h
  14. * `8 F4 `* }, P% y$ Y7 f' b

  15. ) P" f: ~& f& O- T
  16. void CAN1_Init(void);& f% J" g) U4 p" c" H
  17. u8 CAN_SendMsg(u8* data1, u8* data2);
    - e. v% k: v, I& Y, t- O
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);' F, l$ ^: Z) X8 G! S4 R% f

  19. 6 a. Y7 M  e! d( [; H
  20. + [0 U2 Y6 X8 S" p; @+ [4 Y
  21. #endif /* __CAN_H */
复制代码

* j( P  x, I; W# K7 A1 ]0 r
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

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