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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
一、CAN基础
$ j: I( X+ N5 K1 i' Z* P7 Z差分信号:显性电平对应逻辑0,CAN_H和CAN_L差为2.5V;隐形电平对应逻辑1,CAN_H和CAN_L差为0V。! U! A5 t* l) Z
+ q$ _' s0 k1 _6 D9 a7 n$ h
CAN总线的开始和结束都有一个120Ω的终端电阻。
/ m2 ~  [6 z8 T) M( T7 _: ^( Y7 }7 O5 S
数据帧:标准帧11位,  扩展帧29位。
3 y; n1 v9 a/ r/ t& Y. X: b% b* I, ]6 E: R' r4 m; R3 N
其他的一些理论知识就不再赘述了,可以参考维基百科对于CAN的描述。
: F; O6 y- U$ Z, K1 S
) s+ m8 W; \$ h+ J6 h' XSTM32F7xx的bxCAN主要特点:支持CAN2.0A和CAN2.0B,波特率高达1Mbps,支持时间触发,具有3个发送邮箱,2个接收邮箱,可变的过滤器组等。
' R8 ?: l7 q, J. M4 _5 H
" ]; g- c! y/ L( f6 T5 z二、几个重要的CAN函数
1 n6 w; H0 o8 Y2 K( T
  1. HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化
    1 R+ @1 J+ d# `6 ^& _) _

  2. - B, k0 w) Q8 q
  3. HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN发送
    6 \7 m$ N% R/ H! F
  4. 7 r' \+ G# O! R, y  }# ]
  5. HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收
复制代码
4 w: V9 ~/ q+ v$ i. j0 S9 z& U
三、几个重要的结构
* F( t% k  w4 H8 m9 N4 [
  1. // CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化结构 发送接收结构体 其余三个是过程变量& S1 r( T6 D( r5 V& C
  2. typedef struct
    . R/ }1 J1 |; G; V0 }
  3. {
    ! p3 f" S, L. W: X) |  v1 ~% O. A
  4.   CAN_TypeDef                 *Instance;  /*!< Register base address          */0 S5 @) I2 m# w9 l
  5. 1 F  m8 w8 Q* C) E# m4 \
  6.   CAN_InitTypeDef             Init;       /*!< CAN required parameters        */
    ' t: ?! Z3 }& W  j6 _

  7. 1 g& R9 Z8 |4 c# S' q
  8.   CanTxMsgTypeDef*            pTxMsg;     /*!< Pointer to transmit structure  */
      X4 U+ m( y2 y2 Z. K; A
  9. ) E  K4 z7 D8 T/ {% }0 m& p
  10.   CanRxMsgTypeDef*            pRxMsg;     /*!< Pointer to reception structure */
    " f4 D, i/ z; i! _" `. x- Z

  11. 3 [, f; M, ]4 E6 a/ k8 V1 e
  12.   __IO HAL_CAN_StateTypeDef   State;      /*!< CAN communication state        */
    : `& G/ T  O+ H6 t. t& l6 Y

  13. ; w/ r6 B6 R) E$ G# A9 d
  14.   HAL_LockTypeDef             Lock;       /*!< CAN locking object             */# Q3 m" ~. @2 E3 o5 F9 J

  15. " ]! x; v8 s; `" b9 u! L
  16.   __IO uint32_t               ErrorCode;  /*!< CAN Error code                 */# k" E$ ^% D( Z8 @1 ]
  17. . C& r' o, [0 _5 U
  18. }CAN_HandleTypeDef;
复制代码
  1. // CAN配置结构体
    + `! o8 V; O8 O6 h0 o$ j, l7 F% p! V
  2. // 前5个参数来设置 CAN_BTR —— 波特率
    2 U( _4 l6 s/ V+ b+ H
  3. // 后6个参数用来设置 CAN_MCR —— 通信相关的控制位; U1 i2 K0 e: N+ g
  4. typedef struct
    + s3 N" l4 N/ r. w
  5. {
      s( M6 k. b/ p* J& ]
  6.   uint32_t Prescaler;  /*!< Specifies the length of a time quantum.
    ! r/ Z3 v4 N  F& _+ X* Y) h8 L
  7.                             This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */
    % a  L' x7 x+ S$ I

  8. 4 ?4 j+ q8 w& `! ?! Y1 b9 z
  9.   uint32_t Mode;       /*!< Specifies the CAN operating mode.+ P+ G" L! y% Z# \" z
  10.                             This parameter can be a value of @ref CAN_operating_mode */
    3 A1 q7 z) N9 P, b. m5 w" I/ ]
  11. & Y* y1 \2 m/ A* g; u3 c! ^
  12.   uint32_t SJW;        /*!< Specifies the maximum number of time quanta* \. [0 |! d2 J) g
  13.                             the CAN hardware is allowed to lengthen or
    . e7 v% H2 x9 j3 }6 W
  14.                             shorten a bit to perform resynchronization.8 O- f5 N& q* d7 N. q
  15.                             This parameter can be a value of @ref CAN_synchronisation_jump_width */
    & `/ E* e/ I# S; Y

  16. 9 j; O, m9 I8 [/ V  }& C
  17.   uint32_t BS1;        /*!< Specifies the number of time quanta in Bit Segment 1.8 X5 q) @5 m/ j
  18.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 */4 O  e4 T; k8 J
  19. % C5 l9 n, y( P- B
  20.   uint32_t BS2;        /*!< Specifies the number of time quanta in Bit Segment 2.6 y" b! a! F  V9 j) |$ K
  21.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */
    8 u' u5 K- j& o+ T' U, i/ j

  22. * ?- ]! e2 D, u
  23.   uint32_t TTCM;       /*!< Enable or disable the time triggered communication mode.
    - C! c1 i  y! I+ M) r8 k# P& b
  24.                             This parameter can be set to ENABLE or DISABLE. */: j9 I) `) E; r7 ^2 G  S- w
  25. , n  F- r/ A8 ?( J" W
  26.   uint32_t ABOM;       /*!< Enable or disable the automatic bus-off management." o0 Z" ?9 Q3 u
  27.                             This parameter can be set to ENABLE or DISABLE */7 C0 b2 G  U* t2 `7 d2 H
  28. " O; T# m$ O0 t4 ?3 p# k
  29.   uint32_t AWUM;       /*!< Enable or disable the automatic wake-up mode.$ n/ S) Y" ]: k) I# E! m! J
  30.                             This parameter can be set to ENABLE or DISABLE */3 `3 o* V0 Y" J& U3 o. |* k
  31. * c" m  T8 W- {( j
  32.   uint32_t NART;       /*!< Enable or disable the non-automatic retransmission mode.* I  H2 H. W0 T# g
  33.                             This parameter can be set to ENABLE or DISABLE */
    * V% z6 g+ t% n) s, [+ ?; A% d3 b

  34. % ~6 u6 S4 u) o' Y5 t8 @
  35.   uint32_t RFLM;       /*!< Enable or disable the receive FIFO Locked mode.
    2 A4 p. W2 b) W+ `  \0 i& t7 O4 j
  36.                             This parameter can be set to ENABLE or DISABLE */! x0 E& e% M/ B' @( W
  37. 2 J3 p. {5 x0 H2 q6 e" e6 r
  38.   uint32_t TXFP;       /*!< Enable or disable the transmit FIFO priority.% d% G) f4 W8 B# f1 ^# v4 y$ z
  39.                             This parameter can be set to ENABLE or DISABLE */7 u8 Y* v" f) n! j4 M6 [: f: c
  40. }CAN_InitTypeDef;
