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

【经验分享】STM32F7xx —— CAN通信

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
一、CAN基础
( [0 N0 e% {" P: }: V差分信号:显性电平对应逻辑0,CAN_H和CAN_L差为2.5V;隐形电平对应逻辑1,CAN_H和CAN_L差为0V。
* D; @, Q; @, B/ @1 U$ G3 D$ x* o# ^9 Y7 M( w5 y
CAN总线的开始和结束都有一个120Ω的终端电阻。
  }/ `& G+ C9 ?+ H& H1 C. h5 E; e4 z2 w2 r: i
数据帧:标准帧11位,  扩展帧29位。
- I# p0 @" s' G# L; W: i: n' f! M: b; s& q: n( N
其他的一些理论知识就不再赘述了,可以参考维基百科对于CAN的描述。
% K; x0 M0 a, c* m9 u" [* L3 N8 B: _& o
STM32F7xx的bxCAN主要特点:支持CAN2.0A和CAN2.0B,波特率高达1Mbps,支持时间触发,具有3个发送邮箱,2个接收邮箱,可变的过滤器组等。
# [( B) F' q( I. A6 D1 e9 g& ^' R, r2 J  R8 x
二、几个重要的CAN函数1 M$ s* \3 n: F) ]* J- F5 L  @
  1. HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化
    8 f8 R( K6 c/ Q

  2. 2 q1 d1 V3 |7 `/ p6 r
  3. HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN发送7 r7 C3 {  V( m0 j/ f5 ?+ L, i$ @
  4. 4 l7 f! L4 e3 N5 W2 C0 Q( j
  5. HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收
复制代码

! J9 q" p, @" `! C三、几个重要的结构; R: L) z8 O$ F/ D. ?) J. Q( P
  1. // CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化结构 发送接收结构体 其余三个是过程变量' A* ?; F" m4 C
  2. typedef struct, _/ i7 b3 |: M% B! N9 `6 A/ j3 E* _
  3. {
    * ?7 P8 f; A- ?* R: A
  4.   CAN_TypeDef                 *Instance;  /*!< Register base address          */0 o; R7 i$ Y8 v7 G" A, @. K2 s* G6 w  R

  5. 1 Q2 r7 ?6 U0 j2 j7 x
  6.   CAN_InitTypeDef             Init;       /*!< CAN required parameters        */5 v8 _: H1 @6 I  G5 w0 T
  7.   z7 v9 n% L% M4 A4 w
  8.   CanTxMsgTypeDef*            pTxMsg;     /*!< Pointer to transmit structure  */; X1 `6 q0 w, P& _1 F8 l6 H2 H

  9. 1 V# a/ _* i% p& L9 ]1 X
  10.   CanRxMsgTypeDef*            pRxMsg;     /*!< Pointer to reception structure */! u' J2 \& g' V8 N- e. B

  11. 8 P' x. x7 m+ T; a- f* Y/ m! v6 w
  12.   __IO HAL_CAN_StateTypeDef   State;      /*!< CAN communication state        */2 k5 y( {  C  g) z6 Q8 |1 ^

  13.   g) V, p' ]$ U: S8 {- G2 D
  14.   HAL_LockTypeDef             Lock;       /*!< CAN locking object             */7 h6 L. P, g  z2 y5 O) P
  15. : L( S2 V% u, \2 I% U! P8 d
  16.   __IO uint32_t               ErrorCode;  /*!< CAN Error code                 */; g9 J) h- m0 b8 q! W4 A
  17. . z% i) V4 @! A  m1 ~' k: m
  18. }CAN_HandleTypeDef;
复制代码
  1. // CAN配置结构体
    5 H" }, ]: Q+ c; \5 o
  2. // 前5个参数来设置 CAN_BTR —— 波特率
    # v6 L1 Y4 `# V5 ]  W$ V% u/ ]
  3. // 后6个参数用来设置 CAN_MCR —— 通信相关的控制位
    , I  c( n; w! [- l' ?8 R
  4. typedef struct+ }- E6 @# X" w8 h6 r
  5. {
    # _( y  i; q8 ]( U* U8 Q
  6.   uint32_t Prescaler;  /*!< Specifies the length of a time quantum.5 G/ X9 I# X- ]5 @$ a: s
  7.                             This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */
    6 L# {) K/ O4 w7 l& A
  8. ' U+ Y# _8 x& N7 p: ]
  9.   uint32_t Mode;       /*!< Specifies the CAN operating mode.# J! u: P$ d' @% q3 w
  10.                             This parameter can be a value of @ref CAN_operating_mode */
    ! B6 R: Y3 S, q) l; ]4 z$ ?
  11. # ~4 e4 m( y6 w% @3 S5 v6 R
  12.   uint32_t SJW;        /*!< Specifies the maximum number of time quanta' R( G! I" n- L, c' K
  13.                             the CAN hardware is allowed to lengthen or: Z0 W( u& N1 ]
  14.                             shorten a bit to perform resynchronization.' k, Q+ K5 U# C" [& R+ y
  15.                             This parameter can be a value of @ref CAN_synchronisation_jump_width */
    " M) O8 P1 F# O3 B: E
  16.   W8 x( s8 v5 y% g6 `9 Q  w1 ^; C
  17.   uint32_t BS1;        /*!< Specifies the number of time quanta in Bit Segment 1./ v1 Q, p1 c+ S$ w  H# q
  18.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 */
    5 U0 l2 V7 H: w" |% x( X

  19. . m% ^" |$ I3 k" k
  20.   uint32_t BS2;        /*!< Specifies the number of time quanta in Bit Segment 2.
    5 }2 C6 R! S9 c: t" Q4 a
  21.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */
    # ^- _+ ?* _( U0 `0 G, d  V6 e
  22. % }. R! O( J( _: T+ g+ e1 [- v
  23.   uint32_t TTCM;       /*!< Enable or disable the time triggered communication mode.! C1 z3 w6 C0 K2 X7 _
  24.                             This parameter can be set to ENABLE or DISABLE. */5 A0 Q, P( q2 k6 X9 v2 n3 k

  25. & f: ^0 {* k% M4 c) h: @
  26.   uint32_t ABOM;       /*!< Enable or disable the automatic bus-off management.
    & _3 p3 p2 W# F3 T
  27.                             This parameter can be set to ENABLE or DISABLE */$ ], }# I2 W1 m8 c; K7 ^
  28. % c7 H6 n: E2 _
  29.   uint32_t AWUM;       /*!< Enable or disable the automatic wake-up mode.
    5 @1 `5 J) P7 l; V1 ^  B; R
  30.                             This parameter can be set to ENABLE or DISABLE */
    9 L: E3 f' ]1 P- `
  31. , D% _: L% d0 G1 w5 t8 p2 e
  32.   uint32_t NART;       /*!< Enable or disable the non-automatic retransmission mode.) g/ a0 [/ p3 d9 u
  33.                             This parameter can be set to ENABLE or DISABLE */6 i2 C$ R! y6 ?+ o  H) }

  34. ! F5 F+ J. W; f* D* l
  35.   uint32_t RFLM;       /*!< Enable or disable the receive FIFO Locked mode.
    $ l; m+ C, a, i* B2 F! ^) H
  36.                             This parameter can be set to ENABLE or DISABLE */: \% i* v( C  q% }  M( ?

  37. ' f: n! A8 r! F' |6 m$ D
  38.   uint32_t TXFP;       /*!< Enable or disable the transmit FIFO priority.% Y" Q" E! d: C
  39.                             This parameter can be set to ENABLE or DISABLE */9 Z' [) l5 c! F* K, S) c% U
  40. }CAN_InitTypeDef;
复制代码
  1. // 过滤器设置" A& N  Z8 `3 j0 |6 s: n
  2. typedef struct
    # Q. s# K5 v- H0 O/ b
  3. {2 C7 ~2 g; A* T
  4.   uint32_t FilterIdHigh;          /*!< Specifies the filter identification number (MSBs for a 32-bit
    1 P0 W! _6 }) j) K
  5.                                        configuration, first one for a 16-bit configuration)., O6 M2 y( M9 v- V$ D
  6.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    6 m$ T4 m0 W9 B& {7 I, V$ |
  7. ( c0 N, b4 f" g( [
  8.   uint32_t FilterIdLow;           /*!< Specifies the filter identification number (LSBs for a 32-bit$ ]/ G! t/ o, }# o4 ^. a/ D
  9.                                        configuration, second one for a 16-bit configuration).
    / Y$ \) Y* w; n, j) d8 r' `. E1 O
  10.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    ' U( `7 Y2 n4 s' ?5 _
  11. 5 [1 W& b7 n" n) B
  12.   uint32_t FilterMaskIdHigh;      /*!< Specifies the filter mask number or identification number,3 q$ J) B% ~- ?; I6 G* c
  13.                                        according to the mode (MSBs for a 32-bit configuration,
    * U+ x6 g: P7 T) ]' Z' r
  14.                                        first one for a 16-bit configuration).; c; f+ i/ G4 I/ Q3 V( X3 M
  15.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    3 I* ~" I; r- p/ R9 j/ m9 G
  16. " a0 B, t9 E) W' q( Q9 F* |
  17.   uint32_t FilterMaskIdLow;       /*!< Specifies the filter mask number or identification number,) P0 G1 D2 V& m6 V/ E6 y' u
  18.                                        according to the mode (LSBs for a 32-bit configuration,  [4 r  {1 a, e1 ^, U% H
  19.                                        second one for a 16-bit configuration).
    ) E- x) y5 n# x
  20.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF *// k& q8 Y% A  ]9 Y: |, A  n1 c

  21. 3 {+ I6 {( f3 A9 L' J6 }; z
  22.   uint32_t FilterFIFOAssignment;  /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.
    % I' J" Q1 D9 I4 x! [5 Z" i0 k7 K
  23.                                        This parameter can be a value of @ref CAN_filter_FIFO */
    + _8 N; f- Z" E% y. }7 _& j$ K6 k: n$ o. S
  24. : C' t9 W. [9 L6 c
  25.   uint32_t FilterNumber;          /*!< Specifies the filter which will be initialized.
    / m% n$ V/ x- B+ i7 [
  26.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 27 *// _; Y" o* l1 P$ k1 g  B3 T! h
  27. - q, B* B) [. [7 d) x, f4 s
  28.   uint32_t FilterMode;            /*!< Specifies the filter mode to be initialized.
    ( \" e+ L! k. U
  29.                                        This parameter can be a value of @ref CAN_filter_mode */
    7 q% g% R. f( S) R" G8 q
  30. 9 f9 }/ a1 y+ m  f8 X/ e
  31.   uint32_t FilterScale;           /*!< Specifies the filter scale.. k  G7 ~+ a+ g3 R; T' n/ U
  32.                                        This parameter can be a value of @ref CAN_filter_scale */+ L: l- H4 g. L5 \2 H

  33. 6 O& _+ O2 G( v; P4 P
  34.   uint32_t FilterActivation;      /*!< Enable or disable the filter.! R! r: s$ |1 m6 x; x. B& ^% p
  35.                                        This parameter can be set to ENABLE or DISABLE. */
    - t& k3 Y5 w- T; I! v  k

  36. * C+ ~4 V% L- _4 f; |
  37.   uint32_t BankNumber;            /*!< Select the start slave bank filter.+ ]- }; O! D4 K7 @9 U* ]  H2 M
  38.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 28 */
    9 ~3 C' T& k2 l8 ?0 O
  39. % F' |8 n1 u+ I
  40. }CAN_FilterConfTypeDef;
复制代码
  1. // 模式  我们使用普通模式' a, T" A9 e' u3 |3 }1 _
  2. #define CAN_MODE_NORMAL             ((uint32_t)0x00000000U)                     /*!< Normal mode   */! f: h- Z* K9 w: h* x! A: ^8 ^
  3. #define CAN_MODE_LOOPBACK           ((uint32_t)CAN_BTR_LBKM)                   /*!< Loopback mode */* d) e+ ]( W& K9 J: Y$ w
  4. #define CAN_MODE_SILENT             ((uint32_t)CAN_BTR_SILM)                   /*!< Silent mode   */% |1 z) W7 f% S; o
  5. #define CAN_MODE_SILENT_LOOPBACK    ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM))  /*!< Loopback combined with silent mode */
复制代码
  1. // 标准帧 扩展帧
    & h9 r0 N& q2 v% _7 h
  2. #define CAN_ID_STD             ((uint32_t)0x00000000U)  /*!< Standard Id */; f, i+ H! ^  h
  3. #define CAN_ID_EXT             ((uint32_t)0x00000004U)  /*!< Extended Id */
复制代码
  1. // 数据帧 远程帧
    & x; A7 ^5 [, F( r! z4 K
  2. #define CAN_RTR_DATA                ((uint32_t)0x00000000U)  /*!< Data frame */7 y. y8 o: Y3 U3 @% R# [" ]/ Y' K) Z
  3. #define CAN_RTR_REMOTE              ((uint32_t)0x00000002U)  /*!< Remote frame */
复制代码
  1. // CAN中断使能
    + K. M$ F! g0 q7 o0 d' u0 A
  2. __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__)
复制代码
  1. // 接收中断
    - `' W4 b/ g; [! B2 W
  2. #define CAN_IT_FMP0                 ((uint32_t)CAN_IER_FMPIE0)  /*!< FIFO 0 message pending interrupt */* z. E0 i& A4 Y4 t$ F
  3. #define CAN_IT_FF0                  ((uint32_t)CAN_IER_FFIE0)   /*!< FIFO 0 full interrupt            */$ N: A, \6 x4 N" u
  4. #define CAN_IT_FOV0                 ((uint32_t)CAN_IER_FOVIE0)  /*!< FIFO 0 overrun interrupt         */
    3 G* s/ P2 [1 f; B: ~' F
  5. #define CAN_IT_FMP1                 ((uint32_t)CAN_IER_FMPIE1)  /*!< FIFO 1 message pending interrupt */6 Y# A7 j$ a2 G0 a/ C# U, v
  6. #define CAN_IT_FF1                  ((uint32_t)CAN_IER_FFIE1)   /*!< FIFO 1 full interrupt            */
    $ ^$ l* V+ ~( z" |
  7. #define CAN_IT_FOV1                 ((uint32_t)CAN_IER_FOVIE1)  /*!< FIFO 1 overrun interrupt         */
复制代码

1 F- a+ r- I; B四、接口设计
8 Z# g; J! `) o  N3 ^- f( C) ]与串口类似,使用中断接收。先封装单路CAN需要的几个小接口,再顶一个列表,最后使用统一的接口扫描这个列表。
# u% h% b9 x9 E- X
4 l* ~# T, @! l5 W
  1. typedef enum
    ( e' O2 s- Q8 f" P( I8 j2 @
  2. {
    : P6 P) m( [. X1 @( [% J' d  x  W
  3.   CAN_CHANNEL_NONE,
      [5 ?" j2 h) @
  4.   CAN_CHANNEL_1,. S( n2 ^7 F6 U( z
  5.   CAN_CHANNEL_2,' ^9 o% A2 w$ w+ W; ^% a; `+ X; Y! K
  6.   CAN_CHANNEL_NUM1 ]3 s5 `3 f5 S7 r
  7. } can_channel_t;/ J# \# E( F, I5 r& U

  8. # m# P; f9 L# c" ^
  9. #define CAN1_CHANNEL              CAN1$ w# [; `. Y! y& O! q! \
  10. #define CAN1_PREEMPT_PRIO         CAN1_RX_PRIORITY
    ' w" ]7 u/ b7 Q* a6 w. i9 Y7 Y
  11. #define CAN1_RX_IRQ               CAN1_RX0_IRQn
    ; ~/ }# ^! e0 |3 {5 d; V% L) O
  12. #define CAN1_RX_IRQ_FUNC          CAN1_RX0_IRQHandler
      h# q) x2 V! S4 J
  13. #define CAN1_CLK_ENABLE()         __HAL_RCC_CAN1_CLK_ENABLE()
    : c" s$ D6 o% a* b, g
  14. #define CAN1_TX_PORT              GPIOA
    . L. R( D0 }+ ?( s
  15. #define CAN1_TX_PIN               GPIO_PIN_126 D, V% {2 Y$ p% p+ I( S+ h2 g" d
  16. #define CAN1_TX_AF                GPIO_AF9_CAN10 C& q4 u6 }# Y' ?7 g
  17. #define CAN1_TX_CONFIG()          GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF)
    3 `; C2 o1 D1 ~  o7 b7 j; s9 q
  18. #define CAN1_RX_PORT              GPIOA
    4 t$ y6 u' n% i* ~
  19. #define CAN1_RX_PIN               GPIO_PIN_11
    . n/ h( {' V: D5 z! A
  20. #define CAN1_RX_AF                GPIO_AF9_CAN15 x6 A& ]& Z( u5 Y- S/ c
  21. #define CAN1_RX_CONFIG()          GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF). O% i* T' f1 R' n/ I) W( C9 T

  22. 6 @/ k7 Z, u3 y
  23. #define CAN2_CHANNEL              CAN28 ]2 _. E3 ?9 g
  24. #define CAN2_PREEMPT_PRIO         CAN2_RX_PRIORITY; G) s& n5 T- t! k1 W( M
  25. #define CAN2_RX_IRQ               CAN2_RX0_IRQn0 N. D2 e: B: \+ t  a
  26. #define CAN2_RX_IRQ_FUNC          CAN2_RX0_IRQHandler( U- B# ]8 `7 Y3 u! o
  27. #define CAN2_CLK_ENABLE()         __HAL_RCC_CAN2_CLK_ENABLE()
    6 V2 G, Z4 }( t+ ?
  28. #define CAN2_TX_PORT              GPIOB
    0 g4 d. g6 V: H- c9 x7 a
  29. #define CAN2_TX_PIN               GPIO_PIN_6& j" J4 k% B! v9 o
  30. #define CAN2_TX_AF                GPIO_AF9_CAN2
    ) T, E% R/ c! \
  31. #define CAN2_TX_CONFIG()          GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF)
    1 E. x2 o3 j8 L( c) J+ I8 e
  32. #define CAN2_RX_PORT              GPIOB9 F& W+ t9 P9 O. Z0 E7 R
  33. #define CAN2_RX_PIN               GPIO_PIN_5
    4 Q! o  A8 _* V& X6 m
  34. #define CAN2_RX_AF                GPIO_AF9_CAN2
    2 U" B5 S; r* M/ o
  35. #define CAN2_RX_CONFIG()          GPIOConfigExt(CAN2_RX_PORT, CAN2_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_RX_AF)
复制代码
  1. <span style="background-color: rgb(255, 255, 255);">/</span>/ 抽象出一个CAN设备结构体0 Z% Q7 c6 r: S% X
  2. typedef struct
    " T4 o) \' a6 t- F$ o" T% [0 b6 A
  3. {
    : d8 P! G. ?9 l7 q1 M/ T4 q
  4.   CAN_HandleTypeDef handle; // CAN操作句柄1 d' O) g& Y: z# w/ n/ t/ _
  5. 3 f5 r# s; Y  \* X$ e: x( k
  6.   CanTxMsgTypeDef tx;       // CAN发送& d  g6 J/ P% [  w3 e0 _
  7. * x6 y7 g; \& |
  8.   CanRxMsgTypeDef rx;       // CAN接收
    " E' Z' j0 o/ v! L3 ?

  9. : z. l5 }' Q0 V6 B# v& }' w
  10.   can_queue_t recv;         // 接收队列; Z+ D* H$ w* e2 ^, ]) H

  11. ( o4 C# [/ C$ `7 U- c7 s, f3 y; j
  12. } can_dev_t;
复制代码
  1. // 将每路CAN封装成几个小函数; ?1 a2 w4 e# p+ c2 Q+ ^4 U1 `; e3 }
  2. static can_dev_t can1_dev, can2_dev;4 k+ S: b) ]5 M: K

  3. 0 G: X4 b7 w! P1 w- X: `, A9 P
  4. static void can1_var_init(void)+ |% r$ h/ D& {  f0 `
  5. {. @/ L3 @; S0 T5 ~
  6.   can1_dev.recv = can1_queue_recv;3 g! z/ ]6 N" _1 `

  7. ) m* Y" C  P  ^# m) ]
  8.   CanQueueInit(&can1_dev.recv);+ T% a. z, t$ G( K/ _( N( f9 F
  9. }
    ) B' w' E6 A+ T/ c  Z8 |3 Y7 Z

  10. * V- T' g/ o% A/ X" q2 E% z% W
  11. static void can1_gpio_init(void)( s6 S* o) L7 Q0 R+ v* i
  12. {/ o& m0 d8 K" s, z9 j4 K( b8 B" n! ?: [
  13.   CAN1_TX_CONFIG();) g$ S- {& K6 Z6 k
  14.   CAN1_RX_CONFIG();
    9 G: x6 l/ w* Z! K. h
  15. }5 e5 y/ g: y1 P2 i8 P. |. G

  16. 8 H, `" x0 O1 v( f' I
  17. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M6 }2 o' {. T1 W5 n2 Q
  18. static void can1_mode_init(void)
    6 ]9 F7 g2 w& F, s5 z9 H
  19. {& V/ F$ l% Y4 z& ]7 o; U# k4 D
  20.   CAN1_CLK_ENABLE();
    4 [3 G. T: p3 U6 t0 x/ s1 |& ?
  21. , X" ]. W5 @4 B- u4 P) j3 C
  22.   can1_dev.handle.Instance = CAN1_CHANNEL;
    1 ?. K2 F9 K! ?8 L. ^9 {( c% ?+ {$ M
  23.   can1_dev.handle.pTxMsg = &can1_dev.tx;
    8 j# \  B9 ^. U) A* ^' Q* M" \
  24.   can1_dev.handle.pRxMsg = &can1_dev.rx;
    ' h; J' X% W3 e0 ]3 i' @
  25.   can1_dev.handle.Init.Prescaler = 6;3 M+ e9 z* O; W
  26.   can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;2 l$ s4 f& u' B( a( `) _
  27.   can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ0 ^9 p/ m" e9 e7 Y) W3 ^
  28.   can1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    , z& [. |" c4 F( J4 z0 \: S$ e
  29.   can1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ$ j- W3 {# I; B2 g+ [8 _& X
  30.   can1_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    2 r; A% M. _6 I3 x* o
  31.   can1_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理
    8 F. v0 d# S. K; u
  32.   can1_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)/ V) P0 o$ j$ p, f/ y8 E. l: O
  33.   can1_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    * i7 _- r6 {3 ?1 Y: }" ?5 e1 _6 E
  34.   can1_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
    ! M  _7 c3 a. Y8 n/ F/ Z
  35.   can1_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定
    ( F) M. A/ B6 k8 L5 C& T% e6 q
  36.   HAL_CAN_Init(&can1_dev.handle);1 s0 E  V7 v" p+ [
  37. }
      `" t. C# n7 Z7 d  |4 E: d

  38. , e6 J+ c8 q% K% b
  39. static void can1_filter_init(void)
    0 v" A; W* J- b, Y) Y( ]8 v0 k* W
  40. {& y7 a8 P, o+ _2 ~( ]% K  i
  41.   CAN_FilterConfTypeDef  filter;3 J3 Q" B( a$ Q) x3 _+ G
  42. 4 W2 @& d& V  k+ s
  43.   filter.FilterNumber     = 0; // 过滤器05 K( o! v, m0 I5 d
  44.   filter.FilterMode       = CAN_FILTERMODE_IDMASK;
    / D2 {) K2 [5 M5 F5 q) ]2 r+ h% O
  45.   filter.FilterScale      = CAN_FILTERSCALE_32BIT;
    / S+ \7 H. Q1 Y4 c& I

  46. / W( p4 d9 W* x% S: m; T  W
  47.   filter.FilterIdHigh     = 0;1 b6 E" H. O" g3 G. n9 A
  48.   filter.FilterIdLow      = 0;$ o* Z3 ~% T( @8 E" `$ d. h
  49.   filter.FilterMaskIdHigh = 0;
    8 i$ ~: O% d. y1 n
  50.   filter.FilterMaskIdLow  = 0;
    $ h# E& {7 Q6 z2 v! C: Y9 Y

  51. : E* E% W0 L" _( w/ U8 B
  52.   filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0
    ! g; O7 q' V: b- T
  53.   filter.FilterActivation = ENABLE; //激活滤波器03 [1 z6 ~+ o% ~7 x: b% \$ K
  54.   //filter.BankNumber=14;4 x2 {% M4 ^: X8 B
  55. 5 o" `; T6 \$ D. d5 g
  56.   HAL_CAN_ConfigFilter(&can1_dev.handle, &filter);
    0 `5 q0 p+ i- G. v
  57. }
    : R7 ]. {2 ?% m1 E% q' y
  58. 5 m+ x9 j- e& C% }' L) b! m4 r
  59. static void can1_nvic_init(void)
    & o& \) W- w2 T: f9 C- _
  60. {
    ; V8 L% w' y$ ], ^! W
  61.   __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许.
    ( M8 m* t0 |9 H; |1 f
  62.   HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);
    4 Z1 [9 ?* r* B0 L' x7 g
  63.   HAL_NVIC_EnableIRQ(CAN1_RX_IRQ);5 ?( \7 b. a- D% p
  64. }
    ; t4 f9 }& s+ G# n; _

  65. / i! Q& L: {! u( C6 Q
  66. * S; {5 }0 x0 R% }6 U* O
  67. 5 O2 N8 b) ~7 q! ?. Y2 f2 E
  68. static void can2_var_init(void)
    0 v7 U' O  d) n8 \; Z
  69. {! X( A+ g: ]9 G3 q
  70.   can2_dev.recv = can2_queue_recv;  Z- p2 w/ n( i- ?# @& Q
  71. - U/ Q; D/ ^8 z  u
  72.   CanQueueInit(&can2_dev.recv);9 Z$ s5 m; Z/ A! G' K/ |/ E! ~$ D
  73. }$ a$ t: H: G& G, H: ]

  74. . J6 s; S) h- N' a: H
  75. static void can2_gpio_init(void)7 O! ?2 H( a, S7 d) A' o) g" L/ Q* z
  76. {0 ?( U! |  ?; o/ w
  77.   CAN2_TX_CONFIG();% c3 ?! t: e7 U
  78.   CAN2_RX_CONFIG();$ B  f- m6 R# `  ~  a
  79. }5 X" @3 h2 s) `1 H- E' I$ ^& Y
  80. & r3 O2 G+ \0 V/ v4 x4 a
  81. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M3 R% v1 j1 K( N& s  d( z' P( A
  82. static void can2_mode_init(void)" `" K+ s- C. x9 o5 `9 E% P$ C' z" m
  83. {
    # z* D& ~( \+ x7 S( ^: r8 q
  84.   CAN2_CLK_ENABLE();
    8 ~/ o8 _/ z# C3 L, P8 |; ?6 K
  85. + ~& k/ Z3 {+ T) J4 K+ W
  86.   can2_dev.handle.Instance = CAN2_CHANNEL;
    8 B: C$ Z* U5 K" b# D
  87.   can2_dev.handle.Init.Prescaler = 6;3 D% {' R& |( |$ _) w  B
  88.   can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;1 T% b& s1 ]3 P5 U+ }
  89.   can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    9 q/ P* y) e+ y. y5 B  M! _
  90.   can2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
      R( }+ ]8 q5 P3 I
  91.   can2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ2 W0 Z6 @$ e& E+ r8 J$ }! F. h
  92.   can2_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式& ?1 Z8 _- [0 Q3 ?
  93.   can2_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理) \* A3 j  x( v3 h$ g8 ]0 x: Q
  94.   can2_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)3 T6 e- ?  w4 I; C: F6 D- _
  95.   can2_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    4 K/ l$ m# O: }9 V" i. a
  96.   can2_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
    7 \7 q4 K! Y: Z: `( X  H0 g
  97.   can2_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定$ u8 L9 [3 k; ?* n* ?) }( s: }
  98.   HAL_CAN_Init(&can2_dev.handle);
    % |. O% D; [- p' V. U/ |# h7 ], e
  99. }
    , _% U  z$ P+ A0 ?( F/ ~

  100. + [/ ?; q& K( X0 v! o0 T9 p4 H
  101. static void can2_filter_init(void)4 b+ W6 h6 h1 G( @
  102. {/ n2 f- ~* h, F  Y' [1 I5 Y" Q
  103.   CAN_FilterConfTypeDef  CAN_FilterInitStructure;
    & F1 T7 \8 _$ a0 v1 k( y; W1 u/ \4 K; v

  104. % E2 o5 ~5 g6 g
  105.   CAN_FilterInitStructure.FilterNumber     = 14;& `, N! [+ C" P. p+ q
  106.   CAN_FilterInitStructure.FilterMode       = CAN_FILTERMODE_IDMASK;( z  d& L4 l' y( |7 f$ H' k1 \
  107.   CAN_FilterInitStructure.FilterScale      = CAN_FILTERSCALE_32BIT;
    ; e* P3 k2 K# [% E! I

  108. 7 y' g3 `4 ^) l9 h
  109.   CAN_FilterInitStructure.FilterIdHigh     = 0;
    3 V! n' t6 z: E+ b7 e, `
  110.   CAN_FilterInitStructure.FilterIdLow      = 0;
    4 i+ A& E& m2 M7 S
  111.   CAN_FilterInitStructure.FilterMaskIdHigh = 0;
    3 N4 p9 v9 F4 b5 c2 T5 h) V, |
  112.   CAN_FilterInitStructure.FilterMaskIdLow  = 0;
    8 v1 Y4 ?, X, P( l( d6 Y
  113. ' Q5 @5 B. I0 N5 V6 |1 A
  114.   CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO08 Y! O. Z( ]# ^1 \) E: q- @% ~4 F
  115.   CAN_FilterInitStructure.FilterActivation = ENABLE; //激活滤波器0
    ) A( {0 `6 j$ `" m/ ^  }
  116.   //CAN_FilterInitStructure.BankNumber=14;
    $ t+ W( w6 Y& r. p( l/ m

  117. # |; ~% e- W8 l
  118.   HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure);  l& V- c- }8 ]* @/ }
  119. }- U1 u% W( G2 Z4 W

  120. ) H$ Z( J6 G2 N
  121. static void can2_nvic_init(void)$ g6 P+ }, J) U6 x2 {' e% c% C
  122. {
    " \9 x) P: ^1 y, O
  123.   __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许1
    5 o3 X7 f) Q2 _2 c) h+ N* N
  124.   HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);+ C7 V! z# X, f, F5 B
  125.   HAL_NVIC_EnableIRQ(CAN2_RX_IRQ);
    2 E( ~5 O( K7 D2 ?0 t, k, T
  126. }
复制代码
  1. // 每路CAN都有的几个操作,使用列表包含,然后统一扫描处理* V' L, [  W0 q
  2. typedef struct7 V$ a0 W' k( v0 Y5 K
  3. {
    ' _- n4 k* L+ p- @
  4.   uint8_t channel;' B, o; `0 h/ t0 t2 _' O" J
  5.   can_dev_t *dev;" ?8 }  K6 h0 t1 b9 S3 z. @; x
  6.   void (* var_init_cb)(void);& X/ g4 b8 v/ I5 t0 l) V
  7.   void (* gpio_init_cb)(void);
    # E, h. o" }. t) l, L& y5 z% u9 K& F
  8.   void (* mode_init_cb)(void);" T2 x) n0 g0 `/ L* r, k
  9.   void (* filter_init_cb)(void);5 a$ E! J% m# x" k: Y; u
  10.   void (* nvic_init_cb)(void);
    . _, L! l( y) D; c9 A( o
  11. } can_config_t;
    0 t; I4 O3 G2 d
  12. ' t" F5 t' k! b3 H8 ?& Z9 r
  13. static const can_config_t can_configs[] =, ^5 a* H# u. j; L) S( K  O. t
  14. {% T0 Y3 `  T" }5 T% C
  15.   {CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},8 \7 b9 o; V& b* z1 _; U! c
  16.   {CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init},
    # C) J. [7 {6 Z# L% v
  17. };, h! J: s- F; _- L6 u
  18. ' I# N3 L; d: r% H6 u! }& |; F
  19. static can_dev_t *can_dev_get(uint8_t channel)
    5 G8 L# a* D# i
  20. {
    9 G  r' N6 s& R: P* \' `# ]: v
  21.   uint8_t i;5 Q4 }9 f, }( {2 h9 C) c
  22. . K" {& }: q& j, O1 F
  23.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)/ Z# U% i6 s3 a' s3 d) {
  24.   {7 o2 L' Y$ l) s) Z
  25.     if(channel == can_configs<i>.channel)
    2 R: |% |! e& F
  26.     {6 {  _4 g. m5 j: Q  o! x/ a, d
  27.       return can_configs<i>.dev;4 G% r; V8 p* K+ g; i7 ]& F
  28.     }
    0 p4 m* G- t1 Y( t3 G* B
  29.   }
    0 V- m2 _) C5 i6 Z- c* |, J2 e8 M
  30. 8 m. H5 Q' H2 c  Q
  31.   return 0;
    % v6 H: s) |, {. a( i0 d1 o' s
  32. }  v- u. i3 b- ?) T
  33. 7 H- N) a# {; p1 y( k
  34. static void can_var_init(uint8_t channel)' c; x1 I, P- ?
  35. {
    ' n9 }. s' z* s' U7 s
  36.   uint8_t i;
    5 s' b, K; P5 N9 N& k
  37. 9 S$ o; ^; f  p' w' Q; w
  38.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)" u6 y, R6 Y- d' {9 \+ P
  39.   {8 Y* `2 k* e& P3 [  q% g
  40.     if(channel == can_configs<i>.channel)" T; g6 e1 u/ G! C* g# q- ]
  41.     {- Q. ^+ M6 p+ A+ ?6 q: g
  42.       can_configs<i>.var_init_cb();
    - @6 j1 N0 \; A
  43.       return;
    ( G1 ?! y) l- \1 z& v
  44.     }
    7 p6 ^# E: ^7 z& S
  45.   }
    / u9 j- N: |7 i4 Z4 o4 U$ ?) h4 S
  46. }- E% A# o) P8 e& X: Q" ^
  47. - `; b* d  S  F8 }* e6 g+ c1 o
  48. static void can_gpio_init(uint8_t channel)/ v+ e8 C& M/ E" U* l
  49. {  p, [( x$ S; _# E+ b4 z* [
  50.   uint8_t i;1 v' z3 W' P0 K7 r

  51. ; i4 |$ y. L. Y
  52.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)0 H; L2 ]" n8 Z% V1 w
  53.   {
    . `% r, O$ V; B1 u0 S$ d* B
  54.     if(channel == can_configs<i>.channel)
    2 X7 z# H' P5 a* w3 _: n8 E) s
  55.     {
    7 e  w" w/ m* E- C5 O
  56.       can_configs<i>.gpio_init_cb();9 ?0 T. q# [' z# A  h( ?- ?
  57.       return;
    : N* {: z: k( i  V. t2 A+ }3 u
  58.     }' l! H- t; Z1 j" b6 H
  59.   }
    4 Y- Y# K% G: s
  60. }. l+ ?# f. o0 j1 ]3 ]1 t, a9 j

  61. . s/ C$ D0 t( e: R
  62. static void can_mode_init(uint8_t channel)4 J# o( _- w; O  `
  63. {- M4 O) I& W# ~: f
  64.   uint8_t i;
    % T# c0 I6 [; Z1 W. o( i

  65. ' j  i9 {+ k6 A* o
  66.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    8 Z5 D  ^* e+ P8 |% q
  67.   {' r# A: w* u* w0 t$ F8 n
  68.     if(channel == can_configs<i>.channel), O6 \" z4 U. z8 [, j
  69.     {
    / H2 U+ I4 G: @9 k7 K
  70.       can_configs<i>.mode_init_cb();
    $ H9 C3 W& @; v5 v8 g  N
  71.       return;. Y# g! Y  k. X8 s( O) b: f
  72.     }  j, A, E( Z4 n) H4 }
  73.   }4 r8 o8 X+ P6 }" |8 [  i
  74. }
    , d0 P8 f# n( Y1 K9 @& b7 k

  75. 4 q6 P) W( ?# h' p( R
  76. static void can_filter_init(uint8_t channel)6 H2 ^8 b. G  {+ ^( W6 H
  77. {( K# `' q6 \% D  Y; X9 A
  78.   uint8_t i;
    # m2 o1 c4 }  r5 _6 z9 w

  79. 4 T" j) P3 o1 k/ ^2 {! k( `: I3 g4 C
  80.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    ( q' c, p8 @" \. R, d& z
  81.   {( k) V! s3 u( ^
  82.     if(channel == can_configs<i>.channel): t$ P# i9 F- H1 I9 B; n
  83.     {$ Y8 p( p* P" \" ?) o
  84.       can_configs<i>.filter_init_cb();
    7 h6 {* |# ^0 s' q/ m# R" `* G
  85.       return;) q0 y, }# N% R; ?- g# H" |
  86.     }
    3 e: w# a3 H, f, f( D
  87.   }: o& g+ y8 J6 M& C" L1 ^4 p; S
  88. }: s- S; H3 h7 ^& f

  89. # L3 o) F0 ?% _
  90. static void can_nvic_init(uint8_t channel)
    9 e9 H& Y- t4 s
  91. {3 m% K& ]% M* l+ W* b, [( z
  92.   uint8_t i;
    3 I" y/ d5 s1 H' y) M4 f; u

  93. # r  m9 H+ g0 E$ j+ m: W  z
  94.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    . _: V: z. }# I& e
  95.   {% H$ A% ^) B; P# k. N4 ?
  96.     if(channel == can_configs<i>.channel)7 H4 ^0 g+ L- m$ h( [
  97.     {8 R* l6 v+ V& {6 J6 c* A# _
  98.       can_configs<i>.nvic_init_cb();* y2 T: B, C3 ~8 r) I: w9 o& R
  99.       return;$ s9 F3 v5 I3 x
  100.     }* U& w- n1 Q- n, G* @3 l
  101.   }# u$ q8 {0 }8 x5 S
  102. }</i></i></i></i></i></i></i></i></i></i></i></i>
复制代码
  1. // 对外的接口 初始化 发送和接收0 D' u2 \6 L; u9 P! T3 w
  2. void CanInit(uint8_t channel)
    2 m5 V. Z: t. Q6 b# z2 I- k% `
  3. {' _# D+ e1 B7 T9 m/ x  W1 X
  4.   can_var_init(channel);" b9 w# B) l# j1 a! i1 x) w1 A
  5.   can_gpio_init(channel);
    1 D7 [5 m) |: ]; s# t' N
  6.   can_mode_init(channel);3 l) g! k/ ~: c' B1 k! r  L" D
  7.   can_filter_init(channel);
    / H* ?) z  u4 K7 e
  8.   can_nvic_init(channel);& {' X% P# L- F
  9. }0 T# C! I7 p1 X2 N/ G& C

  10. 1 h7 w1 h) m$ v0 H" A" H
  11. void CanSend(uint8_t channel, can_frame_t *frame)6 w& s! c, _% |
  12. {3 u( {  A" i0 r9 p
  13.   can_dev_t *dev = can_dev_get(channel);' g! _5 _, {1 x( \/ Z. I( H. R
  14. * |$ E, v* i# m" U0 C7 a( c4 h
  15.   if(dev == 0)& l  `; ~4 m- m# F1 A$ h& P
  16.   {
    : e" X2 Z8 Q! ?) g: p
  17.     return;' H7 h$ l2 a% Z: V: S# P
  18.   }
    / y7 a1 O* G  O8 U& s1 j* _

  19. * l% [/ a7 y! u& H5 g
  20.   dev->handle.pTxMsg->StdId = frame->StdId;
    7 g  G" p. i3 B
  21.   dev->handle.pTxMsg->IDE   = frame->IDE;0 E# t/ S( D9 `( x8 Z; \& t
  22.   dev->handle.pTxMsg->RTR   = frame->RTR;% O" Y1 ^8 x8 I/ Q$ t
  23.   dev->handle.pTxMsg->DLC   = frame->DLC;/ L  F6 Z2 [0 [
  24.   memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);2 E. \8 X! k8 u5 ]
  25. * j6 V9 {. s. g  n7 p: t" b; e
  26.   HAL_CAN_Transmit(&dev->handle, 10);: r4 ^0 _0 B8 V. \# w. I
  27. }
    7 M( L5 w9 Z1 G4 ]; [: ~

  28. ! d6 e6 _' }6 t# r3 \) y1 s. Z
  29. uint8_t CanRecv(uint8_t channel, can_frame_t *frame)
    ' j/ u. }+ e- y. a4 {% }, @
  30. {7 z. f" g1 z! x$ F8 v# v
  31.   can_dev_t *dev = can_dev_get(channel);
    ; F/ s" ^. r( N/ m/ j% u
  32. & P% P$ a2 x4 W; u# L
  33.   if(dev == 0)
    + z4 n- }) F8 A+ O2 V
  34.   {1 u0 P, G  j0 U
  35.     return 0;
    9 F- w5 p2 r7 p7 Z3 N' c/ i/ e
  36.   }
    * |/ }, H" Q" |0 Y& X. |% a. y. b
  37. 6 e5 O$ r8 j0 A7 r
  38.   return CanQueueRead(&can1_dev.recv, frame);
    9 W7 c( U1 ]3 M( o0 x1 y
  39. }
复制代码
  1. // CAN中断
      s2 ~0 H# P. s
  2. void CAN1_RX_IRQ_FUNC(void)3 u) g: P* L4 {! l
  3. {
    % U% |* D0 f# o# L2 h4 P
  4.   HAL_CAN_IRQHandler(&can1_dev.handle);3 r7 A, Y8 u/ M5 u2 O4 _
  5. }2 u/ p0 a, }# H7 ~, @/ O

  6. ; g' m8 f! g+ R- B7 h/ n. e
  7. void CAN2_RX_IRQ_FUNC(void)
    ' V* L, {3 i% M& u6 ]9 {
  8. {8 `; j6 ]: r4 S( ?
  9.   HAL_CAN_IRQHandler(&can2_dev.handle);
    - y/ e+ _  L  I" {5 j( d
  10. }. z/ v2 V5 n( ^! F8 c
  11. 5 P2 r2 s9 g, h
  12. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)
    4 {' T$ e; C* S5 _+ G
  13. {7 C% Q  c1 h, N) V
  14.   if(hcan == (&can1_dev.handle))
    $ V3 A& e/ h) k
  15.   {
    7 s2 q8 o* M" s* y+ l+ r7 ~
  16.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开  D3 K, I( i' h4 K0 U
  17.     __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断
    - u, |5 ^* S1 ]
  18.     CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);
    ) s/ h* x( p, N' Q' C" K
  19.   }  D0 x: ?) s2 D
  20.   else if(hcan == (&can2_dev.handle))* l" L. S% s0 K# A. I
  21.   {
    + o6 r7 X2 w* }$ G- G# v% {1 J
  22.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开& Q  N  M* Z9 l: t
  23.     __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断
    / ?# \! O0 j0 J$ e6 y! `8 X9 E4 @: z
  24.     CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);, D& A! J4 b$ {& }/ F
  25.   }
    3 _, ~3 D* m  w
  26. }
复制代码

7 K+ |8 B1 Q* G# \        之所以使用列表的形式,是为了方便增加和删除CAN通道和使对外的接口更统一,不会出现CAN1Init() CAN2Init(),个人习惯问题。
  a7 B( p6 I1 J, B, M$ [; B4 G4 P  U9 O3 S0 I  R! F- m  z$ a
) f2 k& ]7 u7 ~9 s

: c& z% I1 _1 j' ?) g4 v% ?# x* F; o/ C
赞 收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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