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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧
    ( f. Y/ \- O% C1 Q8 L4 |9 L
  • 摇控帧" m6 [+ g7 X* e4 t
  • 错误帧
    . K# u/ D7 [6 R; n9 Y7 {
  • 过载帧
    2 L- O  R/ X  g2 e
  • 帧间隔
    7 S/ q* |( S# B
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。
3 l  L4 S: [# r    数据帧一般由7个段构成,即:
: m5 A1 _4 k5 m6 s4 S  U3 f(1) 帧起始。表示数据帧开始的段。% I; r4 G: l0 s: R1 R3 r9 E  G
(2) 仲裁段。表示该帧优先级的段。  K; x5 k( `9 m" q# X
(3) 控制段。表示数据的字节数及保留位的段。
, `8 o7 e8 l3 P! Z(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。
. w4 Y& H; _8 L9 ^, f(5) CRC段。检查帧的传输错误的段。
, {1 f) Y; C, W9 i8 l( e+ J(6) ACK段。表示确认正常接收的段。
; |& \2 |" c1 v- \4 t4 [& W5 ~(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
7 p# J& {* _# G* g9 i: v0 C    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
    % {2 @6 P+ r/ q- ^, y
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。. Q+ H- u' h/ @& Y) W
    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:$ p1 d2 O. I  t* {! W2 x( t9 J% l3 _
PERMNQ{)L%G}{986WRA~Q]W.png

+ @$ W9 @8 |% U2 S( ^1 ?
    在程序中就是:
  1. //要过滤的ID高位
    + f3 O% m2 [% r4 t
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  
    3 h) A0 U, g* a; V
  3. //要过滤的ID低位                 
    . ?8 H) ~6 V0 B5 C
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    . e0 j. @  f- T4 X. b; Q7 s: I; d4 \
  5. //过滤器屏蔽标识符的高16位值
    / H, S3 w! q# y! A/ M
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    ' g- W$ e4 P3 l  c* Z# Z; l' }
  7. //过滤器屏蔽标识符的低16位值         
    " ^  q% A  H9 o1 ?+ F
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
6 r; u# ?7 M4 Q$ J+ l6 A
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。" z( x3 y# K  X3 B: a- K- {8 O4 f; m1 X
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:: U' P4 c/ {( n2 d2 K, V$ u) H
主机:0x1314
8 k* q3 j) ]  f' ]4 ^# p4 H从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:

  1. 4 R& A9 V4 A" K% z
  2. #include "can.h"; w* e3 I. a$ [- {# ^7 S) a

  3. ' O) e, g. V# B; A- U
  4. $ w9 _( P+ N, {/ Z9 o0 S
  5. /* 在中断处理函数中返回 */2 S" D% @2 F' }- Z  v/ [
  6. //__IO uint32_t ret = 0;2 c- }' ]7 p4 e0 V' Z4 O
  7. 8 w3 G1 O7 A9 b* ~* L3 ~

  8. 7 \, |6 q. }6 C
  9. //接收数据缓冲器/ \! p1 t: F  K+ W" D/ P+ v
  10. u8 RxBuf[5];
    ' o7 y; q) ]  R# t" \4 U
  11. u8 Rx_flag=0;$ w# D- \5 U* X+ B3 V/ X

  12. ( i; y2 q- w: u! p6 @2 F$ q
  13. " j! R5 a; Z2 i
  14. void CAN1_Init(void)
    " \2 E8 D: K3 I$ F; ~
  15. {
    1 F$ @  f+ [" X. L5 N' g
  16.     GPIO_InitTypeDef GPIO_InitStructure; ; S1 X+ y7 @+ \" P  }! b' p
  17.     NVIC_InitTypeDef NVIC_InitStructure;
    : d  x: Q& ]- w1 q
  18.     CAN_InitTypeDef        CAN_InitStructure;1 R4 ^& H8 Y! m' G8 [. X' i
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    7 z( L. |, J- J5 v& \- B
  20. . h1 S2 y$ C7 g

  21. * ~' w4 ]+ o4 t) ]2 X% T6 a8 r
  22.     /* 复用功能和GPIOB端口时钟使能*/      h8 U# c) j. M) I% n% I
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                      6 t: ^: K7 r; R* `# B
  24. 2 x5 ?( g7 u7 g9 |$ Y( \

  25. , ?5 O9 c- M! ?6 O  W0 y5 `
  26.     /* CAN1 模块时钟使能 */! F+ O# |" u# J3 u1 w4 z. }3 M
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    & ~" ]  m7 Y" I! [8 M# S
  28. + Z7 X- w' [9 ?: m

  29. 6 y/ F' x& S. G2 k, L3 L" ]; g
  30.     /* Configure CAN pin: RX */  // PB8
    0 m- J' |5 |) o+ z. w! G- [
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    " X+ @* I# k  ]( e5 q# k; \
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入) P7 p% b* _% a% z
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);, `, Y4 n* ?4 b& u/ p+ D( S

  34. ; `8 Z& U2 N  J5 C, i2 y

  35. 5 l- i$ [8 A: o( E0 ?6 g$ ^
  36.     /* Configure CAN pin: TX */   // PB9
    ! V8 ]8 C( u& v! _- A
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
      t) w. u1 N, B  I! ?2 D* P
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出; P! n+ K  G9 \& ~( w6 R
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    - L* }  V8 }6 t  _0 E/ _' \
  40. & R0 x, ~  }- T

  41. * J, S3 b, |% f4 {
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    " `: d7 ?4 I& j
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);2 I* |2 R. T4 s$ U6 B5 X

  44. & ]9 t8 _; {3 z

  45. 4 a# e" {" p5 I! v' g
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   / Q& f' d; Y; S% T2 C
  47.     /* Configure the NVIC Preemption Priority Bits */  ( p. m/ `2 w6 I7 n! r4 {
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);8 w- O: h/ E6 i  d4 a1 s

  49. 2 z/ V9 G8 b9 C" N- I% J
  50. 2 b! m5 Q7 X; M8 {0 d
  51.     #ifdef  VECT_TAB_RAM  
    0 v: E; J& }0 O$ ]/ ]
  52.       /* Set the Vector Table base location at 0x20000000 */ , H# F0 @) U6 r% I
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); + g. o* ?$ v9 G) ^9 W1 f
  54.     #else  /* VECT_TAB_FLASH  */
    3 m" l2 O: B' j
  55.       /* Set the Vector Table base location at 0x08000000 */
    5 @0 ~# q5 R$ |
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    4 X" }4 B( {& j, t
  57.     #endif
    ' x6 R& V: r0 c% r- c

  58. 0 F1 ?0 b/ _4 F
  59. # I% j6 X' ]& M8 a. [" y! ]7 ~
  60.     /* enabling interrupt */6 S1 e/ Q9 U8 T& d( ~  H2 V  G
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;; m' U  Y- m9 B* }+ @, D
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;, P& k) _2 X0 F+ |/ P% }7 V
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;- Z# f3 H  H& W; z4 q  D" ~
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    # o' L. w, i' d3 W
  65.     NVIC_Init(&NVIC_InitStructure);
    0 c, o7 i, _5 Y5 N, g. l
  66. * n8 h$ O% `( ~- I2 _. ^- b4 ^

  67. + h& K& c' o) x6 m
  68.     //CAN_INIT();//CA初始化N模块 + Q3 l  \( o* C9 v' o
  69.     /* CAN register init */
    / s( x2 e1 s/ k1 }7 }# u. g% @
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值, ]3 _* f* K6 C9 D2 d9 J- Y
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入$ H* I3 k& I) z8 b

  72. 3 F7 k4 X% W- ^7 ?- f2 z) {4 v- D* D
  73. / m! B8 c* K1 q# y! f. ]
  74.     /* CAN cell init */
    , I3 e- O9 ]5 W  l' I  ^5 @9 f
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式
    # O+ D5 g6 K& r
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理
    6 d: I+ A6 o* s# I& ^# Y
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式
    9 t( t3 T5 b' ^$ q
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式
    - [! v3 E: S6 y
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式
    % N4 Z$ |; H; X* o- M4 t
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    7 }2 J6 z8 V4 ]8 ~7 [: x
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式
    / |3 B9 }9 L& v) H& d# e0 W1 u
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位1 g0 w1 ]' E0 h' c' y% W9 \- M
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位
    ) Y" d7 \/ V8 C8 ^7 A- X
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位( i, i4 t) Z3 b: e# e
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60
    - L2 q0 d; O/ i7 k" \% a7 G
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    ( u, R0 K2 D/ w

  87. 5 f# f4 O! Q0 K4 j6 e0 c

  88. + t6 ?1 k4 W0 d9 _8 f/ R% k1 N
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    4 \0 @; ?3 B. ]0 p3 ]: u" y$ q
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    2 J- W( s/ j& ?' l9 ]
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式3 S2 ~: Z; w8 w8 }7 O; {# `, I4 K; u
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    - Z9 P  W* L& B) p/ q0 t
  93. ! U0 b: v1 x7 }5 i7 c
  94. ! s3 e! w+ }$ `* h- [
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  ( o* a, J: I2 I2 r
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    " K# E* W* _$ B: e
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    . F. s4 N4 v' J) X" C
  98. 1 P1 T# L3 t# [6 \1 W" C

  99. / T& X5 c- C; P/ k8 O
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值1 ]7 L; W1 ~, L. g' \- Z
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值. ^6 e4 x1 N. ^  J$ G& s0 h
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    + j+ ~; _, R! H9 D
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器. Y+ e- c8 U' v; ?
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    1 I2 ^( F( v4 L0 h' H: T
  105. 6 r( ?# q3 N: l3 G: `# ?  ^% e

  106. * D/ X4 m4 Y, h
  107.     /* CAN FIFO0 message pending interrupt enable */ & U) W: \0 b8 J( Y
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    6 C2 _% T7 Q# e( ?/ ~5 G) ]* M
  109. }
    " o" z" X; i) [: @$ Y/ z1 a) _/ e9 M5 d
  110. 2 m: D: J  p0 M3 ?3 v4 t& u
  111. . I" a; F* ]$ ^* w
  112. /* 发送两个字节的数据*/' C9 M# y' m4 Z, {: y( k1 t, O
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    # X8 S$ v1 ^. N' o) B
  114. { ! q6 t2 h4 s  F8 L7 q, e
  115.     u8 mbox;+ _6 m3 e1 i. |) h+ K. @# Q
  116.     u16 i=0;
    4 Y  h% T) q7 G& w4 Y+ |: ^
  117.     CanTxMsg TxMessage;  % \9 k$ M% y9 I# s4 g

  118. # |1 L; W" T) ~8 Q; A7 [+ J

  119. . H3 B3 L! U  v% F
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    5 W& s- W9 Y3 G2 [
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机& O) O, \! D: ~+ N' e2 S# E# i. U  S
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    / Q+ e/ {( P3 s% {: C
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧# v: E: Y3 Y' l3 ]1 m3 x, y4 g5 O
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    : X' S( d6 w- n3 ]* n" O
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据2 t& M% r: G# d( E- j8 L, W$ _
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据
    " j5 y& O& V! H; L# g- M' `

  127. % i+ Q- B$ B, C6 b, u7 [- l7 h
  128. 9 ]1 }+ ]7 v- B8 M8 W4 z
  129.     //发送数据
    / S9 o) N  Q  D( \# ?
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    8 }" c, A. S/ S: e
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    # w# a: B( H' u) i2 S+ k
  132.         i++;    //等待发送结束
    + o- m, ?' `- Q+ r1 i5 d7 B
  133.     if(i>=0XFFF)' X9 s. U2 a- D- Y) X; e
  134.         return 0;' g0 V2 j) H  q# V; Z/ v- B6 x0 R
  135.     return 1;
    * I4 X/ Y+ F* a
  136. }9 k. J; D3 i' ~# O
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    * N- p( Y' D3 j+ o/ t2 [7 o# x
  138. {$ A$ k0 c# H( n$ M
  139.     if(Rx_flag == 1)//发现数据3 g" p* o  o  Y7 J$ a) u
  140.     {
    1 c2 n* e! z( {' o9 d( f, M4 U
  141.         *msg1=RxBuf[0];
    : E3 Q7 y# R4 }: z. m. y. i
  142.         *msg2=RxBuf[1];
    : e8 z- l4 C9 S$ s. B
  143.         Rx_flag=0;//数据已经取走,可以更新数据# i+ O6 `6 R" _" A
  144.         return 1;- O& X, p' O0 u4 I
  145.     }else
    4 f% n( w8 G2 k7 d, ?
  146.         return 0;
    - C& s7 G) V/ S, W
  147. }: y3 Q% q! j" y6 R: a& m3 U
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    3 U3 e9 @; a6 E) l) ]
  149. void USB_LP_CAN1_RX0_IRQHandler(void)8 L% T) u& y! G2 ~1 b! n- k
  150. {
    % z$ e2 s. G* p: Y5 Z7 g, F+ m4 o
  151. & g% U: \" n# h# x/ D2 O$ Y
  152. # Z9 g) B; P; M, F% q
  153.   CanRxMsg RxMessage;
    # \/ ~3 P& z& d. J
  154. . _  Q# K- v- b& O) s1 h

  155. * i% o6 S8 Z% k# C: G
  156.   RxMessage.StdId=0x00;4 f. J& n1 W5 q- j
  157.   RxMessage.ExtId=0x00;
    ' x, |. |6 k3 v
  158.   RxMessage.IDE=0;8 b: d& W. Q/ ^, o4 p6 K
  159.   RxMessage.DLC=0;
    ) v9 h% K) `7 P  ]+ X8 {
  160.   RxMessage.FMI=0;
    2 S5 G1 d) n5 ~; l6 t
  161.   RxMessage.Data[0]=0x00;) x& c4 d  A( q% F6 F5 h0 l
  162.   RxMessage.Data[1]=0x00;   
    2 i4 O9 ^2 Q0 {: a* l5 P! e; K4 k7 k

  163. ! m1 A  m3 u8 m0 I1 p! D

  164. 2 z+ j% t/ k% |5 Z$ z
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  0 ^4 c2 L7 Q" e8 F

  166. 3 w$ l  j+ W; u! p, s2 o

  167. . }% w- t( z  D4 \* u( v( S. ~' c
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空  U5 P  U9 _' H
  169.     {
    # N4 X" a/ U' l1 u/ H( \
  170.         RxBuf[0]=RxMessage.Data[0];- d) O6 W+ \* t+ C9 e+ v) k8 B, W
  171.         RxBuf[1]=RxMessage.Data[1];8 g: K; t) u% _8 @8 w, w
  172.         Rx_flag=1;//数据已经备好,等待取走
      |" s& v  w, j+ G
  173.     }
    7 h* P, K2 x6 G9 W3 y5 h
  174. 8 ?1 P% N. O3 L% _, w
  175. ; m: K$ t5 y! h: z9 A, ?& n& O- Y
  176. }
复制代码
3 O7 C5 k! i3 `9 k
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。% N8 O9 _% ?# [0 X  b8 x
can.c文件:
  1. 0 O( s5 l$ L  c) M/ v" ?, b9 Y
  2. #include "can.h"
    ( b8 G" M9 T9 A/ J) U+ x5 m0 {: s
  3. ' ]8 m! p$ s8 W* @
  4. 0 M- k% ]- w1 R4 g
  5. /* 在中断处理函数中返回 */
      G3 s8 z- P$ {8 }+ q  d
  6. //__IO uint32_t ret = 0;
    2 Y! h# H8 b- u# X' w
  7. , K) V+ C6 ~. f2 Z# p3 O1 a

  8. ) _: w) X/ p* r5 c
  9. void CAN1_Init(void)
    ' `1 _* N+ B+ ~6 ]4 M) E
  10. {: Q& _+ b! o3 B. a/ W+ L7 Q7 t
  11.     ......//以上与从机部分相同
    ! @2 T$ o# P/ u/ F! X5 ]

  12. " i6 P: w# N3 i) u, J4 i; \7 ^
  13. 4 X6 h/ b/ w6 a  |* G5 P
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    , i' }2 P& s, K! Y8 H8 U% f
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    , O' f/ w4 ~/ w" {2 b  ~+ R1 t4 C
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    ! r( c' u; w* Y; ]5 `. w
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    2 a. ~7 x; X2 `. W8 H5 p" _
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    6 G) A2 B% S. q) C# c# W6 x3 q
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值' [( K' w7 K$ m) o
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    ! G' o2 \# b* c( b
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值
    5 n2 H' {# u' H0 i2 G# V/ X! B
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为02 G- i3 ?* l0 B
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器- A) t/ x: z2 {* C+ H9 S
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    * M% U6 N/ b9 U7 w1 ]* ?, U* x
  25. " U5 z9 \# Q# y$ }5 w9 S. H! ?. H8 ^
  26. ) r! R# s+ u% e0 @! ~5 ^
  27.     /* CAN FIFO0 message pending interrupt enable */ 6 B/ v$ o; o9 s/ n! k
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断" b7 E8 s+ ?  p, `
  29. }
    " k' o/ `# ~" L- S5 I' Z

  30. ' Z( l' O0 c+ d

  31. 9 M7 u+ k3 r4 G' u9 j2 M$ U& u$ m, E
  32. //接收数据缓冲器0 |: |/ e3 ^6 O+ E4 u
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.9 q  h' n6 j7 J
  34. //接收标志位
    3 n# @+ \' R; }9 l5 M' o# t
  35. u8 Rx_flag=0;3 I8 s# F4 ]2 B4 g& F
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    $ b& L; ~! p( V& A1 h
  37. void USB_LP_CAN1_RX0_IRQHandler(void); W3 R7 {, l' r. y
  38. {
    1 o& x! X' v* q8 s- n  ]
  39.     u8 i=0;* }0 a/ f% C4 F; M3 e- l
  40.     CanRxMsg RxMessage;
    / P. R/ G* x4 v+ l
  41. 0 `6 d$ |3 @/ ^/ O5 ^& o! O# k# h
  42. 2 W/ g3 t  S2 U
  43.     RxMessage.StdId=0x00;
      R; V* i9 ^1 Y4 n* G: o
  44.     RxMessage.ExtId=0x00;
    , m1 f  ?% o' Y7 [) u6 `
  45.     RxMessage.IDE=0;* M1 f: ?& C6 V# j
  46.     RxMessage.DLC=0;, Z; e! b6 W* f; h: W( ?  @
  47.     RxMessage.FMI=0;+ ^; |4 j8 B& i- S
  48. 3 S. |, ?7 s9 `* v5 _; {6 e7 g
  49. 1 ~* a. P2 {; z- G/ H
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  # {6 a6 U/ U/ I  y0 X/ U$ W
  51. 1 U2 S- x8 @7 e: K+ b7 m
  52. - o; I2 s, Z4 U! G& ]
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空8 g0 z) I; X+ U9 L- {2 `+ n7 n
  54.     {! b1 e# T8 c, o; D
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    ! x, e" l  x# D7 D4 Y' e$ q- ~# e
  56.         {; ~' j: D# d$ b9 }% _  |, H
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];
    . H% d& \: h7 |* _1 g  H- p2 G
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     / g* }) F9 X/ r6 r0 `
  59.         }
    - X4 ]. r2 [9 r- J+ ~# |) z  T
  60.     }
    ' u: U9 p2 t* O) x

  61. ' n( _6 M+ L7 I8 f

  62. 6 [4 |( Z6 s* h; u" l) B* S8 s
  63. } - O6 A! H- n1 G. ?, p$ d% Z

  64. 9 @" Q  `' r1 W: g) N
  65. % k, z5 y, h/ e( }! Q7 a% o6 C: T. Z
  66. /* 发送两个字节的数据*/2 H" F; c9 ~' H# `/ {0 y0 ?5 d7 @
  67. u8 CAN_SendMsg(u8* data1, u8* data2)
    % p1 o) B2 {/ M- w$ s, l4 e
  68. {
    5 T& T9 \, O- C& ^1 n6 [1 s6 z
  69.     u8 mbox;# R6 d2 u: e- c4 F7 E
  70.     u16 i=0; 7 R4 a, q4 b' F! w" W- s8 ^$ c
  71.     CanTxMsg TxMessage;  
    6 D6 P4 }9 [/ I+ A/ Y8 p, D" k

  72. ; F8 F- q& M8 W5 d1 {1 c$ i. G
  73. 5 j* |% ?- g- K) J' g" _+ f+ n* v
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    5 I6 z5 M, c% D" r' ~& _
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    ( B" f! @( X0 X+ H; k# I: \8 k/ H
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符# e8 @/ h. w: k
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    $ F' [# \" D) o' k# _% F
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节0 l8 z' ^. C$ g. g
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据  q9 z8 s2 S1 R+ a; m
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据 2 p& q! \+ v' @3 i
  81. 4 [' h" m( \7 y$ ~! ~
  82. - V+ \) @7 }& Y) n! r8 A
  83.     //发送数据
    4 ]6 S# @1 y* x" F4 \" ]. F4 C$ t
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  
    9 o0 X! \7 C& q8 y& V
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)). I, l* x: s1 X5 K. j! [
  86.         i++;    //等待发送结束
    ( o0 Q5 w2 I6 L; f( C# Z2 b
  87.     if(i>=0XFFF)0 V8 |( X1 N4 O. C
  88.         return 0;//发送失败4 s: z- @( q& ?+ Z0 K* @/ m: _! \
  89.     return 1;//发送成功
    3 N. v/ n+ v  t: y9 q8 Z$ }
  90. }" N* ]. {" t( m+ B( {/ A
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    + k, I5 F% D6 x) S
  92. {( Q- y' H6 o% z3 x4 J7 n: [$ ]
  93.     if(Rx_flag == 1)//发现数据: a5 J& a8 e% S( r6 n
  94.     {( d4 N6 V* s$ \# U/ N/ G& I
  95.         *msg1=CAN_RX_BUF[0];
    % G2 N) o" H, u. L. a% k, |
  96.         *msg2=CAN_RX_BUF[1];& G3 i1 j# b  N
  97.         Rx_flag=0;//数据已经取走,可以更新数据8 d0 d( x$ n3 o4 J* d* h$ F
  98.         return 1;
    9 U4 J: ]2 K) a
  99.     }else: M5 P. A4 n( x9 X2 Y9 g
  100.         return 0;
    : r5 c. _1 ]! B$ V* N
  101. }
    5 W2 Y- l3 U3 i& M# I& I1 _2 g
  102. void Clear_canBuffer(void)
    3 J5 Y! |; x) e& i
  103. {
    * Y9 ^# e) ^' ^! e
  104.     Rx_flag=0;//清楚接收标志位
    6 m8 v7 K7 T6 P  F6 a
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区) l2 ]+ V5 F$ `# U. V. }
  106. }
    * F- P, E3 U$ O% C8 n! C4 V% M
  107. u8 Check_canRX(void)
    ( l: D" N4 Q  L" {
  108. {0 ?1 x0 V1 c* G
  109.     return (Rx_flag == 6);/ q+ K2 @  g+ p" k+ O# b
  110. }
复制代码
9 J: R5 C0 r4 F/ ~+ q
can.h文件:

  1. 1 e& n, _3 j. V/ I
  2. #ifndef __CAN_H
    ( S9 D7 J: B8 _" O; d/ x
  3. #define __CAN_H
    ' x  V5 N. x- s4 S$ x2 i' g
  4. ! V! m( f0 W4 t2 y& X- G+ M2 I: b7 X
  5. - U  Q* J+ B) X' q
  6. #include "sys.h"
    * r+ s) _7 u1 o; M! g
  7. #include "string.h"! j; x, o9 L2 f/ f( l8 _! K

  8. ! `0 \9 I1 m; Y/ e1 y

  9. 3 ]& ?* [2 G; r' O+ m
  10. #define CAN_RX_LEN          30          //定义最大接收字节数 1 ?: \0 R2 |0 ]# w# E9 E5 F% B2 \: s

  11. 7 J. N7 i8 j/ G1 i4 J2 `- @
  12. , B9 v' g# B) Z: {
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 : z* _7 W# _9 f7 q' {

  14. * x& M; c+ G9 z# A
  15. $ `# M0 I6 F- `  p
  16. void CAN1_Init(void);
    8 G6 E' O: n3 a" W' |3 I% }$ w! P
  17. u8 CAN_SendMsg(u8* data1, u8* data2);
    . S# c) h/ k% [& N! s3 C% |$ v3 ~
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);) F8 W$ {, O1 r7 x4 X$ C! Q
  19.   h) N$ {) i  H, `- S+ M0 O! ?4 i

  20. 6 F& f* J# j6 y0 y1 I9 [6 J
  21. #endif /* __CAN_H */
复制代码

7 W6 i4 z+ l' a6 ~& d8 b  P
赞 收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版