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

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

[复制链接]
STMCU小助手 发布时间:2021-11-7 15:31
CAN通信
    CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
)857N86HK1E0[0K2MXK36X3.png
    CAN协议是通过以下5种类型的帧进行的:
  • 数据帧
    & y2 p5 m2 k$ b) O5 N% n+ _6 c
  • 摇控帧4 I, T; H0 ^7 w
  • 错误帧; f& R; A2 ^3 {5 D, P: Q0 {$ ^
  • 过载帧: C) t* ^4 m0 H( Z' {) {% T6 O& t& q
  • 帧间隔

    ; ^/ ^6 w9 q# R8 d2 }. l
    另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
    大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。4 S+ C0 E* S! e9 Z* }* Y; B! r
    数据帧一般由7个段构成,即:; n; [% W7 L3 x* ~8 o; Q* A9 l" I
(1) 帧起始。表示数据帧开始的段。
) d' C2 J: g4 w, R(2) 仲裁段。表示该帧优先级的段。
5 u) [' j% ]: b  T: w0 h0 j1 |(3) 控制段。表示数据的字节数及保留位的段。
, b9 u8 l3 ~/ a! f7 t3 o(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。% G& s# F' }- q2 U# ]2 N# e
(5) CRC段。检查帧的传输错误的段。, \* m* x( D; q9 Z' V$ r4 Q2 V
(6) ACK段。表示确认正常接收的段。
0 I& v% O% Z+ w) j; \! A% @(7) 帧结束。表示数据帧结束的段。
    明确了数据帧概念,还需要理解一下过滤器的作用。
    STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
$ G( q' Y  K  H. G" h    STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  • 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
  • 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
    + Y, G' v5 {0 C3 U" I3 A1 H$ X" A
    此外过滤器可配置为,屏蔽位模式和标识符列表模式。
    在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
9 h- i1 U; i5 H( s& R+ G% I    而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解
    一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:$ R9 s1 U$ }. S; S: k+ h
PERMNQ{)L%G}{986WRA~Q]W.png
9 i$ a" J7 D0 I/ ^# u+ {
    在程序中就是:
  1. //要过滤的ID高位 : r8 \. `" K8 }: P3 r9 \
  2. CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;  + m% f$ z/ H6 B9 R- v7 @, T1 I. @
  3. //要过滤的ID低位                 . U: I) R( Z& b( I0 V, z
  4. CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; ( c6 j/ `: Z) R: t) [
  5. //过滤器屏蔽标识符的高16位值/ e6 Y' |) H' m# ~2 x# t
  6. CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;   3 _/ X0 E5 i1 C! I
  7. //过滤器屏蔽标识符的低16位值         4 g6 _4 V6 l- P5 M' j5 R3 ]
  8. CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码

' C2 E5 l; ~* P2 s; j4 U6 `
    这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
# |9 L* x* q" U- J# a$ [5 T5 K" w
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
程序思路
    这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:  l6 R: F2 m8 W" r9 v6 h
主机:0x1314% ^1 l* |0 K. e- _) h; T
从机:0x1311
    主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。
相关代码
    代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
从机相关代码
can.c文件:
  1. ; n% `3 `& {% N$ l. Y* `* p( N
  2. #include "can.h"7 i! b7 A" s. o3 F

  3. $ z/ i# E3 O. N/ P% w

  4. , q  |( I) Y, O  R1 P$ I( n' n
  5. /* 在中断处理函数中返回 *// s& h/ D7 Q9 h$ Y; m
  6. //__IO uint32_t ret = 0;
    3 Q2 s0 j& Q  m' Q) A5 C+ V: |" H

  7. ) i0 o! n& z% Z& b# G) ]0 h
  8. 2 R" Q/ p& P( c! c4 s0 U. P
  9. //接收数据缓冲器- p" q! Z7 x9 p7 W' k# E1 T
  10. u8 RxBuf[5];
    4 V0 o# C! z2 L# T2 d* `
  11. u8 Rx_flag=0;
    ' D5 L" G% C2 O* q; ^, R

  12. ! I  L8 e: f+ a& B
  13. ; x9 J4 C: U$ _
  14. void CAN1_Init(void)
    / ^  h; X$ Z1 D
  15. {1 C- s: y! E7 g3 G" g, [6 {
  16.     GPIO_InitTypeDef GPIO_InitStructure;
    , `: m1 M, K: z
  17.     NVIC_InitTypeDef NVIC_InitStructure;1 u. v' x- k% O( a+ R2 {9 m% N) _
  18.     CAN_InitTypeDef        CAN_InitStructure;
      L. c# I+ Z( K( `" w/ C& m- E/ N6 X
  19.     CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    2 C$ C( A4 W7 d
  20. $ X/ N2 C/ Q3 ?' Z6 Y8 a
  21.   t) l/ L# y% O1 {+ [# O8 T) \! U0 F6 W
  22.     /* 复用功能和GPIOB端口时钟使能*/   
    , S' h. ~- ~, _9 `# @. x" |
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                                                                     
    7 S$ l9 d: e) `& `7 w/ e
  24. 8 r& Y( c; W- R8 N0 s
  25. ) O8 k4 D- H0 P7 X$ q; [7 R
  26.     /* CAN1 模块时钟使能 */
    & ^' X9 t" n+ v  q/ @# y
  27.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); 5 @* X( N' W  ^9 e  o

  28. - B$ U+ Z% \: x5 @+ H6 f% R

  29. , M+ C- ?$ Y5 |; M' S5 W
  30.     /* Configure CAN pin: RX */  // PB8
    : c. G9 L& s; ^! S0 {
  31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;- I! h: K( W& C3 `2 J
  32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;       //上拉输入7 V  u3 ~, ~: y- b0 W
  33.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    : @7 F, v# `. Y1 \

  34. 1 S; W; Y2 x# U1 d, ]1 h

  35. 1 ~, U# P& R/ H8 S
  36.     /* Configure CAN pin: TX */   // PB9( ?7 x% E1 ~, m$ \6 Z
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    . R$ q/ h" q* {9 p, h% y% J
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     //复用推挽输出7 |0 D/ L, s: c5 O% |2 d
  39.     GPIO_Init(GPIOB, &GPIO_InitStructure);
    2 d5 x4 o4 e: ]8 {
  40. ! A- r( u; |; L
  41. ' k' l; T! \" a: `! L* T
  42.     //#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
    % B+ b' J+ X% y7 \. ?( ^, N( C
  43.     GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);# R! V, _0 j3 A2 A
  44. ! F4 u% u1 n2 k
  45. # l7 s$ l8 i, g2 N! F- s
  46.     //CAN_NVIC_Configuration(); //CAN中断初始化   4 d& Q" l5 ?% f3 `: J
  47.     /* Configure the NVIC Preemption Priority Bits */  ; W( ^/ c; @- a- y( y# H7 x% N) N* b
  48.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    * f! B! i# U* b5 P

  49. + F" K3 ]9 h  f+ _% N* F! N- ~! C

  50. % r% B( p+ B  c
  51.     #ifdef  VECT_TAB_RAM  
    8 [* R8 x7 Z$ f+ L$ z: M! K3 \. k
  52.       /* Set the Vector Table base location at 0x20000000 */
    $ ]  k! v* O% _& b5 Q
  53.       NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 1 a! C. W: ]1 ~+ s0 Q* K0 `
  54.     #else  /* VECT_TAB_FLASH  */# b; g' r, u- p
  55.       /* Set the Vector Table base location at 0x08000000 */
    " ~5 o& e9 P2 D! G# ~
  56.       NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   % R6 Z) a0 A- A, W. H
  57.     #endif8 `6 Y$ o$ ]8 E2 u
  58. 1 P% a; N& O3 G4 k

  59. ; c! b3 ]  k0 |' F# H: [4 J
  60.     /* enabling interrupt */
    ; g8 i, }: B+ o$ V3 k4 @
  61.     NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;+ M( U  L: k1 u3 c( R( z- x4 I4 g8 H
  62.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    1 @4 n" x+ D$ }2 ~7 {- B- O
  63.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    & H  N, A$ z. c3 ]
  64.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    5 X: f7 Z- j1 X# H8 _
  65.     NVIC_Init(&NVIC_InitStructure);2 q/ P* L; s0 C  [* ~

  66. 3 H) M0 j7 \( H* T2 x6 t5 V
  67. ) p% a# `8 G- C" c: `3 L7 w
  68.     //CAN_INIT();//CA初始化N模块 % i8 Q; ]; r& `2 a9 z
  69.     /* CAN register init */5 C+ r' a; W0 D
  70.     CAN_DeInit(CAN1);                       //将外设CAN的全部寄存器重设为缺省值4 U+ U$ C2 E/ E$ e" y. S
  71.     CAN_StructInit(&CAN_InitStructure);     //把CAN_InitStruct中的每一个参数按缺省值填入
    & C/ Y$ D3 e; m2 h6 D* N

  72. & n9 m9 U1 o) r1 x; J) B

  73.   w& T4 H9 F9 y2 B! R$ g0 G
  74.     /* CAN cell init */
    # Y0 W" g+ i1 X! f
  75.     CAN_InitStructure.CAN_TTCM=DISABLE;         //没有使能时间触发模式# B0 a) ?2 [; R  [+ p1 x/ T
  76.     CAN_InitStructure.CAN_ABOM=DISABLE;         //没有使能自动离线管理9 B2 Q5 L( R4 g. x
  77.     CAN_InitStructure.CAN_AWUM=DISABLE;         //没有使能自动唤醒模式6 o% T+ G* j- [- f
  78.     CAN_InitStructure.CAN_NART=DISABLE;         //没有使能非自动重传模式2 s" D+ g' F0 N, m  W4 K
  79.     CAN_InitStructure.CAN_RFLM=DISABLE;         //没有使能接收FIFO锁定模式. @* X* r- W% E: ?
  80.     CAN_InitStructure.CAN_TXFP=DISABLE;         //没有使能发送FIFO优先级
    9 u9 a8 A  @( X/ y; @( }
  81.     CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式1 ^* X- Z( G5 d
  82.     CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度1个时间单位4 G+ z/ B& o* W4 v. m  W3 X2 p
  83.     CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段1为3个时间单位- y8 @; K2 y3 {0 Y5 D# f
  84.     CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;      //时间段2为2个时间单位
    8 F% h1 M* |. ?2 _, W& q( R
  85.     CAN_InitStructure.CAN_Prescaler=60;         //时间单位长度为60 - K7 @) L+ c0 r; A% z, W
  86.     CAN_Init(CAN1,&CAN_InitStructure);          //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs# W2 x+ V; ]+ o& ]# w
  87. ! d3 A. U$ r$ S. e1 h' f

  88.   c0 H, t+ i: G9 F5 r. N4 N
  89.     // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
    ' c5 z4 u1 @% b& V5 ?
  90.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1, p5 S+ m7 R# k3 k; c
  91.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式% u9 u) q' I  Y& [) i
  92.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位) ~* `0 [& F/ r$ t. X2 U; o
  93. 6 Z: V, Y' k- w& X  V
  94. $ q4 p% P' t7 o; r3 l
  95.     //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16;  ( S1 o1 N6 b3 z* `& g+ f
  96.     CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;                  //要过滤的ID高位
    ! ?2 \- o& {" P
  97.     CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
    - ^$ P% r7 M4 J% W* x9 W. l% l, C

  98. ) E! j$ a/ c0 i
  99. ! X- X0 ~" _6 R+ h
  100.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;            //过滤器屏蔽标识符的高16位值6 P9 E: z1 S1 ^! w! T, p
  101.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;             //过滤器屏蔽标识符的低16位值  y* b3 q) @. D5 X& N2 A; o
  102.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    ) ?+ N  @$ a$ j; g
  103.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器  h8 J  c6 `8 g& z9 x
  104.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    0 q/ E' u+ o" S4 g3 Z: w6 C, M

  105. 0 c9 k5 i+ B- |/ J( d) c$ t' K3 D
  106. , m; B+ Z: b! O# v* X6 b
  107.     /* CAN FIFO0 message pending interrupt enable */ 3 f7 R# O; }2 d" o* V+ J0 |4 ]! o0 d
  108.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断
    8 x7 e( @$ H  m! ~3 d" r5 d
  109. }+ T* g: ?0 P' O; i# ?
  110. 6 g! j- I! Z7 Y( E

  111. " x4 T1 r! f  t1 e3 l" x( g
  112. /* 发送两个字节的数据*/- q$ e6 c& V! z, L
  113. u8 CAN_SetMsg(u8 Data1,u8 Data2)
    7 b" L  _$ F1 V2 _9 J" o/ R2 }
  114. { 5 \! |* T0 J5 w6 K$ C0 `
  115.     u8 mbox;, B- Y; r+ e* j5 A
  116.     u16 i=0;
    ( g/ h& u, f6 w( e$ P, v
  117.     CanTxMsg TxMessage;  
    $ @. q' C( s8 h& X

  118. " c, O1 N" b3 g
  119. ) Y) r, f( u' y0 e! a  S
  120.     TxMessage.StdId=0x0000;     //标准标识符为0x002 ~  V$ Y5 D1 R9 Z: I2 m8 n
  121.     TxMessage.ExtId=0x1311;     //扩展标识符0x1311,可以更改该标识符以示区分不同从机
    0 Q; \6 ?3 G; k$ T# K& @
  122.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    # Z. R* ]" c! m2 [, Z0 s1 c
  123.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    ) ?) a1 u( `" U$ F: V6 O# ~
  124.     TxMessage.DLC=2;            //消息的数据长度为2个字节' d% @9 L% O! n) N
  125.     TxMessage.Data[0]=Data1;    //第一个字节数据
    ) k# }2 z# H, b  T  t! ?* J
  126.     TxMessage.Data[1]=Data2;    //第二个字节数据
    2 W% ^* Y8 i) L, \+ ~
  127. $ ^7 R6 x/ o8 y# V: A* R

  128. . {* ]: Q, Q( p( r2 o
  129.     //发送数据1 i3 S, n8 v6 r4 @
  130.     mbox= CAN_Transmit(CAN1, &TxMessage);  0 l# R4 m7 f0 m  ]) v! p
  131.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))4 l) ~0 \. T- r
  132.         i++;    //等待发送结束
    * Z7 n, S  M# M" L$ `
  133.     if(i>=0XFFF)' O3 _! `5 x5 h; A! ^( U
  134.         return 0;
    $ Y( `, K5 }0 h$ p$ I9 H
  135.     return 1;5 b* T& Q. O. X
  136. }* a3 s6 @( I, y
  137. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)5 n: r$ O* C) d  s8 J/ f3 {- z
  138. {
    $ _' p% X$ C- g" C4 y
  139.     if(Rx_flag == 1)//发现数据
    2 n( q8 F$ Z+ A: N2 G
  140.     {
    $ b3 B1 b) J: a* N2 Y
  141.         *msg1=RxBuf[0];9 B& O2 l& T! I
  142.         *msg2=RxBuf[1];
    , v- {* O3 z) r4 Q# Q, q
  143.         Rx_flag=0;//数据已经取走,可以更新数据
    & m  S7 Y3 c+ v( S" _4 Q
  144.         return 1;+ j- C, K! R# p/ W7 ?
  145.     }else7 a# ^3 I' G# O3 T9 ~" ~
  146.         return 0;
    " G  X( B% {7 o  W! D' M  k
  147. }
    ( B9 B: N3 Q# C& ~
  148. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
    / r9 `3 y" A( V
  149. void USB_LP_CAN1_RX0_IRQHandler(void)
    7 T0 E: i+ O  l! R+ B8 _
  150. {
    6 \! U3 W. n& _4 |$ \7 ]% D# J
  151. 7 q) t  n7 g; ~
  152. 6 F1 _! l0 ]; Q' n# p, g- Y! c% T
  153.   CanRxMsg RxMessage;, G7 s# V. }: }: [+ f
  154. 3 z' s, M. b+ V; x

  155. # ^! z* C7 H: W/ J
  156.   RxMessage.StdId=0x00;/ P. B3 M( R6 x) t( G% {
  157.   RxMessage.ExtId=0x00;+ p: f* _! B  {! s% P3 T( w
  158.   RxMessage.IDE=0;
    6 |% C  k9 s2 L3 ~6 ]& h5 j
  159.   RxMessage.DLC=0;# R7 T3 r& G. ~9 p% u
  160.   RxMessage.FMI=0;
    ' @$ ~6 k  T! p$ O, z# x: q. b
  161.   RxMessage.Data[0]=0x00;" L: h5 Z( M: l* |
  162.   RxMessage.Data[1]=0x00;   
    8 m* W7 W0 m) `5 Q' d- L

  163.   }6 G1 W  y- _) E
  164. % C" O2 K( `, e. B
  165.   CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
    $ q" X% e3 H- g2 Z) t6 f

  166. 2 b& C( {" X$ l2 @9 Y! a

  167. 0 \+ |) g$ [. ?: N, O. P
  168.   if(Rx_flag == 0)//数据已取走或者缓冲器为空+ j! e3 l8 ?7 R
  169.     {
    $ z$ X7 d* d1 R* \
  170.         RxBuf[0]=RxMessage.Data[0];( X5 O1 ]1 h& U( S4 W. x
  171.         RxBuf[1]=RxMessage.Data[1];
    5 M4 v) y) [! }& n9 H( L' D+ n4 k
  172.         Rx_flag=1;//数据已经备好,等待取走. k9 w" @! `8 z5 p# r& [5 |
  173.     }
    ) l5 G0 d0 O' W6 ]4 t

  174. , A* x" S5 V% D7 ?: n* ^

  175. % g! F" W3 [" `3 O
  176. }
复制代码

! p* w/ i+ p$ A" O/ s. i7 |+ S
can.h文件
NQOI@[X5(~C{N5(@A93Y4.png
主机相关代码
    这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
7 u2 ]" y4 s8 Pcan.c文件:

  1. " u9 d" E6 H! u+ q" g  U
  2. #include "can.h"0 W+ u) p: i& u) M8 [# z5 g' q

  3. 5 K" b- u; G0 Z  g: a2 ~# d
  4. 5 r# S$ {7 K1 w+ h5 T: r$ s  M  j
  5. /* 在中断处理函数中返回 */+ R  x: A! t" K
  6. //__IO uint32_t ret = 0;0 }1 N" m* X6 Q& V/ J* W$ i

  7. + E( x9 U; E3 f
  8. $ g, i/ H* \2 {& o
  9. void CAN1_Init(void)
      \, d# R  c9 ~$ y: J
  10. {
    * j0 M" v$ ^5 [! v" \7 j
  11.     ......//以上与从机部分相同
    ' d$ y* j2 w4 P& G
  12. 7 {; [* F+ d4 `7 b2 m- N
  13. / [6 A* B$ Q6 G& @. V" h
  14.     //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号
    8 @: m! Z* u9 ~" j/ A. O9 a/ t
  15.     CAN_FilterInitStructure.CAN_FilterNumber=1;                     //指定过滤器为1* B2 H" X$ s8 D1 B6 B
  16.     CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;   //指定过滤器为标识符屏蔽位模式
    7 g% M* @* \3 v' u- ^' u+ ~' J
  17.     CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //过滤器位宽为32位
    ' f4 W# h: i0 E( n
  18.     CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                //过滤器标识符的高16位值
    ; j) w1 v" x8 V
  19.     CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值
    4 C+ p  A, [( N! a4 F9 f! u
  20.     CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;            //过滤器屏蔽标识符的高16位值
    ' o% n% L$ `; f! ]% W# ]$ H9 h! T
  21.     CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;             //过滤器屏蔽标识符的低16位值: W" U, {& M5 d5 Q
  22.     CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;     //设定了指向过滤器的FIFO为0
    ; C0 M  x; R& p
  23.     CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;            //使能过滤器1 E( B2 M) e+ e: [( R1 V1 F
  24.     CAN_FilterInit(&CAN_FilterInitStructure);                       //按上面的参数初始化过滤器
    6 _) b& _3 n4 v: v
  25. 4 F0 f5 k( d5 A2 \3 s4 x
  26. + W6 r& X9 [# H$ R) J% G
  27.     /* CAN FIFO0 message pending interrupt enable */ " b, `  w8 E1 W4 X8 t
  28.     CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE);                         //使能FIFO0消息挂号中断9 |- I3 I: ]* \/ t$ d4 T4 S+ g( ?/ K
  29. }; J6 u2 [& B( C0 u
  30. 8 b' D# V9 q$ x% ~; c% h

  31. 0 u9 k  F% U- [+ u7 Z) m
  32. //接收数据缓冲器
    + k7 ?3 L+ D1 F1 ]2 u
  33. u8 CAN_RX_BUF[CAN_RX_LEN]={0};     //接收缓冲,最大USART_REC_LEN个字节.
    5 s. d: P3 U" r9 S
  34. //接收标志位
      a" J6 u7 }- O$ u
  35. u8 Rx_flag=0;- @% U" H6 P; D/ C
  36. /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */! g) _& Q, l( t7 r+ s5 E
  37. void USB_LP_CAN1_RX0_IRQHandler(void): e; s4 ]1 K" K" X6 y/ A3 s" B. q5 }
  38. {
    ( i/ L# |9 F, g: m& s
  39.     u8 i=0;( H/ p2 |- n4 h! S( U
  40.     CanRxMsg RxMessage;, F+ C6 C  L% i" ~
  41. 6 S0 a7 |# V6 q- q

  42. ( M) F! T6 J0 C/ N. u6 o% @
  43.     RxMessage.StdId=0x00;
    ) x" F" d3 u; i6 n, d! ~
  44.     RxMessage.ExtId=0x00;
    3 r# S) a8 J# m0 Q" O. h( I" |
  45.     RxMessage.IDE=0;
    , G4 t2 X$ k. z* @
  46.     RxMessage.DLC=0;
    : a4 x& z% M0 P2 x
  47.     RxMessage.FMI=0;
    0 X: R. o8 N, I6 J* [- q! Y& C
  48. , a7 v+ `3 _- @" E- ]4 f& `- g6 ^
  49. : h4 M; n0 ]+ M" j* Y* t9 L5 Q
  50.     CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  1 |9 p; [0 ~6 V, N. D( B$ M8 H' [7 I
  51. # y. ?6 h0 Q3 A& I4 H6 ~) w
  52. ! t+ L$ h9 M& \! c: h
  53.     if(Rx_flag == 0)//数据已取走或者缓冲器为空! S7 E% }- F  W9 \1 Z4 ^( C( D. u
  54.     {
    ! M, s; f% k& g5 S) R
  55.         if((RxMessage.DLC) == 2)//是否收到2位字节数据
    ' V# z) R" Z  \# ]5 [( h
  56.         {
    $ y  m; \& g! z
  57.              CAN_RX_BUF[0]=RxMessage.Data[0];4 @/ Z) f  b! b2 S
  58.              CAN_RX_BUF[1]=RxMessage.Data[1];     
    9 ?2 l' m( b. i4 s3 U
  59.         }5 P" @1 t& k! T( Y' S( Q
  60.     }3 ?) s1 E6 m1 X" O% w8 {
  61. ! ^) _1 F1 V, |+ K/ e) Y6 |

  62. . G9 L8 J- J$ Z/ t. t6 h# }
  63. }
    $ I6 c) ^9 H* E9 I! Z9 L

  64. ( p4 e  @" h" `7 P$ Q. T) m9 j
  65. ' V/ s8 A1 @. Q' R& @# Z! X- A
  66. /* 发送两个字节的数据*/) g: G: l/ L. f, j+ ?5 H
  67. u8 CAN_SendMsg(u8* data1, u8* data2), u  x# i$ h+ R- N" |
  68. {
    . p$ x  S! N4 m" R/ f9 n; N
  69.     u8 mbox;+ f: t( A& R, y1 H7 x! n/ ^5 u
  70.     u16 i=0;
    6 o- V: D" v8 G7 }, H
  71.     CanTxMsg TxMessage;  ; @9 ~) {+ n0 \* ^

  72. " w9 V, ]! J5 {7 \( a. N

  73. 5 P6 S* ?- }# f1 g
  74.     TxMessage.StdId=0x0000;     //标准标识符为0x00: \# f3 W- ~+ J  K) w2 G) k
  75.     TxMessage.ExtId=0x1314;     //扩展标识符0x0000* l6 ]6 Q& O% H2 e8 v
  76.     TxMessage.IDE=CAN_ID_EXT;   //使用扩展标识符
    5 X2 G8 J) d& O$ \& }2 x
  77.     TxMessage.RTR=CAN_RTR_DATA; //为数据帧
    1 f# m6 I  w& C4 f+ q
  78.     TxMessage.DLC=2;            //消息的数据长度为2个字节
    3 u1 d" q5 v' G" g% J* x" S; L
  79.     TxMessage.Data[0]=Data1;    //第一个字节数据4 i) y2 p/ `- W
  80.     TxMessage.Data[1]=Data2;    //第二个字节数据 . s$ _8 h1 Y0 M$ U

  81. ; T0 d$ S8 b$ o$ f, c' L8 Z! }

  82. 3 T1 [) b2 s2 u' e
  83.     //发送数据
    3 K7 l6 `7 V6 o2 t! q
  84.     mbox= CAN_Transmit(CAN1, &TxMessage);  7 W6 Q) v3 _* ~2 c0 V
  85.     while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
    * \  K2 T  \+ L: c, F9 }, l- g! D9 F
  86.         i++;    //等待发送结束# \3 v7 k+ q' _2 i2 S2 C4 T
  87.     if(i>=0XFFF)2 |4 @5 j5 N& C7 C. T6 u
  88.         return 0;//发送失败- X) b" O  Q! L; I
  89.     return 1;//发送成功
      [2 u& |* x9 L1 S
  90. }- H1 Y2 _0 D4 I6 v5 f6 t
  91. u8 CAN_GetMsg(u8 *msg1,u8 *msg2)5 ?) w$ `( U7 Y' w
  92. {& i1 m5 v- W: ^7 n3 a8 a4 B. w7 F9 Z
  93.     if(Rx_flag == 1)//发现数据
    + W6 o! X& W4 E  }: k6 s5 l- W
  94.     {1 X, A) K$ k3 N8 p
  95.         *msg1=CAN_RX_BUF[0];1 k' L: U4 @7 l& @  e
  96.         *msg2=CAN_RX_BUF[1];  |2 m5 ^1 D1 m( R8 \+ @
  97.         Rx_flag=0;//数据已经取走,可以更新数据" m! E# J/ ]5 D9 e7 w5 G
  98.         return 1;$ B5 k% K; t. _. w
  99.     }else
    / {' U- y& n8 D  I
  100.         return 0;
    - t3 I, g/ ~" y$ c  c: ]3 I
  101. }3 g+ F0 B( @7 W
  102. void Clear_canBuffer(void)
    3 ]+ I' ?0 p, c0 m5 R& p1 M
  103. {8 J5 f# n+ t/ t
  104.     Rx_flag=0;//清楚接收标志位7 m9 g3 T! m) b9 |
  105.     memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区. {/ h% w2 X' E  W# F
  106. }, ]# M8 |, J9 b% m& n4 r
  107. u8 Check_canRX(void)
    # b6 H7 R# |8 Y4 t
  108. {
    7 I' R- D2 S" c# ]
  109.     return (Rx_flag == 6);$ ~# H% n7 L# `1 W3 j  I- f
  110. }
复制代码
3 P! M: K1 f( n7 D5 |( \
can.h文件:

  1. . I# R) g" }& y6 p" {2 G
  2. #ifndef __CAN_H
    4 E! a% N3 q) [; _- B
  3. #define __CAN_H
    1 d: L0 ~0 Y2 `. k8 _
  4. * d4 O  h* Q5 Q7 _& q
  5. - W% c6 C3 O# j6 d- p
  6. #include "sys.h"' j, V  e# ]0 o1 ~# \% @! ]
  7. #include "string.h": ~8 M0 A4 Z! P' P' q" Q6 N0 |
  8. 3 b5 O' H" h8 ~) d5 J9 I% y9 ]
  9. " k  |3 X& M4 a1 b+ w' |
  10. #define CAN_RX_LEN          30          //定义最大接收字节数 & ?# a1 I3 b) t0 {
  11. ; v' Q; e( \4 A* t7 V
  12. 7 ~9 T8 k* N" r# i- D
  13. extern u8  CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 6 ~1 K  P  u  Z7 C( _, A; e
  14. % T, d% e2 P- N* `

  15. : E! N  @3 T$ w+ m! e: G/ p# s7 D
  16. void CAN1_Init(void);
    2 P  O2 C; @$ X6 [& }$ O  Q. N% E
  17. u8 CAN_SendMsg(u8* data1, u8* data2);) Z5 E0 {6 L+ j- }
  18. u8 CAN_GetMsg(u8 *msg1,u8 *msg2);
    % H( Y* f8 h+ G) p

  19. 4 l1 h. {& k; d7 m

  20. + j, }' t$ u, H* n: d
  21. #endif /* __CAN_H */
复制代码
/ |7 @' ?9 w( H# x
收藏 评论0 发布时间:2021-11-7 15:31

举报

0个回答

所属标签

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