复制代码
  1. // 过滤器设置
    7 U5 {6 a! V6 n/ ]
  2. typedef struct; n6 ^2 F4 h2 N7 J
  3. {5 I* [8 e* A2 O
  4.   uint32_t FilterIdHigh;          /*!< Specifies the filter identification number (MSBs for a 32-bit  L( U: M6 m& ?- {3 z
  5.                                        configuration, first one for a 16-bit configuration).
    1 c" T% [5 k% G3 \" h" y
  6.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */6 ^6 {  B; e% z

  7. 8 U+ d8 w3 d/ }+ B
  8.   uint32_t FilterIdLow;           /*!< Specifies the filter identification number (LSBs for a 32-bit
    9 k% Z+ X7 w8 k4 ^
  9.                                        configuration, second one for a 16-bit configuration).
    1 b% Q5 y4 {, f" a% S' D! ?9 P
  10.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    ! z4 u$ y9 @$ d! v0 p0 A
  11. & P8 i7 g' |( [: a
  12.   uint32_t FilterMaskIdHigh;      /*!< Specifies the filter mask number or identification number,7 G# q: I4 |% S) e& z
  13.                                        according to the mode (MSBs for a 32-bit configuration,# ]" a1 t! R2 [# e! y* O
  14.                                        first one for a 16-bit configuration).
    5 L: s) M" ]8 U4 S" B
  15.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    " G" Q/ j1 t* I+ C& G
  16. * w* l5 X( W! d& U" U0 l9 N) o
  17.   uint32_t FilterMaskIdLow;       /*!< Specifies the filter mask number or identification number,
    # L4 ]( `: I1 R
  18.                                        according to the mode (LSBs for a 32-bit configuration,+ e' Q& E1 P& s, W
  19.                                        second one for a 16-bit configuration).
    $ A; Z& a; w/ t1 ~3 D$ M( u
  20.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */$ v- y8 o+ }4 _
  21. $ z  N$ e5 l. T  {* ]/ S! m: t* u
  22.   uint32_t FilterFIFOAssignment;  /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.
    - y% i" I& p2 A* n+ \- `$ t
  23.                                        This parameter can be a value of @ref CAN_filter_FIFO *// H  x) Q$ i' K8 b, D; l; |
  24. 1 B2 S/ s( m1 [
  25.   uint32_t FilterNumber;          /*!< Specifies the filter which will be initialized.
    ( _' W, r5 U& \( k; Y" w
  26.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 27 */0 R4 X+ k* @! J" [# o4 M

  27. ) u. V, [" `' j3 J( \! n4 Q
  28.   uint32_t FilterMode;            /*!< Specifies the filter mode to be initialized.
    " X' r4 G9 X1 _  T7 K! j
  29.                                        This parameter can be a value of @ref CAN_filter_mode */
    3 Z8 ^0 C" W: j) \6 W
  30. # J  w9 N/ `7 [2 c
  31.   uint32_t FilterScale;           /*!< Specifies the filter scale.; B- }  w3 a2 ?
  32.                                        This parameter can be a value of @ref CAN_filter_scale */) L/ K2 r0 m$ h" r! K5 {+ I; f/ W
  33.   ]' O: ~9 v6 u& d. [$ t# A
  34.   uint32_t FilterActivation;      /*!< Enable or disable the filter.6 v# l: X; b; ]1 k7 m  s
  35.                                        This parameter can be set to ENABLE or DISABLE. */1 I+ h9 U+ O! x& }2 r: K, W

  36. ; G. c" J$ f2 `: \
  37.   uint32_t BankNumber;            /*!< Select the start slave bank filter.
    $ F, i! T; G" n
  38.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 28 */' l$ A! |9 o. w) \! ?& w
  39. ; m* b" e4 x) K3 x8 m; m- @& D. Y
  40. }CAN_FilterConfTypeDef;
