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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
一、CAN基础
4 J/ S2 Y, k- l. @差分信号:显性电平对应逻辑0,CAN_H和CAN_L差为2.5V;隐形电平对应逻辑1,CAN_H和CAN_L差为0V。
) `" m9 S  v) @! ?" u- N7 T0 @$ [) G1 L9 H1 u; H( l
CAN总线的开始和结束都有一个120Ω的终端电阻。. U$ m" X5 y/ ]6 t8 S( f
  W" a) C/ I1 @5 \
数据帧:标准帧11位,  扩展帧29位。
" x" j; w, r2 X
& L0 H) l/ l4 \# V4 v$ E其他的一些理论知识就不再赘述了,可以参考维基百科对于CAN的描述。
3 I7 B6 s. `- f, K  T  C0 h
6 w. |8 q. k) s- mSTM32F7xx的bxCAN主要特点:支持CAN2.0A和CAN2.0B,波特率高达1Mbps,支持时间触发,具有3个发送邮箱,2个接收邮箱,可变的过滤器组等。
! b0 ]! M! g- f7 z, o6 N- V2 d+ z& x& l4 ^
二、几个重要的CAN函数
" V# k: ?  q3 s6 Q( S' X+ b& z' V
  1. HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化
      s; v, Z) P1 M) X: S

  2. 6 y( M6 A( @: x, H. o
  3. HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN发送6 u- F7 A1 z" o( ~# x/ l- i0 D

  4. / a- }- i: y8 k5 e) U+ o
  5. HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收
复制代码

! D) j0 m5 Q" y7 I: I6 I# d三、几个重要的结构* C; \( V  U3 S+ O8 d% r$ Z
  1. // CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化结构 发送接收结构体 其余三个是过程变量* [. Q' w7 F8 @  w
  2. typedef struct# k* D6 Z, ~5 k( z1 J
  3. {
    - k2 d) d* I, ^8 ]6 Y
  4.   CAN_TypeDef                 *Instance;  /*!< Register base address          */
    9 i# `6 j  ]1 \' u9 X# {
  5. ! d. F4 K; b6 q1 G1 o1 L+ S
  6.   CAN_InitTypeDef             Init;       /*!< CAN required parameters        */. T/ \/ d5 l* ]3 R* ]9 X
  7. ( S+ f/ \7 w6 T+ j
  8.   CanTxMsgTypeDef*            pTxMsg;     /*!< Pointer to transmit structure  */
    8 `% x& F& m" x" I
  9. 0 e, p9 `. ^8 o9 @
  10.   CanRxMsgTypeDef*            pRxMsg;     /*!< Pointer to reception structure */
    $ d4 P) A4 |! ~- \; M0 j
  11. : A* b" P$ J2 G% ~+ F. u% }# Z
  12.   __IO HAL_CAN_StateTypeDef   State;      /*!< CAN communication state        */
    7 R+ K. N* _! J. ^3 M" e/ g

  13. / o2 |+ h7 S. k* i
  14.   HAL_LockTypeDef             Lock;       /*!< CAN locking object             */  P. w9 z8 a+ ~0 F

  15. 8 S- ~4 F: W# l/ i; n
  16.   __IO uint32_t               ErrorCode;  /*!< CAN Error code                 */
    2 u5 _/ Y  c! x, {/ Q+ F

  17. ) Z0 F& C' H; q8 `7 M0 j7 n* U
  18. }CAN_HandleTypeDef;
复制代码
  1. // CAN配置结构体 * O3 w% m, g& T& @: A/ W9 u2 {
  2. // 前5个参数来设置 CAN_BTR —— 波特率' N$ s' F% {, W6 x5 q; ]- o
  3. // 后6个参数用来设置 CAN_MCR —— 通信相关的控制位  ~8 V6 f$ U8 f" S$ G7 D3 g
  4. typedef struct
    * h3 d3 h. ~" o6 _; g3 _
  5. {
    2 [0 Z+ [- G+ Z* F' d: n
  6.   uint32_t Prescaler;  /*!< Specifies the length of a time quantum.; ~* \# Z  a3 r- n% q3 P
  7.                             This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */
      Q8 ^7 X8 L8 u% _- R6 i

  8. : Z4 ~) [  [1 S6 R, G1 M% p
  9.   uint32_t Mode;       /*!< Specifies the CAN operating mode.* Q! e# |6 x! w" F
  10.                             This parameter can be a value of @ref CAN_operating_mode */
    & w0 E: I& D) v( @3 l, F6 U$ y  c

  11. 8 M& u9 A" J% i% V
  12.   uint32_t SJW;        /*!< Specifies the maximum number of time quanta
    4 C( d# q% T, X' f, l- c/ n$ r& J
  13.                             the CAN hardware is allowed to lengthen or: j8 V! o) `8 j+ P( b
  14.                             shorten a bit to perform resynchronization.
    ! ?# u) h, W) h
  15.                             This parameter can be a value of @ref CAN_synchronisation_jump_width */. k) I9 z3 m4 z$ X: l
  16. . c8 u. M. q9 C1 b
  17.   uint32_t BS1;        /*!< Specifies the number of time quanta in Bit Segment 1.& K) _  g& D+ k* F, o; @% V6 R
  18.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 *// x) c4 {* O& D

  19. * h/ i5 @  r) r" x& O. k+ X
  20.   uint32_t BS2;        /*!< Specifies the number of time quanta in Bit Segment 2.* y: \5 X9 p5 x; y+ [+ h  {% L
  21.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */
    6 D5 \0 Q' B9 t8 L
  22. & E4 b6 f, V: T8 g2 z& d
  23.   uint32_t TTCM;       /*!< Enable or disable the time triggered communication mode.
    . O9 w/ @$ k+ `& d! J
  24.                             This parameter can be set to ENABLE or DISABLE. */
    4 Y6 S# V- w- g9 R
  25. . h( K! z% d. B  d( @3 x
  26.   uint32_t ABOM;       /*!< Enable or disable the automatic bus-off management.
    0 _9 [, M& m- R9 Z2 U0 N1 J
  27.                             This parameter can be set to ENABLE or DISABLE */
    8 f9 x, O' c- x2 g3 C: ^& G% ~

  28. 8 I+ Y7 E) i0 |3 L! C' Z, B
  29.   uint32_t AWUM;       /*!< Enable or disable the automatic wake-up mode.: {3 T- g0 q/ U' ~( ]+ B9 _& l; R
  30.                             This parameter can be set to ENABLE or DISABLE *// c4 G* Q) R- v$ O" t8 d# i7 R0 {! }
  31. 4 Y! W: [: H+ O3 ~8 \7 B/ R! d
  32.   uint32_t NART;       /*!< Enable or disable the non-automatic retransmission mode.
    6 K5 K+ U3 I3 D  x7 C% t
  33.                             This parameter can be set to ENABLE or DISABLE */
    3 V$ w4 Q! @. H: X( v1 x% O
  34. , S3 s+ n4 b) U* d) \7 ]
  35.   uint32_t RFLM;       /*!< Enable or disable the receive FIFO Locked mode.
    & }3 T8 n" [0 {( S3 o7 [# \
  36.                             This parameter can be set to ENABLE or DISABLE */# _1 g# x% X! O$ U4 k5 [2 C
  37. 0 g; G" ^) a$ e2 w2 y! s0 {
  38.   uint32_t TXFP;       /*!< Enable or disable the transmit FIFO priority.
    $ J0 m" Y, M, `( p+ X4 q) b7 y7 N/ Q; G
  39.                             This parameter can be set to ENABLE or DISABLE */9 N0 R% a! |5 ~) K6 J5 v% M  L, L
  40. }CAN_InitTypeDef;
