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

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

[复制链接]
STMCU小助手 发布时间:2022-6-7 10:05
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
}2%6MKU]I@$GZ9X6S6IVP$L.png
$ ^1 k' Z* s5 k/ y0 `. x$ p
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧# {  ~( |* i) m* r. h7 V
  • 摇控帧
    / x/ k# D& y) ^" a  S& ]; _
  • 错误帧; m7 f  a& @! X4 N, w& y) l/ ]
  • 过载帧
    , \5 [1 \& d, W! c) E# c+ ~
  • 帧间隔

    " H* U0 d% R' m! d9 K
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。) L5 Y1 }5 W# z7 U6 f: u
    数据帧一般由7个段构成,即:
; Y5 Q! q3 t( d(1) 帧起始。表示数据帧开始的段。& |8 K, X0 K( @$ |( H
(2) 仲裁段。表示该帧优先级的段。$ i( D+ f# g8 D( M6 ]) Z
(3) 控制段。表示数据的字节数及保留位的段。8 t( ?: o5 U" E5 t9 F% |
(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。  o6 r6 ]; S( H
(5) CRC段。检查帧的传输错误的段。0 [4 P* ~5 `* }% J; L; Q; r
(6) ACK段。表示确认正常接收的段。
. P. O6 u3 e* b4 l& y, r8 N(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
+ [6 v8 ^1 l0 Q    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

    " n4 x! |- P0 [1 c$ ^( T' ?
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
- r3 o. j6 n5 X2 t. l    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
+ J3 K( l9 U5 k9 K& [  Z
IDZ(%0[HG8QC`YFQM3K90ZL.png

/ A+ _4 ^3 E& M& z
" c9 O- J, Y2 _, w! F
    在程序中就是:
  1. //要过滤的ID高位
    & C# Y# T+ K5 j2 f
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  ) z# d) Q) `3 W* S( m, e
  3. //要过滤的ID低位                 % O# v5 x, n4 j! f4 w
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
    $ J5 x+ d6 _5 u
  5. //过滤器屏蔽标识符的高16位值$ H4 A! w& ^1 J: U: H
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   
    : e+ z! Q7 z  j, t4 h# V6 e1 d. X
  7. //过滤器屏蔽标识符的低16位值         
    ) }) V/ @1 I" ~8 m5 G
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
/ i) [1 U! P/ H% ?
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
0 |1 |1 Y. l: Y4 G% y
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。

0 R* l! y. [  T# d& I! x
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:5 e0 k+ K4 y8 R. b  r0 }
主机:0x1314# _$ d- x9 K  C7 K
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
( x$ G1 w. z" K6 p5 y0 U7 Q
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
8 L  G) R* T: s( [; G2 Q- x7 F
从机相关代码
can.c文件:
  1. #include "can.h") @! e" h8 b/ D: x+ u
  2. 2 j" p1 z) F* w, W% E
  3. 3 c9 y  ?$ P& M- F8 @
  4. /* 在中断处理函数中返回 */
    " T! }$ e4 v& |4 p# B& n, x7 k
  5. //__IO uint32_t ret = 0;
    - T) a2 C$ E- n  a

  6. - X. R0 }) C( U7 T6 S0 g; x

  7. 0 K8 B4 t, T5 W/ Q' @( ]
  8. //接收数据缓冲器0 O" U% W3 S2 K4 o) M; y/ i4 o# U
  9. u8 RxBuf[5];
    & Z% n) P& `( n% e& ?' x
  10. u8 Rx_flag=0;% r* ]& b. G' D3 B; p* C

  11. 4 K9 H0 t, d/ f! s: o5 E8 Z0 m$ }' z

  12. " a, E& U8 R9 N9 s2 \) X+ @
  13. void CAN1_Init(void)3 }, e2 r/ E1 E1 u/ C: U! l7 _
  14. {
    - m% n( L7 x% {" w/ e
  15.     GPIO_InitTypeDef GPIO_InitStructure;
    - a9 p# ^7 v+ c$ @# R7 y8 |
  16.     NVIC_InitTypeDef NVIC_InitStructure;
    3 v4 S# K$ z9 F' V! U3 w3 v
  17.     CAN_InitTypeDef        CAN_InitStructure;" G% S# b# m7 T
  18.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;$ p4 C6 P9 l" G
  19. , T, m9 N) O: C: G
  20. ( g; Y5 A( |6 q
  21.     /* 复用功能和GPIOB端口时钟使能*/      I/ x$ X7 U# E3 k2 }' r
  22.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     
    6 v9 x  N8 |' `& F

  23. ( p" c& f& p& ]2 x& M9 \7 L

  24. 7 T4 v7 o% }! i2 ^3 i0 E- [: O
  25.     /* CAN1 模块时钟使能 *// h" x  f+ J1 ~8 N
  26.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); 6 q7 {) m* X0 S5 G# W, A
  27. 1 ]0 M( x. }) c: c! T, f

  28. ! W9 F' v5 n. Y4 ]6 F! m. ]
  29.     /* Configure CAN pin: RX */  // PB8
    7 s0 X$ R  W6 A* S  b" o5 m/ Q
  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    ; }2 ]6 \- ~: Q2 x& a
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入. n0 S" R) J5 i; B/ {
  32.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    . a3 a  @1 a( z7 C% j
  33. 3 G) w4 J# |5 C) Y2 W
  34. 8 a$ j  B- Q- P3 ?3 k9 b
  35.     /* Configure CAN pin: TX */   // PB9
    ; Z5 l  t% d+ I5 W0 T1 y
  36.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    0 N1 y9 x" [- G/ r2 R# y
  37.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出
    ' g1 m; e$ z8 \" a1 `
  38.     GPIO_Init(GPIOB, &GPIO_InitStructure);3 B' O4 ]+ x% t, i
  39. & |$ T: T) C7 W6 {+ e% o

  40. ! g7 o7 d# w: V  R- C
  41.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O# ^2 ^* ]; y- F) U) U$ w# K
  42.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    6 E* u& V4 L) t; y! O
  43. # Z% S8 J0 g8 W1 w& Z3 |- X/ T
  44. . V& C5 J1 g" m* x# e" V
  45.     //CAN_NVIC_Configuration(); //CAN中断初始化   
    % G: i$ \( g+ \% v2 ?5 S
  46.     /* Configure the NVIC Preemption Priority Bits */  + T  W, @% z1 l% c
  47.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    3 v2 w/ `6 Y3 ?

  48. # `+ N! c1 c1 Q* Y' [9 k
  49. 9 e5 U& y. V2 ?9 ^  S, |
  50.     #ifdef  VECT_TAB_RAM  1 {9 `- E$ W3 M% H+ D8 `
  51.       /* Set the Vector Table base location at 0x20000000 */ 7 G8 T+ z2 R. v' V
  52.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
    : j' c  {# q% y$ A( m
  53.     #else  /* VECT_TAB_FLASH  */
    * w& y9 \' q/ L% ~7 E% ?# a
  54.       /* Set the Vector Table base location at 0x08000000 */
    4 `! N1 `( J% N0 ]2 W$ q
  55.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
    3 c! H# l$ Z# N. i
  56.     #endif
    ; Q$ W/ |! O0 M) N# F- ]" h
  57. 8 |+ R+ m- e" R7 D( c. a

  58. - M$ C, T& e  y
  59.     /* enabling interrupt */# v4 I9 j, u, Q, b5 C/ M
  60.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;) l7 V- W3 l: G5 n5 L! Z; ?8 G
  61.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    ) o  e, D, g4 }* I0 y3 ~; a- ^
  62.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    0 z6 K' I; K  l! E
  63.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    & E" }4 s8 H1 x* n% \: t# m
  64.     NVIC_Init(&NVIC_InitStructure);
    / s5 i, ?7 P. R4 d! p3 G
  65. & k4 M- t% P/ V2 W+ h
  66. 8 U) b) _& a9 t- t
  67.     //CAN_INIT();//CA初始化N模块
    4 n* s1 d! B9 G9 ~' y# @
  68.     /* CAN register init */5 V9 {) q2 C% Z; B6 l
  69.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值; Z7 v* h3 G+ n1 p
  70.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    5 M# X. s" `2 ~) m, \; a0 z
  71. * v4 x; N: o8 o* c' F# {
  72. ) @# t, ?# ?: l1 D$ g6 [& V4 n
  73.     /* CAN cell init */5 t1 K; x) L8 q4 @1 V- V
  74.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式* H: Q" |; ~, `8 b0 R7 g
  75.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理. S5 A& N4 k7 M- @
  76.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式. O6 z% B6 C0 k# _$ N8 Y' y" c, H
  77.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式' O1 O% Y0 n' p
  78.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式4 g5 \3 g& m1 l* N* ^
  79.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级* s& a- N2 `/ ?
  80.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式( `. n) d! \$ ]' Q4 k8 }
  81.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位
    ; E$ V; g5 Q0 R7 J; }
  82.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位* y: J+ D3 l2 Z' I4 a, {
  83.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位, V# v& Z$ B) n0 R# Q. d
  84.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60 $ |& J' R) N5 @1 u" s
  85.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs
    & I2 F: w7 Q4 {7 `( z

  86. - _0 ~4 R9 i6 I: \* O
  87. 3 Q' }7 _: k2 }2 i
  88.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据7 F3 h; {+ m; K) W6 r
  89.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    % ]% a1 K% ?7 ]" ~) a$ Y$ A
  90.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    6 f5 Y1 M- z+ a: @# h
  91.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位  n# N8 Y, Q% ]2 P: v2 L

  92. 7 Y1 G' f! ]6 }8 K2 [

  93. 0 T+ s% K3 F( i
  94.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  + O( [& ?0 i! y, v3 k- \& ~
  95.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位 . F5 l! [- d" a) p
  96.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位 - Q) @, [1 `, Z+ [2 O- ?7 j

  97. 8 u  j9 {2 d5 e- r
  98. 6 E* R4 R1 a7 F  m# _3 r9 U  [
  99.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值
    ) k1 N& J+ G3 p! H5 E: ^
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值; e1 s+ _" M/ i* M0 x) U, d
  101.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    , `4 J4 u+ [. i
  102.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器- [, _: Z7 U' \5 S, v# U# p
  103.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器& Y9 v; u: o# t; i. w" f; i  c5 E

  104. ) r8 q2 Z7 A1 [, S6 G8 H
  105. 0 O- l8 x6 ~2 [" Z
  106.     /* CAN FIFO0 message pending interrupt enable */
    ) V$ T* [" L: X0 Z' G$ k4 u3 M
  107.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断( H5 r* T7 `+ Y! Z+ Z
  108. }
    4 R! H9 n$ l0 q* ~. t1 b; t" U
  109. $ J" i3 O1 j/ q  ]: K

  110. - \; T7 e8 Z" [% O- |
  111. /* 发送两个字节的数据*/( A( l0 [8 S& T2 x2 i% S% `) L; b9 x
  112. u8 CAN_SetMsg(u8 Data1,u8 Data2)- P  k! M6 H) g0 x
  113. {
    ; s' r, d. I$ x/ A! f4 v* c
  114.     u8 mbox;" ]1 G% d6 B- u" \! d: F
  115.     u16 i=0; 0 E5 W# s) q# a+ X
  116.     CanTxMsg TxMessage;  
    5 H6 m, t7 g+ N: t8 z+ B! K
  117. 2 c) n$ U' x* ~# ~
  118. ' j' u9 [. n% r, Z
  119.     TxMessage.StdId=0x0000;     //标准标识符为0x00% D% m) L: D# `4 K0 x+ R
  120.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机4 g% f- }1 \: r( b. U8 K( ?  M
  121.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符: Q5 i2 X+ |$ o9 M+ k& T
  122.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧4 z! F& ~$ P& x5 H7 U
  123.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    & k9 A4 _& K* R9 b6 L4 Z
  124.     TxMessage.Data[0]=Data1;    //第一个字节数据
    / C9 z; M) Q  S5 b& Y) v
  125.     TxMessage.Data[1]=Data2;    //第二个字节数据
    % m# o% v" c% w# k8 Z8 n
  126.   o* m. P! B  x9 a% k  j" Q* y
  127. # g8 |% Q6 W+ b9 `
  128.     //发送数据
    2 x; {2 V5 |5 W/ }4 L. `. d
  129.     mbox= CAN_Transmit(CAN1, &TxMessage);  - f& y$ [; w' y+ E& z: g( v( R
  130.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))+ j/ b3 {, B' G8 s
  131.         i++;    //等待发送结束' `% \: I. i" j% i6 N5 y4 g
  132.     if(i>=0XFFF)* R. y0 N5 p: ]" B0 ~3 g+ D/ j
  133.         return 0;2 t. v% u- H2 ]' j
  134.     return 1;3 L) J- C: j. t& z" v( ]8 {
  135. }5 [- }. _7 n! b' e3 I
  136. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)/ c1 j6 [  l) m3 a1 y% F+ S4 }, o4 J: V
  137. {7 K/ @9 }+ n- s0 v! y
  138.     if(Rx_flag == 1)//发现数据& M! V( p) e& t" C( \
  139.     {- L5 w' _7 ~/ W3 u
  140.         *msg1=RxBuf[0];/ |* i% n- S/ p3 E
  141.         *msg2=RxBuf[1];# j" S- {/ ~5 Y2 K$ `+ M
  142.         Rx_flag=0;//数据已经取走,可以更新数据9 T' J# [: |% e4 i* e- _
  143.         return 1;
    + w( F" o+ K' Q2 P% ^3 F5 a! ]" J
  144.     }else3 H2 A( [8 R& E: e2 k9 S+ I4 v
  145.         return 0;
      j( }. i8 C8 v
  146. }
    " E' g, _. G4 J
  147. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    1 [/ B  K$ b: ?9 L4 T; \) j
  148. void USB_LP_CAN1_RX0_IRQHandler(void)
    9 B- `2 C+ z' Y9 c$ Q7 k5 c
  149. {; {. K2 R" N0 d" f) O  @( {3 R
  150.   A  f" L9 i* b( w2 Q

  151. ; v1 P* U( b) ^/ b7 n; O' v3 M9 D
  152.   CanRxMsg RxMessage;2 ~: J  z5 @; X! h7 Y: ?

  153. ' [, p3 \2 }. C
  154. . w" B/ {( n  T) t- a6 n9 r
  155.   RxMessage.StdId=0x00;1 H& E! o2 ?& D6 v* \1 I
  156.   RxMessage.ExtId=0x00;
    & r6 I* X, V1 K, V. @! |
  157.   RxMessage.IDE=0;
    9 `' B- m, |. B: c7 ?6 o3 Z
  158.   RxMessage.DLC=0;& N3 p# |* p7 [7 r7 D& w: p
  159.   RxMessage.FMI=0;: F! r& x2 V# V4 p% z* }; `
  160.   RxMessage.Data[0]=0x00;
    0 @* P+ E0 D1 m9 U( y) r
  161.   RxMessage.Data[1]=0x00;      B; l: w: V0 e5 s; S* s

  162. % e! d2 r0 ]/ A8 K
  163.   h* S& B* w+ Y5 `7 W% J! L
  164.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  $ j' s. }) c) v$ F3 r: [
  165. & p" \! _. F: n% N+ O! E, r

  166. . G( ~7 y. D4 a; v
  167.   if(Rx_flag == 0)//数据已取走或者缓冲器为空8 q' ]7 e& z5 I" |- z
  168.     {
    5 \- V( }  T8 b, Y' }" n
  169.         RxBuf[0]=RxMessage.Data[0];
    ! L! ^' ^# g9 H; f  R% t
  170.         RxBuf[1]=RxMessage.Data[1];0 k, }- I8 K8 }7 w5 x
  171.         Rx_flag=1;//数据已经备好,等待取走
    : r0 ^5 u" @- t  E; ~& u
  172.     }1 Z. ~9 m- _- C8 j& S
  173. 0 v/ {" j. F3 w9 L- i4 |

  174. 2 e# s' T# A7 d7 X$ A
  175. }
复制代码

. Y: s9 {- L, e( N! _
can.h文件
  1. #ifndef __CAN_H
    : Y  k; Q, M" A; w1 e
  2. #define __CAN_H
    - Z0 X3 Y, @4 q2 A3 Q4 z# x

  3. 0 \" o, i0 p! |; l" S; V
  4. / h) G: C* j( _8 s& ~
  5. #include "sys.h"5 a  ^; d& d8 O$ J% c! F
  6. 8 M# j: I1 [( \$ a4 l
  7. - }; r1 v' ^$ a8 o1 h8 T& a" O
  8. void CAN1_Init(void);
    5 N5 R/ L# l" L9 ~9 s5 G( S( s! H
  9. u8 CAN_SetMsg(u8 Data1,u8 Data2);
    1 L( j* {  Z/ ?
  10. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);2 e6 _( z: O% x4 g" b
  11. & W) J5 I) z1 U. M% i

  12. & p, b* K+ R7 @) t: \5 ?; Y* v
  13. #endif /* __CAN_H */
复制代码
3 j! h1 ^  \8 @" n

& e& I9 I% M. f主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
1 ~7 c; C2 h( Q. |can.c文件:
  1. #include "can.h". k) q$ x! R9 a& o) ^
  2. , E# ^1 H/ z+ {

  3. 8 W9 y5 w: ?/ ^: U. S8 d. O
  4. /* 在中断处理函数中返回 */
    5 b( K' N1 }9 G' l" ?" |+ b+ W& F
  5. //__IO uint32_t ret = 0;* W& k$ x6 P- Y: c0 Y( A: t. c
  6. 5 f% G) b, u8 s! P/ G
  7. 2 U; \( E7 d7 b) c' [' X
  8. void CAN1_Init(void)
    6 D: V4 w% E( @9 U- z; K
  9. {& K, `0 `; I$ m$ E5 n" I
  10.     ......//以上与从机部分相同
    / c8 K! e4 j' C- {  \* C5 T

  11. . D5 n# w. ^% r% O8 F" J
  12. ( H2 [5 i, M1 ~! J/ m7 U' z# X
  13.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号& t8 h1 f# t* R# S5 v$ A2 ]
  14.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1
    ) D# r  E% A  |
  15.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    - J! t( x2 x2 l* M, o
  16.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位2 ]9 V' q- {; g7 k5 K8 Q3 K+ K' A
  17.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    / Y0 R* d3 e' Q# V
  18.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    , u; Q7 f: y$ V) f0 P
  19.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值. V" i8 l2 z6 m4 T/ C' B, D2 E
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值2 ]+ |5 t, v; {3 ~7 Q6 n0 @  L' n6 h
  21.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    8 m/ e' v. p! D! K# e
  22.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器
    / Z9 Y* D  p8 }: k/ Y1 b0 m& Q* ?
  23.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    1 K( r" i+ e; p5 N4 z

  24. 3 S" A. R+ L6 F. J' Y
  25. 1 u. V) T* {$ C2 c
  26.     /* CAN FIFO0 message pending interrupt enable */
    ! [& N8 o; L/ M* I
  27.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断0 \9 K. b1 W! W4 I! p5 w
  28. }1 b1 l) C' B2 z0 G

  29. & F. J: |( R( {; W$ g

  30.   d3 v( _! `: V6 b
  31. //接收数据缓冲器% s0 h( V$ ~5 Q' c* w3 Y
  32. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    " u9 m6 ]" u! `& a' z( p
  33. //接收标志位2 _- x; v! R) H) H2 {" J1 m" p
  34. u8 Rx_flag=0;
    2 {* |6 ~$ x6 z
  35. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    & o% x9 L+ M5 {% c
  36. void USB_LP_CAN1_RX0_IRQHandler(void)
    4 e/ U/ Q, ]) o" k4 a; o
  37. {
    & L$ e" P' [8 j7 u( c3 ?: L; x8 w
  38.     u8 i=0;
    1 L3 e( A( S1 y& U' @- d+ H
  39.     CanRxMsg RxMessage;
    - [7 ]2 Z0 i. b2 Z

  40. ) p. v% T0 ]* \4 J/ Q
  41. 6 f  ?. h6 k! A5 P* @( H' [% B( K
  42.     RxMessage.StdId=0x00;$ d. Z! l+ c& J1 G$ c
  43.     RxMessage.ExtId=0x00;6 ~' ~; w2 a. I0 S' \
  44.     RxMessage.IDE=0;: m4 z! c1 G; {& U6 V- q) |. g7 K5 B; ^
  45.     RxMessage.DLC=0;8 ~; O* K8 ~# b$ A0 V
  46.     RxMessage.FMI=0;) O" X4 o6 q+ ~) F7 v& ]# T2 d" U+ K
  47. ' m- u, q1 S6 L3 L

  48.   K7 y+ g- ^) q
  49.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  & r) ~0 {5 L1 ~& ^: H3 U2 Y9 ^

  50. 2 K: N! }5 Z# a3 u" O: t) l  {1 r
  51. 2 _: v# k$ b: ~( b) a
  52.     if(Rx_flag == 0)//数据已取走或者缓冲器为空  j9 j6 R; G% g1 k! E5 n) y. ?# h
  53.     {
    5 F* Y; f* I6 E# t7 n
  54.         if((RxMessage.DLC) == 2)//是否收到2位字节数据/ }: @& \! w3 E3 N* ]
  55.         {/ ?2 q( [  C0 T$ x8 x9 g8 z0 ?
  56.              CAN_RX_BUF[0]=RxMessage.Data[0];4 K. _; C9 v% g+ g* G! X4 W% L. [
  57.              CAN_RX_BUF[1]=RxMessage.Data[1];     8 G3 s8 {5 y+ C5 \
  58.         }
    $ H& S8 `. C- g, w
  59.     }+ a2 C. V9 `/ J0 G$ `; g& c

  60. * f3 @  a1 v1 s* J- j) Z# h6 w3 [3 G
  61. , a" |5 G; q$ i, m& C* m& |$ P
  62. } : c/ j/ w' U0 k' H" H4 B5 V5 p

  63. : N2 q. l9 J1 B. e. l/ d, p# D
  64. 2 A! F0 g+ {! I* l! ]3 N: s
  65. /* 发送两个字节的数据*/3 s7 ~( L# s% E/ T! L7 \) l
  66. u8 CAN_SendMsg(u8* data1, u8* data2)
    # x$ M' d6 C4 r% R
  67. { . F& u* R6 u' Z' @; V
  68.     u8 mbox;$ w& \; V! e1 d
  69.     u16 i=0; % ?, Y% z+ d6 ]+ @: ?: R) U  Q
  70.     CanTxMsg TxMessage;  
      z2 f6 v  R" W& x" @" G" y
  71. , m# [1 g9 \$ q7 B/ @: @; m

  72. 9 j9 N, {" f1 I: s
  73.     TxMessage.StdId=0x0000;     //标准标识符为0x00
    ' y) [! o( c; p
  74.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000
    6 u: H& Q6 C3 S, t7 w' Q
  75.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符) l$ n, ]: x# R7 i$ C. p# C
  76.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧' u- \0 g) n, ?$ e7 E
  77.     TxMessage.DLC=2;            //消息的数据长度为2个字节, }9 H& h2 W7 P: ?* b$ R
  78.     TxMessage.Data[0]=Data1;    //第一个字节数据
    $ d0 {8 U% `  g( [$ z
  79.     TxMessage.Data[1]=Data2;    //第二个字节数据 6 V! k& O! e; Q  U
  80. 4 `4 n8 B) u9 b9 |7 J6 a3 z3 r

  81. 1 C5 ?% B, i2 y3 u7 ~" g3 s; i
  82.     //发送数据4 l) B* T( t& q1 t; L/ @
  83.     mbox= CAN_Transmit(CAN1, &TxMessage);  ) d- \7 |# F1 q% k7 s  C
  84.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))' z* b' d9 g: Q+ v4 G1 \6 N
  85.         i++;    //等待发送结束6 S! Q* s7 Z0 k# a
  86.     if(i>=0XFFF)
    1 s" {. B8 k$ e" z* q. J" P
  87.         return 0;//发送失败
    ) \3 c) q) S, Z8 G
  88.     return 1;//发送成功
    : n0 p9 S; X2 j9 V1 N3 \+ w
  89. }
    4 C8 [  V4 l) B
  90. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
    # a( k  Y; n/ I# ^: I
  91. {
    5 v# z! `1 w! \7 I" L
  92.     if(Rx_flag == 1)//发现数据
    & c$ Y$ m: r: [; ?
  93.     {- ^1 _) B2 I8 H8 n% N) a2 |
  94.         *msg1=CAN_RX_BUF[0];
    ; ~1 o2 ]1 X# ?$ ?' Z0 n/ ~$ f
  95.         *msg2=CAN_RX_BUF[1];. ~% \1 F, R9 K6 K" k3 [
  96.         Rx_flag=0;//数据已经取走,可以更新数据) U# i9 D1 v" }' C  K8 p; ^
  97.         return 1;
    # h3 F8 k  s! U7 t4 t+ y
  98.     }else3 |0 j4 [% G1 g9 U
  99.         return 0;( C3 b# f6 a3 b; {& S8 s0 `6 l
  100. }
    7 j6 `) q* W2 x- y4 l3 E8 S6 H9 [$ n
  101. void Clear_canBuffer(void)
    " N0 |3 N7 K. |& r  J& H/ P
  102. {; o9 u! m" L- t8 O, o9 y& _
  103.     Rx_flag=0;//清楚接收标志位# X7 w9 }' W* d+ O
  104.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区1 S5 C2 x3 i3 j! F! @$ }$ d4 X
  105. }
    ( }# {/ X$ ^' I# S
  106. u8 Check_canRX(void)
    * P. y; N5 k( }+ o( Z" F7 R& S
  107. {! R2 x0 ^- C  ^, v6 W4 Y& f
  108.     return (Rx_flag == 6);
    9 k% b+ F. F- r6 A7 N. }
  109. }
复制代码
' r9 s! q5 H7 k" g
can.h文件:
" f0 }: ?, _- H7 V5 g
  1. #ifndef __CAN_H
    5 ~3 b& B: c4 U! x$ Y+ q
  2. #define __CAN_H
    3 f) X0 ?! c  c9 g( ~+ L% i

  3. + r8 Q: p5 L' V0 E1 X
  4. 1 u* y# j3 X% `
  5. #include "sys.h"
    $ a, q8 t( y; e
  6. #include "string.h"
    " M! m3 w9 U' T' Y  X' W0 k/ P' ?' n

  7. 3 a& x  J: z/ X! E1 B! i! r

  8.   I7 P& r4 V9 I/ g
  9. #define CAN_RX_LEN          30          //定义最大接收字节数 3 ^: ]6 x; ~/ s6 g8 U; d/ w: n
  10. 4 @& {3 x. i" ]# F, r6 s
  11. " y# f' t' F: ^" G5 q: v5 a
  12. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
    + H  }2 H/ o+ i
  13. 7 ]; ]$ {8 \7 H3 G6 ^

  14. # W$ {0 x7 r9 C
  15. void CAN1_Init(void);
    ( O! S% J& u5 @" M# B9 `! H( [; J
  16. u8 CAN_SendMsg(u8* data1, u8* data2);& t" r! e  z# e- q8 R6 |
  17. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);; v- t, |4 B7 ~& w0 G
  18. ) n# N0 [0 i5 g7 F, S

  19. 5 o% }  _# _1 X- ?2 g
  20. #endif /* __CAN_H */
复制代码
# Y( a" {& z" h6 d# p
: ?. S( j+ f3 H7 r
赞 收藏 1 评论0 发布时间:2022-6-7 10:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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