复制代码
  1. // 模式  我们使用普通模式
    & y# r: l& g5 Y7 M0 u
  2. #define CAN_MODE_NORMAL             ((uint32_t)0x00000000U)                     /*!< Normal mode   */
    , \4 P5 [$ v; I
  3. #define CAN_MODE_LOOPBACK           ((uint32_t)CAN_BTR_LBKM)                   /*!< Loopback mode */
    3 H7 |7 o! B8 \+ @; Z( C- b
  4. #define CAN_MODE_SILENT             ((uint32_t)CAN_BTR_SILM)                   /*!< Silent mode   */
    % f1 ~+ c2 A/ i/ _  I" U5 T- y
  5. #define CAN_MODE_SILENT_LOOPBACK    ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM))  /*!< Loopback combined with silent mode */
复制代码
  1. // 标准帧 扩展帧9 ^+ @7 d) S: S. s, n
  2. #define CAN_ID_STD             ((uint32_t)0x00000000U)  /*!< Standard Id */
    * k& \3 ?. v. Z9 H/ H0 _
  3. #define CAN_ID_EXT             ((uint32_t)0x00000004U)  /*!< Extended Id */
复制代码
  1. // 数据帧 远程帧
    % J8 _: ^5 w$ M2 d5 }$ h" K
  2. #define CAN_RTR_DATA                ((uint32_t)0x00000000U)  /*!< Data frame */
    & E5 q; x4 ^) W5 w5 S2 m& h, i  k
  3. #define CAN_RTR_REMOTE              ((uint32_t)0x00000002U)  /*!< Remote frame */
复制代码
  1. // CAN中断使能
    ) C" w: D: o# ]8 n& V- R6 D3 @
  2. __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__)