复制代码
  1. // 过滤器设置
    , N) h% k- B! @( [4 e, t
  2. typedef struct  S7 v( \$ V2 e9 M8 U/ c7 l( h
  3. {5 J9 |! o* g+ a- D! q, Q  T' X
  4.   uint32_t FilterIdHigh;          /*!< Specifies the filter identification number (MSBs for a 32-bit# J. I& t1 S9 {' S
  5.                                        configuration, first one for a 16-bit configuration).! |, B8 q9 G* z
  6.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */$ O$ p  [5 `% t7 V9 D6 i

  7. 9 a( T$ x6 ]+ w5 u$ h6 o  I: @
  8.   uint32_t FilterIdLow;           /*!< Specifies the filter identification number (LSBs for a 32-bit
    : I) @; c  t# U# }
  9.                                        configuration, second one for a 16-bit configuration).; w- @# Q) V3 n& A" a2 L- G0 I* k
  10.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    2 `7 O0 P: ^+ Z# i
  11. " E: F1 {9 p: H3 h7 s
  12.   uint32_t FilterMaskIdHigh;      /*!< Specifies the filter mask number or identification number,7 T$ c- B9 V! U% A% ~
  13.                                        according to the mode (MSBs for a 32-bit configuration,$ F0 Q3 V5 a$ c/ x+ ^
  14.                                        first one for a 16-bit configuration).+ q8 I' M/ i" S1 [- L
  15.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    % ^2 N4 P6 s9 q

  16. 0 ]+ p# W; Y$ W6 w  Q  w8 H4 S
  17.   uint32_t FilterMaskIdLow;       /*!< Specifies the filter mask number or identification number,
    $ ~$ |- j0 V" D# N% d* j% j
  18.                                        according to the mode (LSBs for a 32-bit configuration,
    2 o- ]# ~4 r4 N; q3 u
  19.                                        second one for a 16-bit configuration).( j) e8 A  {- y
  20.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */$ ~. i+ W/ c/ r  U. g4 G

  21. 7 h. o, t$ r7 X* Q% n) v
  22.   uint32_t FilterFIFOAssignment;  /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.
    # m7 T4 G% `# e* T' q+ A& P0 H
  23.                                        This parameter can be a value of @ref CAN_filter_FIFO */- J( x3 `; I! M4 |8 y
  24. 7 h$ h% m! J" M( P% I
  25.   uint32_t FilterNumber;          /*!< Specifies the filter which will be initialized.
    ( z+ D& w  g; ^+ E( d2 s
  26.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 27 */' V+ Q( j$ R* K9 x; A, }

  27. $ b  f" i2 i* ^. O. }
  28.   uint32_t FilterMode;            /*!< Specifies the filter mode to be initialized.6 r: U7 t- s1 x" I$ p3 C% H7 R
  29.                                        This parameter can be a value of @ref CAN_filter_mode */
      \0 u7 J0 n% G' C( l

  30. 1 j- o# D$ _9 Z. V. R* H$ l/ p
  31.   uint32_t FilterScale;           /*!< Specifies the filter scale.
    . _. d& i# Y. u# O' F+ @  O
  32.                                        This parameter can be a value of @ref CAN_filter_scale */) l6 m' \* s! q. z" C. c. H
  33. ' C% W3 d, q8 H; G5 R+ w% q, d
  34.   uint32_t FilterActivation;      /*!< Enable or disable the filter.2 U1 Q/ O  M1 y. p( e. [1 l0 c6 Y
  35.                                        This parameter can be set to ENABLE or DISABLE. */3 T; {0 J8 A3 M5 k- H( i8 \1 f

  36. 7 j9 I/ ^. x' |% \3 R4 F
  37.   uint32_t BankNumber;            /*!< Select the start slave bank filter.
    . d" \8 ]# z3 M/ a( l& P2 X
  38.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 28 */. K8 {$ B  `. c0 N: F
  39. 4 \$ }" J+ q2 a9 j$ B
  40. }CAN_FilterConfTypeDef;
复制代码
  1. // 模式  我们使用普通模式
    * t1 H6 Y, p9 G7 j  t
  2. #define CAN_MODE_NORMAL             ((uint32_t)0x00000000U)                     /*!< Normal mode   */
    $ H) z" @; `1 g4 h! `
  3. #define CAN_MODE_LOOPBACK           ((uint32_t)CAN_BTR_LBKM)                   /*!< Loopback mode */
    8 r% ~; m' L% k/ I# j: b1 E3 u
  4. #define CAN_MODE_SILENT             ((uint32_t)CAN_BTR_SILM)                   /*!< Silent mode   */
    6 I, U5 v8 n, ^0 z- R0 w+ L7 ]2 o
  5. #define CAN_MODE_SILENT_LOOPBACK    ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM))  /*!< Loopback combined with silent mode */
复制代码
  1. // 标准帧 扩展帧! f9 Y3 \7 R5 \6 u9 W
  2. #define CAN_ID_STD             ((uint32_t)0x00000000U)  /*!< Standard Id */
    ! I3 f& c: t7 V9 S& z! g
  3. #define CAN_ID_EXT             ((uint32_t)0x00000004U)  /*!< Extended Id */
复制代码
  1. // 数据帧 远程帧
    9 ?! W1 C9 o( m
  2. #define CAN_RTR_DATA                ((uint32_t)0x00000000U)  /*!< Data frame */& Q: S- K  B6 a* r1 f: U
  3. #define CAN_RTR_REMOTE              ((uint32_t)0x00000002U)  /*!< Remote frame */
复制代码
  1. // CAN中断使能
    ( V1 n7 c0 ]" y
  2. __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__)
复制代码
  1. // 接收中断+ M  v$ Q3 a1 I
  2. #define CAN_IT_FMP0                 ((uint32_t)CAN_IER_FMPIE0)  /*!< FIFO 0 message pending interrupt */9 F" W) C$ D* n8 v/ J  r& I
  3. #define CAN_IT_FF0                  ((uint32_t)CAN_IER_FFIE0)   /*!< FIFO 0 full interrupt            */: X1 J3 v- b$ p' W: k5 T" {
  4. #define CAN_IT_FOV0                 ((uint32_t)CAN_IER_FOVIE0)  /*!< FIFO 0 overrun interrupt         */
    / J& r, e* ]5 ~8 H  d
  5. #define CAN_IT_FMP1                 ((uint32_t)CAN_IER_FMPIE1)  /*!< FIFO 1 message pending interrupt */+ e0 j1 k% i& d4 T6 ?6 a' `$ V( e
  6. #define CAN_IT_FF1                  ((uint32_t)CAN_IER_FFIE1)   /*!< FIFO 1 full interrupt            */: {: q( G6 T: K, X) Q& o  W
  7. #define CAN_IT_FOV1                 ((uint32_t)CAN_IER_FOVIE1)  /*!< FIFO 1 overrun interrupt         */
复制代码
; f) W8 L; r6 Q! Y6 x, O! b# k
四、接口设计
/ S9 q: [* U$ {. o! f与串口类似,使用中断接收。先封装单路CAN需要的几个小接口,再顶一个列表,最后使用统一的接口扫描这个列表。
1 y, l) D2 E0 H: B3 f1 Z* W$ i  Q6 A+ C: k, I
  1. typedef enum
    1 l& S- {: E$ w4 x2 Y! t
  2. {
    , o+ A! W& s2 C' F4 Z' y/ C
  3.   CAN_CHANNEL_NONE,# c; [, }! ~  v0 E
  4.   CAN_CHANNEL_1,
    ! |6 Y5 k+ v( T3 H) u. H, |
  5.   CAN_CHANNEL_2,& o0 h$ v$ d& M: b
  6.   CAN_CHANNEL_NUM- K& F% \- X8 q) p. y7 j
  7. } can_channel_t;
    - Q" z9 X# O$ K' V

  8. ( t8 r* {, x$ r& R7 ~" U# {) b
  9. #define CAN1_CHANNEL              CAN1
    ; V0 j4 {! _8 {. @7 R$ Y# s
  10. #define CAN1_PREEMPT_PRIO         CAN1_RX_PRIORITY4 a9 f3 N  w+ Y2 I- O8 \. u/ q8 E
  11. #define CAN1_RX_IRQ               CAN1_RX0_IRQn
    9 Z$ y+ B: }! p. \$ O6 L
  12. #define CAN1_RX_IRQ_FUNC          CAN1_RX0_IRQHandler
    ! Q/ W/ S, A0 v- X8 C3 {6 f. B% Q+ }
  13. #define CAN1_CLK_ENABLE()         __HAL_RCC_CAN1_CLK_ENABLE()
    - b' V' l' b. l2 J; u6 L( x) R$ P- F
  14. #define CAN1_TX_PORT              GPIOA/ m! t6 y1 D2 P( h$ V+ p
  15. #define CAN1_TX_PIN               GPIO_PIN_12# R. w# K% D* B3 ]
  16. #define CAN1_TX_AF                GPIO_AF9_CAN1% n0 f8 B7 ^9 H: }: w
  17. #define CAN1_TX_CONFIG()          GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF)4 X! ?8 n, ]; Q
  18. #define CAN1_RX_PORT              GPIOA7 n! U6 u, g* [/ u
  19. #define CAN1_RX_PIN               GPIO_PIN_11
    0 W+ _- e/ w- e, N# Z! G- L" I
  20. #define CAN1_RX_AF                GPIO_AF9_CAN1
    0 u0 u% q' o% q5 h5 ?& C( ~: X+ S
  21. #define CAN1_RX_CONFIG()          GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF)/ h# r1 L1 b& u0 @2 [

  22. * z: }8 D8 N$ f' ~# U
  23. #define CAN2_CHANNEL              CAN2  e+ C8 z& a4 a4 i
  24. #define CAN2_PREEMPT_PRIO         CAN2_RX_PRIORITY
    " v/ ^3 Q( t. k; f3 F. O0 c
  25. #define CAN2_RX_IRQ               CAN2_RX0_IRQn9 p5 L. v5 F6 i0 r$ q- |
  26. #define CAN2_RX_IRQ_FUNC          CAN2_RX0_IRQHandler9 h# u1 E0 R: J9 ]6 C- n
  27. #define CAN2_CLK_ENABLE()         __HAL_RCC_CAN2_CLK_ENABLE()# j& b$ H; H7 l5 h4 v) f
  28. #define CAN2_TX_PORT              GPIOB
    6 u: S6 d; C0 A) V' W
  29. #define CAN2_TX_PIN               GPIO_PIN_6
    4 u5 v  R  g4 q# [7 H; }, \8 {3 U
  30. #define CAN2_TX_AF                GPIO_AF9_CAN2
    0 [: i) m) e$ u& l8 L
  31. #define CAN2_TX_CONFIG()          GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF): l( \9 V# P9 H
  32. #define CAN2_RX_PORT              GPIOB
    ' i7 I* l( j: W. I3 z1 P
  33. #define CAN2_RX_PIN               GPIO_PIN_5
    ' a( N3 ~5 @% r9 G8 F6 M
  34. #define CAN2_RX_AF                GPIO_AF9_CAN2
    " l) a2 R( n8 J! R
  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设备结构体
    " B$ E- p0 j' _8 o! o+ |; @. m5 Z
  2. typedef struct
    9 K1 f: Z; }+ c+ L1 V
  3. {
    ; U, `* M; D4 a3 u+ l0 n
  4.   CAN_HandleTypeDef handle; // CAN操作句柄
    ' U% I, N' X  ^

  5. 9 f! H  j- n# a! Z8 W$ U
  6.   CanTxMsgTypeDef tx;       // CAN发送; t- c) v, S3 u/ I+ {1 p( K. V& p; @
  7. 4 S/ R9 W% y2 P9 f& n* @
  8.   CanRxMsgTypeDef rx;       // CAN接收: j3 T0 C- v" _5 G8 A3 X  C
  9. 4 x, D. n9 {/ y4 K4 s* `0 K
  10.   can_queue_t recv;         // 接收队列
    : e( e  y9 Y+ l4 f

  11. ! M% @( U- `+ g* L# d& q( ]
  12. } can_dev_t;
复制代码
  1. // 将每路CAN封装成几个小函数
    6 O- E1 [5 c6 a
  2. static can_dev_t can1_dev, can2_dev;% V1 @# B; H  d8 W0 V4 m" O

  3. ; o# I$ w7 y( F) U. ~
  4. static void can1_var_init(void)
    1 @, L9 L3 J$ l/ P& G1 i
  5. {
    6 Z6 F# q4 \, P' V, c5 q& i1 e
  6.   can1_dev.recv = can1_queue_recv;
    5 q' V* @4 B! f" _. c# I) u
  7. . D+ x6 G- p3 U3 @8 d- u
  8.   CanQueueInit(&can1_dev.recv);+ ~. y! i0 S8 L( f) P, P
  9. }% x! i$ N2 o' @# E
  10. 3 d% [) ~0 s- D
  11. static void can1_gpio_init(void)8 a7 x/ Q$ w1 r6 E
  12. {
    * E+ g5 v  t) r8 V
  13.   CAN1_TX_CONFIG();* y. P% P1 k8 H7 D5 n- L; _
  14.   CAN1_RX_CONFIG();
    ) B" n( S+ `9 k6 A+ u
  15. }4 U3 f5 Q- j5 T& f' }$ W

  16. 9 N( ^$ X' |5 L# \1 J( g: a6 J
  17. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M* M) w9 E6 F9 o/ I8 x2 \
  18. static void can1_mode_init(void)9 s( E7 J0 I, S# E  R" |5 a
  19. {
    4 F/ {# r8 Z# [" a' c7 `+ x* m
  20.   CAN1_CLK_ENABLE();: {8 D- W1 ^$ @

  21.   I% P9 v: c8 F( \4 B1 @
  22.   can1_dev.handle.Instance = CAN1_CHANNEL;
    : W5 R) b- X/ M7 O: y9 i
  23.   can1_dev.handle.pTxMsg = &can1_dev.tx;& ~' _  Y# L/ z" ^* g: N. b! ~
  24.   can1_dev.handle.pRxMsg = &can1_dev.rx;3 u0 S+ Z: v: [7 w# _" a
  25.   can1_dev.handle.Init.Prescaler = 6;
    & B* H( u3 s0 K& l6 L  b/ F! M
  26.   can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;
    6 G# ]* {. I8 q+ R: q
  27.   can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ3 s+ ]% h: ?" w5 c1 v3 B  G) ?
  28.   can1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ: t9 o$ d3 I. G
  29.   can1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
    * X$ Q# O4 D8 [$ l$ G; ]8 [
  30.   can1_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    4 r+ {4 Y# w+ S$ R
  31.   can1_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理
    1 l+ L$ ]6 h) ]
  32.   can1_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)1 L* B! G& C1 i' T; H. P
  33.   can1_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    5 I; m% @6 I* E9 T
  34.   can1_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的5 J. a" X( c2 `2 D$ }+ w
  35.   can1_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定
    * p/ _0 [# Q5 A- r- Y+ r8 U0 n
  36.   HAL_CAN_Init(&can1_dev.handle);
    * E+ X$ s* v) D: X
  37. }
    8 R9 o8 m$ q7 S1 `; ~0 ]
  38. 7 }9 V- Z, }( g& {% a" D3 f6 Q8 e
  39. static void can1_filter_init(void)8 [! c, y6 V- o' U. n( c# \
  40. {/ Q. x5 a- k' R
  41.   CAN_FilterConfTypeDef  filter;% ]8 C" X$ t; W2 `
  42. 1 D+ i. M8 @' k6 D, m
  43.   filter.FilterNumber     = 0; // 过滤器01 ^7 a. ?) x9 g; d2 s
  44.   filter.FilterMode       = CAN_FILTERMODE_IDMASK;
    5 L5 G1 @- W: D( t/ [8 L
  45.   filter.FilterScale      = CAN_FILTERSCALE_32BIT;
    & K8 x+ f' K# Y7 g
  46. . U* m1 L* l9 a; @% `6 h5 V2 [
  47.   filter.FilterIdHigh     = 0;
    . t; X: k/ o6 Z# E  `2 q8 M
  48.   filter.FilterIdLow      = 0;( e5 ]8 g" x, H+ A) l* `
  49.   filter.FilterMaskIdHigh = 0;
    3 i) ]  S* s* m7 R( R+ c( e
  50.   filter.FilterMaskIdLow  = 0;
    ( {& k1 h7 L4 W. i! D( r8 {

  51. + I/ e: [  N5 U6 l) A' q' [/ F5 n
  52.   filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0
    . h1 [- D6 j* Z$ y2 }4 |7 s) a
  53.   filter.FilterActivation = ENABLE; //激活滤波器00 U- j! @; s# ?
  54.   //filter.BankNumber=14;, f: S4 g" w: b# t

  55. % E+ W! w4 s6 _0 h' H9 r
  56.   HAL_CAN_ConfigFilter(&can1_dev.handle, &filter);
    8 M  E: n) M4 ?$ [6 I4 w& U
  57. }
    7 I! _3 @) E8 ?
  58. % d* Z5 ?& M0 h" q2 O5 ^+ X
  59. static void can1_nvic_init(void). ]- |3 i! M: Z4 D. {
  60. {1 H# {, ~9 J& k5 H
  61.   __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许.( J' K* e- D0 U$ Z9 y
  62.   HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);
    , x" R. o/ ~" Q5 ^, a4 T1 H/ f; t
  63.   HAL_NVIC_EnableIRQ(CAN1_RX_IRQ);4 H# C/ L$ U8 i3 b. z+ f6 x. ?% t; S
  64. }
    ' l6 D) D! K& x. Q, i8 V9 m

  65. 6 @0 ~0 }+ _. ]7 H, d, m$ i. {7 n
  66. 6 W3 i8 }5 R9 w" A
  67. 1 e/ {0 x' E: t' T# J
  68. static void can2_var_init(void)
    0 C1 C! Y0 R* x5 F# q8 l- c& s
  69. {+ j/ ^9 N, k, D5 f5 C/ i. P3 f- O
  70.   can2_dev.recv = can2_queue_recv;
    9 }* [1 ^# M; q, `# h5 F
  71. * |5 N: K+ ?' G7 I
  72.   CanQueueInit(&can2_dev.recv);/ ^% J/ t3 f; t# Q, D, N0 x
  73. }
    6 f" g6 I7 q4 j/ i8 _, k8 H
  74. 6 b: [1 D* x5 ^' R* M9 F" z
  75. static void can2_gpio_init(void)  o* R8 g- @# U; b- j
  76. {
    ( g+ U" c: m' V" o/ u
  77.   CAN2_TX_CONFIG();& V1 S% a  S/ j7 `# X0 I4 e0 U9 _
  78.   CAN2_RX_CONFIG();7 a& y. k" w, c5 l0 o
  79. }
    3 n  ]6 @2 D1 z) a: B

  80. & F, K0 Z& |! a; W4 y9 n* O# \
  81. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M4 B& `7 |" t0 }; u. `! o, d: D
  82. static void can2_mode_init(void)' ]7 ?1 j' Z2 S7 k
  83. {) Q( i5 ^/ _+ k, w8 Z" D
  84.   CAN2_CLK_ENABLE();
    ; _2 N) Y7 X& X' f) X2 `; n+ ]7 \
  85. , i- S6 x/ Q- ^
  86.   can2_dev.handle.Instance = CAN2_CHANNEL;
    3 `' T( {" |( L" M6 s' L' ]
  87.   can2_dev.handle.Init.Prescaler = 6;
    3 E" J7 H8 a; d: E* H( S6 n
  88.   can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;
    6 W/ j/ `1 i  d% T- |2 i
  89.   can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ' R( U$ @( W# T
  90.   can2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ3 Q1 d# Y# S5 O3 d+ O
  91.   can2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
    1 `, G, N) Z6 n% w
  92.   can2_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式; E6 a: k7 T8 v, n
  93.   can2_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理8 @% _" [8 P0 i1 m% A. Y
  94.   can2_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
    3 x" L7 k! I  [6 q: j$ J: A/ X2 S
  95.   can2_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    9 ~, A& R# F( ~$ C: p& c% t
  96.   can2_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
    " ]( m! u1 L$ d8 X
  97.   can2_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定4 F" z+ F4 y- ]: Z' |) e9 h9 R
  98.   HAL_CAN_Init(&can2_dev.handle);$ m& U6 c* s  `0 V
  99. }
    3 f7 U6 q- @% C2 A* h( Z5 g
  100. 8 V2 K* h' Z- N) L
  101. static void can2_filter_init(void): _, `8 D5 b/ ~3 J1 `/ m4 M
  102. {, a% U* m) d( s$ O
  103.   CAN_FilterConfTypeDef  CAN_FilterInitStructure;+ H& F' x( Z. f6 v5 _! |+ A, E
  104. * \/ z6 w0 p0 ]
  105.   CAN_FilterInitStructure.FilterNumber     = 14;8 H8 h* K* u- j2 ^0 ]7 Y
  106.   CAN_FilterInitStructure.FilterMode       = CAN_FILTERMODE_IDMASK;
    6 L6 a) U" D3 q: j# v+ q% q
  107.   CAN_FilterInitStructure.FilterScale      = CAN_FILTERSCALE_32BIT;
    8 x5 q6 o" E7 ]8 g: k9 T

  108. * b3 b4 ^7 C0 j( H
  109.   CAN_FilterInitStructure.FilterIdHigh     = 0;) w  |( J- o0 `& p
  110.   CAN_FilterInitStructure.FilterIdLow      = 0;
    , G% \9 G( H! R/ m5 W$ h& t! M7 z
  111.   CAN_FilterInitStructure.FilterMaskIdHigh = 0;
    # r* m" |6 [- M$ @0 ]  Y' T
  112.   CAN_FilterInitStructure.FilterMaskIdLow  = 0;1 y1 k! |9 ^4 ?7 B9 O; c

  113. 7 p) c% V$ I% |6 v0 i
  114.   CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0+ |5 t7 B& l+ m. O; o
  115.   CAN_FilterInitStructure.FilterActivation = ENABLE; //激活滤波器0
    + _( @/ e, t& z# n
  116.   //CAN_FilterInitStructure.BankNumber=14;; L3 F" y- X7 @

  117. ' t! _5 P% E5 M2 R% U! ?% F% k
  118.   HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure);
    , \% b2 i% X: H3 p
  119. }+ j8 d* n& `' Z% W3 P, I

  120.   ]9 R! w0 L  t
  121. static void can2_nvic_init(void)# M( E- [0 s7 }2 X, e
  122. {
    7 U" d9 A5 C6 F5 m6 |6 }& p9 P
  123.   __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许1
    9 ]: @4 z' p, ^% b1 c9 T$ k$ z
  124.   HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);; N3 y# C9 o: U0 v2 \+ M% W* j
  125.   HAL_NVIC_EnableIRQ(CAN2_RX_IRQ);7 e- U0 s, v8 K' a
  126. }
复制代码
  1. // 每路CAN都有的几个操作,使用列表包含,然后统一扫描处理
    . |% d7 V$ G$ ^; V4 N
  2. typedef struct
    3 p. A0 y# i% r- g6 ]1 x
  3. {7 `9 j( b* u! _1 G8 b. m) o0 R/ ^/ w
  4.   uint8_t channel;
    2 M5 n8 h9 }* S7 U" i" e/ o
  5.   can_dev_t *dev;9 L6 M, O) N- q- n! F
  6.   void (* var_init_cb)(void);( T; c+ R5 V3 l5 t" g6 A* R! E
  7.   void (* gpio_init_cb)(void);
    2 R/ x: e) `4 w" Q6 r, e
  8.   void (* mode_init_cb)(void);
    " F/ f5 O! H% e+ ]
  9.   void (* filter_init_cb)(void);! ]. A  _5 ^3 X' U- D
  10.   void (* nvic_init_cb)(void);. e' E* S0 a$ r5 Z
  11. } can_config_t;; A' n! W( b3 a1 H

  12. 1 g4 p; _4 p! F5 \
  13. static const can_config_t can_configs[] =8 u  d( {- g3 _  L
  14. {
    # [7 o* M% L! V. y) U
  15.   {CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},
    4 U0 O. ^/ q* a6 [% s' d" f
  16.   {CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init},, o( p2 P1 ^4 e
  17. };
    1 y- ^/ M6 }) L& _: W) s1 _

  18. 1 [1 w5 h6 T$ |9 Q3 D  `
  19. static can_dev_t *can_dev_get(uint8_t channel)
    8 U# `! B4 g7 W; t
  20. {2 W; M4 q" L& l6 h& C& H
  21.   uint8_t i;
    ! ?3 X# ]# p1 Z; g+ y8 U

  22. ! v  R' H+ o" c/ b, u4 [
  23.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)* |0 f" ?( H3 G; U+ w  _! q
  24.   {, U0 U5 i3 n8 g; Q' B5 V
  25.     if(channel == can_configs<i>.channel)
    0 f8 O# i* s% |( Q4 J
  26.     {1 h" x, S1 {/ |/ s
  27.       return can_configs<i>.dev;! C5 g  O  ~' _; w, N* h
  28.     }6 N4 m( ]# b0 c7 ]$ W) d& S( @
  29.   }* u- Y5 g! x! ~

  30. . c0 e' p3 R2 H& Q
  31.   return 0;$ M. l2 t& V/ F  y; D5 p  ^
  32. }& Y: y$ V9 h' j2 Y" E

  33. 7 P6 @0 E! N3 U* T' o6 g& g' u9 w
  34. static void can_var_init(uint8_t channel)
    3 g2 s& N5 f! s0 E: `0 B& H# {0 o7 g
  35. {
    ( i) b9 v( k+ D: ?: P) x
  36.   uint8_t i;& Q2 l) [7 W3 O* B8 ^

  37. 6 S" ?) j5 R3 D# W( v0 T
  38.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    $ g; C1 B6 [% b/ [+ b
  39.   {
    & G7 o8 Y6 I) V  v0 p3 r) g/ I
  40.     if(channel == can_configs<i>.channel)
    $ m9 v$ {0 G$ e! T; j
  41.     {) }1 f. p4 I$ S4 i5 K) k7 h+ V* z
  42.       can_configs<i>.var_init_cb();
    8 T6 k( q# B1 w7 a* ~4 N* p
  43.       return;
    ; W- i! X( s3 U" R
  44.     }
    0 E; T  c. c7 G% }% N) ^. _! @
  45.   }
    . x; l1 O, ?, C, K
  46. }
    & V: Q9 |* e$ Q8 a+ y* Y5 @" u
  47. ' h: v& o9 n5 x
  48. static void can_gpio_init(uint8_t channel)0 O7 ^6 n5 H  v- L5 M- d# G
  49. {
    - Q/ ~% `1 w# f: E
  50.   uint8_t i;( O' i3 S9 ?3 E

  51. 1 I  {7 {: S+ _3 x4 Z
  52.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i), p" u5 p2 K5 i( F! P# a
  53.   {+ \- M" B' f) B) A* y; i( `( ]7 x8 `
  54.     if(channel == can_configs<i>.channel)
    # p1 ?$ D: Q, r8 n
  55.     {+ C/ z+ ?" ~6 p* \
  56.       can_configs<i>.gpio_init_cb();
    $ }+ F! Z' D& j
  57.       return;
    ; @! z4 K, G* A  j: u* h
  58.     }6 w2 L" z+ r, v7 ?2 v6 n! \0 i
  59.   }
      o6 _2 t; p8 `7 r8 w2 I5 P# o: C
  60. }
    # k3 A8 y* f3 j, I
  61. / n7 y5 F# \1 C) i8 _( \! u8 D& ?, G, G
  62. static void can_mode_init(uint8_t channel)4 V/ i/ m+ m8 ~7 x
  63. {
    3 x  v. p. ]- E/ H( K0 E
  64.   uint8_t i;
    4 s+ K  ]$ h; x9 |* `3 Z

  65. 6 b4 q+ ]  Y3 \# K; o4 Y
  66.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i): b) z9 V( S5 ~; w7 f6 n
  67.   {
    6 F# J9 J* k  E: J8 ]" |% s# @9 q
  68.     if(channel == can_configs<i>.channel)
    6 O" w  s0 {7 F" ~, r
  69.     {% I7 r, D1 N. _4 L
  70.       can_configs<i>.mode_init_cb();
    ) n# B# U7 N# R2 D# g0 w  G
  71.       return;5 \5 p. a6 Z+ I$ _1 {
  72.     }
    1 E+ ~# ]0 N$ k+ O" I
  73.   }6 w; w( P: C  \4 b* u; v, D
  74. }* V5 S# ]& ^+ N- @* I1 j
  75. ( T  a! ?2 ~! ~: r, _8 ]
  76. static void can_filter_init(uint8_t channel)
    ' u" V; J0 k0 {1 n% N* o# ~/ z
  77. {
    : |9 V  q7 t9 \
  78.   uint8_t i;
    - O7 \; ~$ n7 {- ?1 c
  79. $ k4 o9 U  d  F& ~! `+ s
  80.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)3 N0 V% O8 U8 J2 s
  81.   {
    7 ?$ f0 {/ i% f
  82.     if(channel == can_configs<i>.channel)4 H2 s4 a8 `6 V' n( Y5 A) ^& V* P+ c
  83.     {
    ' @( |2 R1 l3 ~: y8 l' p
  84.       can_configs<i>.filter_init_cb();
    % u% i# a) r. |" N$ E% O. b
  85.       return;
    1 v- w% W5 Q% }9 b2 `
  86.     }
    2 j& D& _$ B3 V, j* P
  87.   }9 q, W9 u( A) W2 E8 O' _
  88. }* u4 Z$ T  T7 o1 |0 U( ]

  89. ( r- C7 X0 b' `- j+ y0 G
  90. static void can_nvic_init(uint8_t channel)' r5 s0 c4 p1 L  t! h; a
  91. {
    6 d0 B( Z6 T8 M2 B3 Q7 x: Q, E
  92.   uint8_t i;
    4 x$ y7 ~5 m  _) e# |* Y

  93. ( q% m+ F3 N( \5 H4 [: i8 z
  94.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    8 T+ ?! z" {, H' o
  95.   {! G  w6 R* K" H1 l; P
  96.     if(channel == can_configs<i>.channel)
    9 z# w: R8 x& L! x8 }3 {/ @* a  |6 k
  97.     {
    0 l% g& _) n, s* a% Z+ [7 f- O& I
  98.       can_configs<i>.nvic_init_cb();, k1 h8 a4 t! }, T/ b
  99.       return;
    * `7 u' W, l. }/ I1 O3 U7 s4 Q
  100.     }
    % H  B# H, Z5 E( b" x3 y
  101.   }
    : f9 s  ^) e- _6 H8 I7 g' o
  102. }</i></i></i></i></i></i></i></i></i></i></i></i>
复制代码
  1. // 对外的接口 初始化 发送和接收
    ) S4 X+ K6 }5 N6 ]
  2. void CanInit(uint8_t channel)
    8 ^& \: n. _+ m. o5 c
  3. {
    9 A0 {: R2 [  @. \* ]* K6 D
  4.   can_var_init(channel);, V  M5 L. v" W
  5.   can_gpio_init(channel);/ h; \) D3 B$ P* u
  6.   can_mode_init(channel);
    " D* T- v" Q9 Z1 k) H1 W& p
  7.   can_filter_init(channel);$ z& U. c8 L  I4 C
  8.   can_nvic_init(channel);3 [6 q2 v; p" _: T. O
  9. }+ l* P5 E6 _0 z1 S

  10. ) }; g8 `* W: [/ k0 [
  11. void CanSend(uint8_t channel, can_frame_t *frame)
    4 u8 c- U' v' _( _$ m% w
  12. {
    8 }* p1 k1 b$ k9 n& ^
  13.   can_dev_t *dev = can_dev_get(channel);! O1 M: V" Q* A- k3 P3 ?6 h

  14. ) [, G: y! T6 z% e! E2 P+ V
  15.   if(dev == 0)
    # z; ]8 M8 J+ F* v" P
  16.   {
    - G! q4 N+ Z; a, X( d/ U
  17.     return;/ p( Z" x2 d5 ^9 V9 \; ]1 M
  18.   }5 G$ @3 [: H& y/ N1 H

  19. 8 \9 o( n" z2 u7 F3 q" L" T
  20.   dev->handle.pTxMsg->StdId = frame->StdId;
    + p! d( l( D% A+ u
  21.   dev->handle.pTxMsg->IDE   = frame->IDE;$ M4 y$ H: s/ W: H) J: e- }
  22.   dev->handle.pTxMsg->RTR   = frame->RTR;+ |8 t5 W' e3 _1 H5 a& b- i! p
  23.   dev->handle.pTxMsg->DLC   = frame->DLC;+ k& E$ i- S/ c/ C. I& m. e
  24.   memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);" o- D7 P& _# F
  25. 7 u2 I% P& E1 g7 k+ O
  26.   HAL_CAN_Transmit(&dev->handle, 10);
    3 L/ i, T. \$ a5 z
  27. }% J7 x" i$ K; D8 l
  28. # j* o  z( H! S6 s% ]9 Y2 a
  29. uint8_t CanRecv(uint8_t channel, can_frame_t *frame)
    ) @! Z$ m# C/ V6 ^) q
  30. {
    9 h( b3 O: e% R9 B# p
  31.   can_dev_t *dev = can_dev_get(channel);
    ) _7 I" \' ?; N
  32. # e/ z4 K" m% A* m# I8 N
  33.   if(dev == 0)
    3 f% B* q; t+ d+ K  S4 X
  34.   {4 y6 {2 S/ E7 n  X
  35.     return 0;
    2 j' ?7 D- ^9 q5 p) t
  36.   }/ ^# p  f# N! Z

  37. ; q0 V1 _  Y% C; Q. u, L' p
  38.   return CanQueueRead(&can1_dev.recv, frame);
    , Q5 F7 l1 ]2 e6 }' z
  39. }
复制代码
  1. // CAN中断
    / ]# l1 _; E$ a
  2. void CAN1_RX_IRQ_FUNC(void)
    # `3 r& s: w# B; c, p9 U
  3. {
    7 t3 }. C5 j- ~! W! ~  f" ?. h
  4.   HAL_CAN_IRQHandler(&can1_dev.handle);! R, Q" V, r! D) |
  5. }
    " x3 Y8 E5 }1 g: D

  6. 8 C2 K) R6 B' O
  7. void CAN2_RX_IRQ_FUNC(void): F! P+ |) v+ O( S9 J
  8. {
    + [6 V. [3 W0 _% _, C9 f" s
  9.   HAL_CAN_IRQHandler(&can2_dev.handle);- ?4 a6 l, \  C( ~  _
  10. }
    % h( A. ~  x# P0 |
  11. 2 F7 R- t! b) A" o: l
  12. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)0 R$ @  X) ?/ k0 f  ~1 D! w: o
  13. {
    ; M# {8 n2 Y" B" y: K3 m
  14.   if(hcan == (&can1_dev.handle))
    & d! |9 x) T) j; J+ Y
  15.   {
    1 ^3 z9 M4 r7 H2 r
  16.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开; }: j, L& |1 e# Y2 ]
  17.     __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断: ?8 s0 }' S& i" x4 e( f
  18.     CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);
    ; Y$ k& o5 K+ T% r
  19.   }; k  ^5 r0 `1 j: w/ Q
  20.   else if(hcan == (&can2_dev.handle))4 I' I" v  ]  p; J* @' G" |/ e
  21.   {
    $ S5 g! F! @5 d# f' b$ A( T
  22.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开: h: T5 \9 f" x5 s( ?' n2 m; a  c
  23.     __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断6 ?5 u7 n# a$ k( i
  24.     CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);  i( F2 U: d# g2 W9 Z0 y: K
  25.   }! j% a4 t' G) h$ D- O/ [. D
  26. }
复制代码

# j6 S% @8 U% T        之所以使用列表的形式,是为了方便增加和删除CAN通道和使对外的接口更统一,不会出现CAN1Init() CAN2Init(),个人习惯问题。
/ M( U4 n* P! r$ B5 D  A8 k8 W
- Y1 r' l8 W8 u8 r# M# X1 g+ x$ c3 w7 _9 C) y; P
/ n9 f0 b. t; P4 e8 b

) h4 K4 T" g  k2 e! _8 f$ B* X
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版