复制代码
  1. // 接收中断& D( O. J- A: G( ]# ]3 J0 N
  2. #define CAN_IT_FMP0                 ((uint32_t)CAN_IER_FMPIE0)  /*!< FIFO 0 message pending interrupt */  J& ~' J! Y: k% }
  3. #define CAN_IT_FF0                  ((uint32_t)CAN_IER_FFIE0)   /*!< FIFO 0 full interrupt            */" ^% U4 R- L* S- ?8 t: d& U
  4. #define CAN_IT_FOV0                 ((uint32_t)CAN_IER_FOVIE0)  /*!< FIFO 0 overrun interrupt         */" n. |/ h& v. }9 p3 ?
  5. #define CAN_IT_FMP1                 ((uint32_t)CAN_IER_FMPIE1)  /*!< FIFO 1 message pending interrupt */
    4 \/ ~+ ^1 K) c( q5 j2 q% ?
  6. #define CAN_IT_FF1                  ((uint32_t)CAN_IER_FFIE1)   /*!< FIFO 1 full interrupt            */
    % j; e5 P. Y7 ?4 B$ \( @
  7. #define CAN_IT_FOV1                 ((uint32_t)CAN_IER_FOVIE1)  /*!< FIFO 1 overrun interrupt         */
复制代码

5 A* ?. f9 N1 Y) M) e2 |$ t四、接口设计
* s8 `  O! n1 C3 m% J$ J; c/ t与串口类似,使用中断接收。先封装单路CAN需要的几个小接口,再顶一个列表,最后使用统一的接口扫描这个列表。
6 i3 M2 Z+ N/ N" y( Z/ m- |3 l5 v3 z) w9 J  n
  1. typedef enum7 p; R. w/ o& A6 e) G
  2. {- `3 Z! H+ z; l: j( N# M0 `; c7 z
  3.   CAN_CHANNEL_NONE,& H2 z8 l* L6 e* |
  4.   CAN_CHANNEL_1,0 y9 f, M4 C9 R
  5.   CAN_CHANNEL_2,
    ( Q) p/ ~# O7 T1 M0 W
  6.   CAN_CHANNEL_NUM
    : V7 a, m* E' [* m2 t8 G6 H
  7. } can_channel_t;
    ( K8 M) H7 D; X7 Y$ Y4 @+ R9 E0 u
  8. + H! k' }- w1 u
  9. #define CAN1_CHANNEL              CAN1( d1 d% g, M# b+ n9 A& z
  10. #define CAN1_PREEMPT_PRIO         CAN1_RX_PRIORITY
    7 }8 S" u8 \$ ^- ]
  11. #define CAN1_RX_IRQ               CAN1_RX0_IRQn8 W; x0 m1 l! O" l' f
  12. #define CAN1_RX_IRQ_FUNC          CAN1_RX0_IRQHandler! \, ?$ v7 S, p( \5 H5 ~
  13. #define CAN1_CLK_ENABLE()         __HAL_RCC_CAN1_CLK_ENABLE()
    2 T7 y7 e4 W; E# n4 \3 O
  14. #define CAN1_TX_PORT              GPIOA
    * ~  B, n! N, v  ]
  15. #define CAN1_TX_PIN               GPIO_PIN_12  H1 K5 D& L/ {3 K5 p+ K* [* e0 Q* o
  16. #define CAN1_TX_AF                GPIO_AF9_CAN1/ R  \& i  H4 s2 r1 f, f5 Z
  17. #define CAN1_TX_CONFIG()          GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF)
    # G' T6 T" W5 W: l0 l
  18. #define CAN1_RX_PORT              GPIOA
    6 \1 }. F0 x* p
  19. #define CAN1_RX_PIN               GPIO_PIN_11
    : e3 E. d8 x. J0 F
  20. #define CAN1_RX_AF                GPIO_AF9_CAN1* Q# Q4 h5 @5 y! m- n8 Q
  21. #define CAN1_RX_CONFIG()          GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF)& S5 ^. Z6 |7 n* h

  22. 2 a; b" x& `9 O6 {+ h' f
  23. #define CAN2_CHANNEL              CAN2
    7 W+ S; S# L, C3 }* W
  24. #define CAN2_PREEMPT_PRIO         CAN2_RX_PRIORITY, ]  A1 z! X6 u5 I
  25. #define CAN2_RX_IRQ               CAN2_RX0_IRQn, `! Z. \, @; w% P8 A# l
  26. #define CAN2_RX_IRQ_FUNC          CAN2_RX0_IRQHandler" O) C' M: S3 P/ d
  27. #define CAN2_CLK_ENABLE()         __HAL_RCC_CAN2_CLK_ENABLE()
    1 C4 w- K9 i( h  ]0 u
  28. #define CAN2_TX_PORT              GPIOB
    . G" `' r: Q- ~8 E' l; U
  29. #define CAN2_TX_PIN               GPIO_PIN_6
    * [. O: `' n& h1 Z! X; _" E
  30. #define CAN2_TX_AF                GPIO_AF9_CAN2- J" c5 ^8 X0 n* @: J
  31. #define CAN2_TX_CONFIG()          GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF)
      [1 m$ m% i# S) B2 X0 K
  32. #define CAN2_RX_PORT              GPIOB* Q; }9 I, R  J8 E1 c2 A
  33. #define CAN2_RX_PIN               GPIO_PIN_5( N0 a2 O3 ~8 A5 M- T3 ?, b
  34. #define CAN2_RX_AF                GPIO_AF9_CAN2
    9 z$ S3 i5 D& G1 c
  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设备结构体
    2 O# n1 {  [+ Y. U. Z3 L. }4 C
  2. typedef struct9 z$ V% f2 L$ |! n
  3. {  h3 \1 k! R5 P' f) ^: _
  4.   CAN_HandleTypeDef handle; // CAN操作句柄
    ( S- b$ G( k, o: P& ]
  5. 7 V, t; f' s: ?# H9 h) V' h
  6.   CanTxMsgTypeDef tx;       // CAN发送
    & n! h+ m! @' k8 n3 E; x9 ~

  7. 7 c- f) i3 f$ ?1 c! n( G$ k0 \
  8.   CanRxMsgTypeDef rx;       // CAN接收* h1 m3 Z- B# R2 e

  9. 9 M- P( y7 X) ?! I
  10.   can_queue_t recv;         // 接收队列2 F0 @, ^$ c) {/ ~: H! s% K$ x* D  x

  11. * q# r8 O$ t# U, x
  12. } can_dev_t;
复制代码
  1. // 将每路CAN封装成几个小函数: I9 b; C- Z% u8 T7 g# @
  2. static can_dev_t can1_dev, can2_dev;
    ' t; @% U- x* ?* V; Q' U( P/ V
  3. 4 L" K0 m; {+ ~* G5 j1 Q
  4. static void can1_var_init(void)
    ( A% t  m! f' ~* T
  5. {
    ' C& c5 C) s% [0 X1 ?
  6.   can1_dev.recv = can1_queue_recv;6 i7 {' h- u2 ^0 c( `: p
  7. 4 T4 _  ]& I9 R! ^* ^7 U
  8.   CanQueueInit(&can1_dev.recv);# p( P2 \# S9 Z" n+ D1 t; ]
  9. }* X3 l5 w2 K- t9 d' r) J
  10. & @1 T, {- A* z. Q1 Q0 F+ j) }
  11. static void can1_gpio_init(void)1 k) h9 H" m# A, F1 z' b! f0 D& g
  12. {+ T7 B  T+ N7 ^  \6 p9 O1 Y
  13.   CAN1_TX_CONFIG();
    * a" ~' m2 \' L, B% m
  14.   CAN1_RX_CONFIG();
      k$ W. _1 q+ h# G: v" J3 o! |
  15. }
    " v6 O- T9 ~# J
  16. ; T: S, W* T, g% J- S; v
  17. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M: u& J) \! K* p& n6 A  [
  18. static void can1_mode_init(void)
    1 D% z& ]* s6 }; A! U; C* |
  19. {! H; _9 }9 L2 h0 m) v
  20.   CAN1_CLK_ENABLE();
    $ X, s3 Q1 |7 E( i; f

  21. & e( o3 D" @8 L5 m) O" T! V
  22.   can1_dev.handle.Instance = CAN1_CHANNEL;
    - u5 u4 W- ^" g
  23.   can1_dev.handle.pTxMsg = &can1_dev.tx;! l2 R0 X/ u. x, |
  24.   can1_dev.handle.pRxMsg = &can1_dev.rx;9 A# L3 V7 C1 a7 Q4 C2 h; v# H$ {
  25.   can1_dev.handle.Init.Prescaler = 6;! w: l( q6 U6 `
  26.   can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;
    7 Q8 L$ a; s- E) w" s
  27.   can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ' _; T( D1 a1 M
  28.   can1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    . L7 ]& L- i& B( \  p9 v  |
  29.   can1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ" j$ l! Q9 \* g
  30.   can1_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    0 }; V& r7 G) O/ t0 q1 t/ P8 ~
  31.   can1_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理' m, o8 m/ C9 O3 w& ^1 D! C
  32.   can1_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)" Y: D3 q; i9 `5 ?
  33.   can1_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    ( H5 z) `2 W6 z0 j, W% }( Q5 Q" F
  34.   can1_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的8 B6 e: A  U2 ^( i6 U5 g* }
  35.   can1_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定7 i& L! b" v3 L* t4 ]6 L
  36.   HAL_CAN_Init(&can1_dev.handle);0 j  f0 o" {* w' K" ]7 c
  37. }* a6 |9 o8 |' P. P
  38. 2 M1 O, C- J! }/ E
  39. static void can1_filter_init(void)
    % j1 X, W# p( k/ Y# n
  40. {
    , G1 y& I3 C0 P+ p8 R6 L$ ~
  41.   CAN_FilterConfTypeDef  filter;
    - H6 s+ g/ \. _# G- V" m  q

  42. 9 ~2 c) G  I- S/ a
  43.   filter.FilterNumber     = 0; // 过滤器0
    0 g; B8 d4 W8 |4 x0 D( p
  44.   filter.FilterMode       = CAN_FILTERMODE_IDMASK;
    5 I6 l, E) [$ u* g
  45.   filter.FilterScale      = CAN_FILTERSCALE_32BIT;
    ' Y! U* k5 [0 j  h) P

  46. 4 Z/ s; k" z% {. \
  47.   filter.FilterIdHigh     = 0;
    ' H5 r( o2 N: J2 j# Y
  48.   filter.FilterIdLow      = 0;; r; z4 |9 o, s- s) i; q- V: j; k
  49.   filter.FilterMaskIdHigh = 0;- @8 ?2 a* Q& @9 T( h6 M+ U
  50.   filter.FilterMaskIdLow  = 0;) H& g  t" V  ~/ X, F
  51. 4 k. s) Q0 Q+ e" N3 z5 q
  52.   filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO02 J7 ]0 H8 j1 Z! ~5 [9 Q
  53.   filter.FilterActivation = ENABLE; //激活滤波器0
    9 D1 L6 @9 P1 N$ m! [, |9 q) A
  54.   //filter.BankNumber=14;/ M6 `" V6 E' t5 Z( [- s5 }# i) j/ v% ^

  55. ; V0 ]& ]& s3 h+ m, y/ ]3 c( e- g
  56.   HAL_CAN_ConfigFilter(&can1_dev.handle, &filter);
    9 y# N* t2 Y; J' d' Q' i
  57. }( l) s& W/ Y0 S! \) Y

  58. 3 S4 C! F2 h" \, ]8 j+ M0 `5 W# [
  59. static void can1_nvic_init(void)% l3 @/ B7 b9 ~, L, `
  60. {
    + d" n5 y# E6 Z' R
  61.   __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许.
    * D8 [7 Y# o, C3 j$ K
  62.   HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);
    ( u! Y) a* v4 f; Y2 J
  63.   HAL_NVIC_EnableIRQ(CAN1_RX_IRQ);
    + ?- k! g- b1 m' a% |
  64. }
    + v+ a" m: F1 f* Y
  65. % Y% z  f- G# |7 L* D
  66. * T6 K: K, s/ y5 @& b4 _5 I# {

  67. 1 w: F5 t0 U$ o- z% x+ ^
  68. static void can2_var_init(void)
    1 C( N+ V2 v4 p: }/ p, Z' h
  69. {
    : V9 Y% y4 U& A# ~2 ~, `, q7 _" w" o
  70.   can2_dev.recv = can2_queue_recv;
    ) m* |% |% n6 Q. v  v/ Z/ s) f% I6 C
  71. * C! I0 d( Q% }6 F8 ?
  72.   CanQueueInit(&can2_dev.recv);9 ~7 j( Q- z* X0 h' {6 h5 C
  73. }
    ; E" f3 o" j% i, }7 q1 Q
  74. 7 @/ o; \5 @% c7 E6 P, Z
  75. static void can2_gpio_init(void)0 \" a; b& o% g5 d- U* U8 L" g' U8 u
  76. {
    ' ^6 d7 R- u# p
  77.   CAN2_TX_CONFIG();9 f6 A9 X. w8 x, ^4 N* `7 O
  78.   CAN2_RX_CONFIG();
    : K! G9 J* K; }# s, y) r5 X4 e' z
  79. }
    # E7 Q" V- W+ P$ ~

  80. + l: @7 G$ ~. R2 |1 o
  81. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M& a+ B  N( I6 S0 C: z) r% J) l2 s
  82. static void can2_mode_init(void)# J1 U; k" E2 X" N4 d# |
  83. {
    7 k6 n+ e" z/ F4 a4 S$ o
  84.   CAN2_CLK_ENABLE();
    ( t+ L  O) |; K( M4 [

  85. ' u# w  p, H' b
  86.   can2_dev.handle.Instance = CAN2_CHANNEL;# B. ?% q' J( r3 E9 b0 W. w
  87.   can2_dev.handle.Init.Prescaler = 6;8 R- d; p6 }" D: V, F( d
  88.   can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;
      o9 i* B. c/ h0 O/ @2 h/ D
  89.   can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    & R0 L; Q5 g* @  i2 m
  90.   can2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ* c" k; ~1 g; J/ b
  91.   can2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ5 @" T# n/ A) J( Y6 K& A: E# }, f
  92.   can2_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    5 c: z. H" m. T" @- f1 t; i8 |' T
  93.   can2_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理5 l2 Z" N& I) m! M/ u3 O0 }: e( u7 _
  94.   can2_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)( _6 s: T- S8 M6 f# @
  95.   can2_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送! |7 Z# R, S6 o- j/ }
  96.   can2_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的) E  z4 p" V/ x3 G) N, L' o
  97.   can2_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定8 V+ H" r9 e3 T1 h% A! Q; w4 r; p
  98.   HAL_CAN_Init(&can2_dev.handle);
    3 N6 ?- x0 \0 K4 R% f3 k. E1 R7 f
  99. }
    ) y: r4 E9 I; p& a; ~% D, Q
  100. ) G) [6 D6 I2 ~! ^( O
  101. static void can2_filter_init(void)# \5 F8 B, W( w) K5 n& d' A
  102. {: w6 |0 q) b3 s
  103.   CAN_FilterConfTypeDef  CAN_FilterInitStructure;
    6 G. {  T* t+ R% V* V" L" C' X' s) a* ~
  104. ' V% \, y9 I: j: Q
  105.   CAN_FilterInitStructure.FilterNumber     = 14;9 B4 A7 Q) p6 f/ U4 g, p% X" p
  106.   CAN_FilterInitStructure.FilterMode       = CAN_FILTERMODE_IDMASK;9 b" ^1 z9 S8 H  F( V. t
  107.   CAN_FilterInitStructure.FilterScale      = CAN_FILTERSCALE_32BIT;7 f! S! O, r9 U6 W
  108. # L. f7 _# f6 N. ^- k
  109.   CAN_FilterInitStructure.FilterIdHigh     = 0;0 X! `" c0 w# a: X9 j
  110.   CAN_FilterInitStructure.FilterIdLow      = 0;- I: f! @. F1 ^
  111.   CAN_FilterInitStructure.FilterMaskIdHigh = 0;
    3 m' r1 C8 R. l  i$ e& l
  112.   CAN_FilterInitStructure.FilterMaskIdLow  = 0;- |# E2 I0 j8 P! z8 v$ Z

  113. ' ]5 l/ ^  V$ ]& u
  114.   CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO07 s& L; ~4 I, `( @$ K
  115.   CAN_FilterInitStructure.FilterActivation = ENABLE; //激活滤波器0$ @' C3 ^  a1 @( ]! L  M
  116.   //CAN_FilterInitStructure.BankNumber=14;
    , B6 o7 M" |3 @

  117. : Y* M) c# c( R
  118.   HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure);
    ; K9 ^' ^4 A$ ~( M9 u2 J
  119. }
    * r( }% n1 I& Q& d8 \. E

  120. 9 o& h% p' }0 [# Y7 Z; P
  121. static void can2_nvic_init(void)+ G4 ?. i3 i5 I" ?
  122. {
    - `- X; ?! ]3 X- X0 B' j! v
  123.   __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许1  R; P/ _% y/ p) x+ P' N4 k
  124.   HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);( X# L3 a& ^$ g$ v, O
  125.   HAL_NVIC_EnableIRQ(CAN2_RX_IRQ);8 U+ [: F" x6 V* G) f/ t
  126. }
复制代码
  1. // 每路CAN都有的几个操作,使用列表包含,然后统一扫描处理9 [  [) x+ u( p2 N
  2. typedef struct
    ) Y. F. s3 w6 S
  3. {. b) ~9 P1 u% e8 N6 A5 e7 C
  4.   uint8_t channel;# b& Z1 [; V; `0 z* e, y8 s. D* }
  5.   can_dev_t *dev;. }1 b$ y4 V% N! c: Z/ N, n' K
  6.   void (* var_init_cb)(void);
    - ^4 G! Z% U2 T/ Y9 D; M# m' t' G) R
  7.   void (* gpio_init_cb)(void);
    ! O4 @3 e5 R- e$ e6 {
  8.   void (* mode_init_cb)(void);: c# s0 n7 O0 a8 f( x8 y0 O
  9.   void (* filter_init_cb)(void);
    2 r: @1 h2 \' ~# ], u6 }5 F, ^
  10.   void (* nvic_init_cb)(void);2 Z' K; p0 w; U9 G6 ~
  11. } can_config_t;
    0 i* M5 U% W. _" U( z/ h, A

  12. ; J4 O0 a! G5 ^, q& K$ q
  13. static const can_config_t can_configs[] =
    ) v/ E5 Q2 p' W5 t
  14. {8 I! L. V5 ^7 A4 H/ _! y4 B' c) q; W
  15.   {CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},' n  c+ m7 O' A  l+ Z
  16.   {CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init},- ]& L  V, e, H) V% T6 D1 S
  17. };
    * D  s& V7 o* d2 k5 u. \

  18. 5 q4 w" U6 l4 E+ ^# G6 j) r6 I, p
  19. static can_dev_t *can_dev_get(uint8_t channel)8 O& i( a; X% r- t4 \
  20. {# x- c1 i# `, j. U6 E
  21.   uint8_t i;' _3 m9 B' l# ^0 W2 d. ~; z
  22. & {% E) u- m7 v1 ~" v  a5 j
  23.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)/ S' _4 v: e4 Q  j
  24.   {
    & g  `! O8 {; V+ {3 l! F7 p) `: q
  25.     if(channel == can_configs<i>.channel)8 P2 Z" r. C3 v/ F
  26.     {% U2 |0 n9 n" q- r% M- Q
  27.       return can_configs<i>.dev;
    9 [, S* t; N4 U& W1 s
  28.     }( [2 T; j9 e1 A4 Z* ~  y4 R
  29.   }
    3 k1 t6 W+ d% o8 N
  30. 8 L( d% I6 L: k* c' B
  31.   return 0;% K- Y# {4 v0 P
  32. }2 Z9 P- C6 A2 B9 ^& y1 Z
  33. 9 X0 z# E  a5 Y# X
  34. static void can_var_init(uint8_t channel)
    - l, j. j( O7 k  p. I+ o$ G3 x
  35. {
    ( y. s3 G1 K2 d! C+ o. g
  36.   uint8_t i;
    3 U) {; {+ w7 I* Z0 z
  37. ! K: v3 ^9 W1 h: o; r& v; r$ G
  38.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    # h' E0 N. R0 b: F% @; _6 b& A/ [
  39.   {
    ! J8 c' a! z  n
  40.     if(channel == can_configs<i>.channel)& N& v' {* B7 E
  41.     {
    1 D2 j' t7 e& |5 T7 S; R
  42.       can_configs<i>.var_init_cb();
      k' P2 o: D- x6 i$ G0 q5 R, f
  43.       return;
    : u8 P$ Z+ ^6 E- x# g% ~
  44.     }, U- e) K  \; [- Q' v4 T
  45.   }
    # r( i. F' L& h8 z+ J' {
  46. }# v9 u4 T5 S# k) p
  47. , k6 Z: p4 i3 O: \' A) s3 y
  48. static void can_gpio_init(uint8_t channel)
    4 a1 N4 k8 S0 E: j! r6 L2 f+ R
  49. {- n! V! y% G4 g$ C
  50.   uint8_t i;7 U! `" r+ u7 M+ p

  51. 7 c; H" g; o4 P
  52.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)0 L$ z% |+ @" c0 B
  53.   {
    , y& z  {# v1 g
  54.     if(channel == can_configs<i>.channel)8 N& k/ G0 O8 h3 {
  55.     {
    9 F; f; i6 w; g9 I7 ^# e; B) E( g* f
  56.       can_configs<i>.gpio_init_cb();
    ; |/ h/ \- K8 i6 y/ q+ ~) Q
  57.       return;
    7 `: D0 v! G. W& T+ {( M1 U$ ]: c! ?! J
  58.     }# ]) C/ n% R; d& n, ^; V8 Q: |7 C
  59.   }6 [  g, w3 G' a* J0 ]- Y" F. h
  60. }
    + I7 i0 [5 I, o4 T) N9 R2 a
  61. , M7 ^( t- O/ N8 l0 x9 R' y/ D( g6 m" x
  62. static void can_mode_init(uint8_t channel)* Z5 X& h- q, j
  63. {
    , v7 n" i, c) |& N9 b' v6 c
  64.   uint8_t i;; H2 v8 _; {6 z/ O+ l) N# S0 X) @. V
  65. . ^9 }1 |9 d% H. u9 |2 n! n
  66.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    : W0 V1 L( v- s9 {; [) q
  67.   {8 N1 m: K) |: N7 N2 c
  68.     if(channel == can_configs<i>.channel)
    7 r! X6 `6 u) a5 B- f6 \2 B
  69.     {  k0 r$ |  Q% l; q9 J- Y6 |4 _* w: ?
  70.       can_configs<i>.mode_init_cb();! l: q5 _" T) z) h, I7 e
  71.       return;- G4 y- F0 B8 v/ j; H$ ^' v
  72.     }
    2 T% p- |+ l+ I/ R  A
  73.   }
    ' O+ @' W; N& O5 ~
  74. }% P4 K& n2 S2 R% s1 {: c

  75. 8 f/ x3 [: G7 p1 E+ ^5 i' g
  76. static void can_filter_init(uint8_t channel)( g0 X, l/ p9 ?( k
  77. {
    2 }; c# j+ ~* ]5 M9 `
  78.   uint8_t i;3 w3 A! R8 q. c# Q

  79. ' z/ S; A# [. {6 O0 l! @0 h9 ?6 R
  80.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    " F  w! \! X. ^% F7 o
  81.   {
    ; S8 {! p! N" w
  82.     if(channel == can_configs<i>.channel)
    5 l4 R+ L' @( N& q0 F# E
  83.     {/ w( f  X% A3 _6 m( ^" z! P
  84.       can_configs<i>.filter_init_cb();% n# M3 ^1 Y2 L/ L0 E
  85.       return;
    ' D. Y" f  a0 M- y
  86.     }% U$ X$ F1 O  \! h) S
  87.   }
    " S$ r! q6 ?  r& ?9 |2 N4 l5 R' p
  88. }: i/ Q& P* I3 E$ R8 a3 k

  89. , k1 ~8 j0 |0 y7 J9 W( ]% e$ ?
  90. static void can_nvic_init(uint8_t channel)
    4 A7 U) C: I* Y0 D; Z/ S
  91. {
    4 m# W; M2 s- p
  92.   uint8_t i;" C6 F* d* t& S7 E% A! N4 @

  93. / q+ W+ u  u& A
  94.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    * d# r. K7 C: o- _  S1 X0 y
  95.   {: _( a" n3 ~; J! h/ c. S
  96.     if(channel == can_configs<i>.channel)
    $ S9 h% G2 g- K, }4 H7 o! N4 d
  97.     {9 D. u% _2 O0 v4 ?5 r1 Q5 B
  98.       can_configs<i>.nvic_init_cb();
    0 Q1 |4 ?$ l; c3 r% R/ R) o
  99.       return;0 n0 t6 _# y0 w6 a+ O
  100.     }
      l" m5 ]1 b* w8 m+ P5 ^% D- O
  101.   }
    1 f/ y' c9 _. g. X0 t
  102. }</i></i></i></i></i></i></i></i></i></i></i></i>
复制代码
  1. // 对外的接口 初始化 发送和接收
    5 z* M; J, R, }" d. s1 q. i- w* L
  2. void CanInit(uint8_t channel)7 l7 b6 H! m) A# o) x. y' _' K
  3. {
    % B! P+ y7 D3 U# j, r- }
  4.   can_var_init(channel);, T6 [4 }# _9 U: r+ d
  5.   can_gpio_init(channel);7 ]) ^! I8 [: S& Y; s, }6 s) l
  6.   can_mode_init(channel);
    9 f- X9 J' T* F; n% d) t$ v9 w
  7.   can_filter_init(channel);
    2 S. _$ R% k: ^7 M
  8.   can_nvic_init(channel);
    ) b4 u5 s2 x! T; O
  9. }( {- A# y3 b5 d( m" W

  10. % w4 |, B0 b; ^  I
  11. void CanSend(uint8_t channel, can_frame_t *frame)
    / h+ R0 O, w, B
  12. {# f7 m, X8 Y' I2 l" w5 [
  13.   can_dev_t *dev = can_dev_get(channel);
    " U7 O, b! V8 `; [
  14. : Q$ q: |0 g( K& |6 ~: g
  15.   if(dev == 0)1 b+ q$ q8 g; C  U+ M  H! f
  16.   {7 s. _1 A; Y' k( T4 H
  17.     return;
    / u7 z; Q, V5 i- L' \# }+ k+ C- l% Z
  18.   }
    / ^. \: |9 u3 l7 Y; [
  19. 5 r% k& G' c2 K: b
  20.   dev->handle.pTxMsg->StdId = frame->StdId;
    + w1 i5 n# y# G1 ?
  21.   dev->handle.pTxMsg->IDE   = frame->IDE;& O1 V4 e3 H, A) J7 K0 \
  22.   dev->handle.pTxMsg->RTR   = frame->RTR;; B0 }  }* `, Y
  23.   dev->handle.pTxMsg->DLC   = frame->DLC;
    9 T. w. X& \, C! R* O) H
  24.   memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);
    : H7 N( `1 ?% u
  25. + d) x. W$ W, ]5 ~  I6 ]
  26.   HAL_CAN_Transmit(&dev->handle, 10);
    6 ]5 ?0 ~$ m( X! E2 r5 a
  27. }
    3 b! f9 ~$ ?0 `

  28. - z$ G, Y/ T7 g" s
  29. uint8_t CanRecv(uint8_t channel, can_frame_t *frame)
    * K& h) l' O+ I+ f' S
  30. {% o) c5 j8 F' g) g7 x' q! a% P
  31.   can_dev_t *dev = can_dev_get(channel);
    2 X4 \0 F, c) Y$ }
  32. " [# @# G, Q5 O1 j! S( E
  33.   if(dev == 0), W; C  e1 A* O3 i( W7 ^& t6 g
  34.   {6 B' \, }: G) X/ i" x$ z5 S4 u$ r
  35.     return 0;
    9 V; f% s* X) g: d5 N* F& w( d
  36.   }# I; S6 O; T* a$ k% n; E
  37. : Y, ~& t! c5 g: I
  38.   return CanQueueRead(&can1_dev.recv, frame);* g- O6 v# p+ r; Y8 [: W
  39. }
复制代码
  1. // CAN中断
    # [- t3 n( _3 D
  2. void CAN1_RX_IRQ_FUNC(void)
    # T% ]: e8 W8 f$ p2 \- v
  3. {$ f( l# L4 r( J" W7 i; |5 i
  4.   HAL_CAN_IRQHandler(&can1_dev.handle);6 A2 L# Y- D7 _1 @) `
  5. }
    . |8 S5 B5 x1 C+ t& [
  6. 0 o  h, C9 I9 h& W8 a& J- T
  7. void CAN2_RX_IRQ_FUNC(void)- C$ g1 {8 m1 N/ k2 }( x
  8. {
    / E  R& Q8 Q" _: G! Y4 j
  9.   HAL_CAN_IRQHandler(&can2_dev.handle);
    ( t3 W% j; i/ ]; J
  10. }
    - x2 v- w4 Z0 _8 y% G3 q( l- `

  11. 6 _( S+ ^1 d( T+ {* {: ]7 I8 B
  12. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)( G& b1 [. F4 T3 _( B
  13. {
    ) g  h3 V+ v) p0 }" t
  14.   if(hcan == (&can1_dev.handle)); z, F) w0 D+ `( x- B
  15.   {2 O- j4 s7 y$ M6 O- Y
  16.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开4 W, R3 Y! s$ x  o2 B0 n. L- L
  17.     __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断
    " a, u" I) {" Z$ g
  18.     CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);
    # `% o& |! i5 o( k
  19.   }, W! g' p% m. S! E
  20.   else if(hcan == (&can2_dev.handle))  A# P# a$ R0 I6 j
  21.   {
    2 J$ W# V5 e: P' I5 N% k
  22.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开
    3 q6 I, f* D7 G# y' k5 K
  23.     __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断% P/ S8 A, ]1 W! X5 R  i" I0 E, ?
  24.     CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);
    ' N4 _: k. w* k& j7 s
  25.   }
    / W, l( D7 W# U
  26. }
复制代码

: f: T9 c' y' n# p; u* X1 T* {        之所以使用列表的形式,是为了方便增加和删除CAN通道和使对外的接口更统一,不会出现CAN1Init() CAN2Init(),个人习惯问题。( j- m; x& p  q% A
; l1 ^" p% n" K* m

! U1 W- X# G8 V$ F( W9 [0 v- |
& Q* h  H; Q9 t% x' _! _& O
& B1 q7 d: k% g- e
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版