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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
一、CAN基础
7 _8 `/ f/ T$ a0 G5 t8 f2 S差分信号:显性电平对应逻辑0,CAN_H和CAN_L差为2.5V;隐形电平对应逻辑1,CAN_H和CAN_L差为0V。
3 W' n- }) T! I6 a
. l6 z. G/ y' [7 c! h( MCAN总线的开始和结束都有一个120Ω的终端电阻。( h6 V! {& W  ?. h) J8 e7 d8 k

& s7 ~# R- {9 `1 j7 \数据帧:标准帧11位,  扩展帧29位。/ g( W! w* N4 V2 R* D
# l. I* I2 k& a4 z2 y
其他的一些理论知识就不再赘述了,可以参考维基百科对于CAN的描述。, f) r" D4 ^+ r- r

8 T' \. u2 ?6 Q' M, nSTM32F7xx的bxCAN主要特点:支持CAN2.0A和CAN2.0B,波特率高达1Mbps,支持时间触发,具有3个发送邮箱,2个接收邮箱,可变的过滤器组等。  h  m. `4 `3 x+ A

3 Y1 ?# V" \4 X2 J二、几个重要的CAN函数
0 V2 r8 U) F( l* v% N( o: ]5 q
  1. HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化# L# @+ ^$ m9 X& ^( g

  2. / X" z" A8 {+ y
  3. HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN发送  m/ I, e8 r0 t" s
  4. 4 f7 o- \. v4 ~# c/ p6 ?
  5. HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收
复制代码

/ _: T( q- g( l/ a3 i$ i; m# t9 Q三、几个重要的结构
4 E2 w, b' g/ i0 r# k& n% b
  1. // CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化结构 发送接收结构体 其余三个是过程变量7 H4 B) A! `! C& u+ Z$ l/ v
  2. typedef struct( M) q( `) k( g  K% F
  3. {
    ! s7 c/ Y: U" ]# a* d" ~. U
  4.   CAN_TypeDef                 *Instance;  /*!< Register base address          */$ B$ I5 Z/ {' Z# n# h5 w/ \
  5. 4 t* T+ C. h7 I3 [+ V' k. H1 l
  6.   CAN_InitTypeDef             Init;       /*!< CAN required parameters        */
    * r1 Q: F) ^8 X) q% C

  7. $ \4 T  K: w# s6 E! N" m
  8.   CanTxMsgTypeDef*            pTxMsg;     /*!< Pointer to transmit structure  */" M) A6 o- R5 f
  9. ; o5 `; k: [) i& k
  10.   CanRxMsgTypeDef*            pRxMsg;     /*!< Pointer to reception structure */$ ?1 w# E6 }* ~8 I6 |! f( ]
  11. % q0 q; k. V( \9 w/ T; r3 o5 G
  12.   __IO HAL_CAN_StateTypeDef   State;      /*!< CAN communication state        */) p/ a- l) h8 O2 ?! e, H9 d9 U
  13. ! ?6 @4 I  [$ R2 A
  14.   HAL_LockTypeDef             Lock;       /*!< CAN locking object             */1 j7 {% i- u2 d' ~

  15. 5 P. h5 A/ ~& A& S3 [6 Y
  16.   __IO uint32_t               ErrorCode;  /*!< CAN Error code                 */
    9 w7 Z1 D5 ?2 }) {' U
  17. # Q0 K. y  q3 p2 z* G
  18. }CAN_HandleTypeDef;
复制代码
  1. // CAN配置结构体
    9 _# O) |: K/ J- D) x
  2. // 前5个参数来设置 CAN_BTR —— 波特率7 S7 [- l& e  P: `6 O' D, @. G
  3. // 后6个参数用来设置 CAN_MCR —— 通信相关的控制位
    6 R) E$ r5 D% [+ A& a- T
  4. typedef struct% r( G2 u* U$ t0 y; u* \
  5. {9 O$ s3 b( `7 a! O5 U
  6.   uint32_t Prescaler;  /*!< Specifies the length of a time quantum.
    # P8 D, p  A1 h4 t' F; C
  7.                             This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */5 L  Y+ e7 b0 s5 I- [* \! B

  8. : |9 @: U, ?4 _
  9.   uint32_t Mode;       /*!< Specifies the CAN operating mode.
    $ Z$ s! L5 {  r( H0 q; A
  10.                             This parameter can be a value of @ref CAN_operating_mode */
    9 ~5 N  l$ m( C
  11. 2 j5 j9 }8 L& ^" w9 [) Y3 h
  12.   uint32_t SJW;        /*!< Specifies the maximum number of time quanta
    ' `1 Q+ m+ ~% m
  13.                             the CAN hardware is allowed to lengthen or. i" m! W1 w7 R
  14.                             shorten a bit to perform resynchronization.$ a, D# m6 ?+ L. @; s3 R
  15.                             This parameter can be a value of @ref CAN_synchronisation_jump_width */
    ' w  l: C$ x6 U: l+ m# F$ p1 U! ~6 n/ }" l

  16. & V; Z) c/ \7 }: q) p4 g! U- @
  17.   uint32_t BS1;        /*!< Specifies the number of time quanta in Bit Segment 1.
    7 b/ t! s6 Q# H0 W+ X1 p: @
  18.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 */
    2 n! [) {6 Q. J$ O- ~2 A

  19. % b% ]3 F! {$ \5 X6 {3 }
  20.   uint32_t BS2;        /*!< Specifies the number of time quanta in Bit Segment 2.
    # l- {7 E/ @1 u- Y& ~- ?
  21.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */! d3 C! y# D7 @9 |, o1 X2 Q" E+ A3 n
  22. ) d9 `3 j9 A- W% K! D6 j
  23.   uint32_t TTCM;       /*!< Enable or disable the time triggered communication mode.
    0 i& P+ x  A- L& u- i+ z
  24.                             This parameter can be set to ENABLE or DISABLE. */- Q; W' B0 P3 E/ t
  25. 9 [9 Q  v2 C! T# |/ h% w: ]  [
  26.   uint32_t ABOM;       /*!< Enable or disable the automatic bus-off management.! i$ `) B3 R) a5 E' c0 n
  27.                             This parameter can be set to ENABLE or DISABLE */
    & N. a9 l) j7 ]6 i  c" O! r0 K( h
  28. 2 o/ o7 i( R1 H8 ?: A$ d
  29.   uint32_t AWUM;       /*!< Enable or disable the automatic wake-up mode., ?# y2 u# Y- e% j9 P7 r5 ]
  30.                             This parameter can be set to ENABLE or DISABLE */
    % O* B; B$ Q* _& B9 B: B7 \4 Q
  31. ( ~! ]! {1 t  ]
  32.   uint32_t NART;       /*!< Enable or disable the non-automatic retransmission mode.
    0 e8 }( F; D$ }. O4 f5 C, J
  33.                             This parameter can be set to ENABLE or DISABLE */
    5 \8 ]) \" }0 i5 Y$ J

  34. 4 V# o: \5 {3 f$ d. x5 }
  35.   uint32_t RFLM;       /*!< Enable or disable the receive FIFO Locked mode.7 d8 j! n" l. b, b0 A% m' I" S- c- G
  36.                             This parameter can be set to ENABLE or DISABLE */! }% D& g% X; n

  37. , ?/ t2 C# T3 R9 u% {
  38.   uint32_t TXFP;       /*!< Enable or disable the transmit FIFO priority.
    - B2 ~  l  W6 X6 g% X# K
  39.                             This parameter can be set to ENABLE or DISABLE */
    6 I# D9 @7 \/ ~
  40. }CAN_InitTypeDef;
复制代码
  1. // 过滤器设置
    & Y+ `4 T/ W: T1 W6 z/ z6 q
  2. typedef struct1 @; }5 Z3 {* S) c% T! Q( b
  3. {" ?' J  }; A9 j! ]
  4.   uint32_t FilterIdHigh;          /*!< Specifies the filter identification number (MSBs for a 32-bit( s6 Q: ~) _- T8 g+ D& G
  5.                                        configuration, first one for a 16-bit configuration).
    4 U$ i: ~0 W5 N4 g2 ?! E
  6.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */2 N  a( R5 C8 Z6 f1 g% `3 B9 z

  7.   W9 p! g" O) t1 K8 L% |
  8.   uint32_t FilterIdLow;           /*!< Specifies the filter identification number (LSBs for a 32-bit
    / a# U& y& S# E" h2 }
  9.                                        configuration, second one for a 16-bit configuration).
    * ?' h9 T7 n. A- ?9 J+ E* ^
  10.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    1 r5 |) u/ g1 Z2 O! X0 f
  11. * g6 Y, I( c$ p# C7 W
  12.   uint32_t FilterMaskIdHigh;      /*!< Specifies the filter mask number or identification number,2 B9 \- l$ e' _( K( K# U
  13.                                        according to the mode (MSBs for a 32-bit configuration," x, [2 M( @# y
  14.                                        first one for a 16-bit configuration).
    * s7 l$ I1 n$ A' R/ n; O6 J5 w
  15.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    , P0 c# ~% C  G0 c2 V9 x
  16. ( p+ W* `/ N6 ]! V
  17.   uint32_t FilterMaskIdLow;       /*!< Specifies the filter mask number or identification number,
    6 Q4 G  S2 X" y3 r- |
  18.                                        according to the mode (LSBs for a 32-bit configuration,
    $ n& Y- f( o: B/ I
  19.                                        second one for a 16-bit configuration).0 x. t4 z( K9 s1 L) q6 ]
  20.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */. N  i/ B+ O# z  _1 i0 d
  21. ; [: J$ l1 ~- C+ y. P" j
  22.   uint32_t FilterFIFOAssignment;  /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.6 x% ?- n+ [  k- |2 j) M6 U
  23.                                        This parameter can be a value of @ref CAN_filter_FIFO */% G0 l/ o6 U/ T/ l6 [8 }

  24. ! ^. R) o) A, u" V$ f: Z
  25.   uint32_t FilterNumber;          /*!< Specifies the filter which will be initialized.
    ! t+ l; c# T! @
  26.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 27 */: ]) g3 G" l4 x# W& q) x" s$ O+ y1 k3 @

  27. 0 Y5 X$ K% L# i, Q2 L% e
  28.   uint32_t FilterMode;            /*!< Specifies the filter mode to be initialized.
    5 b: @0 H# a* S9 U
  29.                                        This parameter can be a value of @ref CAN_filter_mode */' a9 d9 s- d9 r2 T  x- e
  30. ' V9 D6 a  N$ H1 f* c4 t2 F% ^
  31.   uint32_t FilterScale;           /*!< Specifies the filter scale.
    & k9 Q8 K" a  H* j4 R3 G: C
  32.                                        This parameter can be a value of @ref CAN_filter_scale */
    / R5 j! q5 Y- R9 b2 O

  33. & R" U0 E! k# Z6 V* m. [, s! H0 p
  34.   uint32_t FilterActivation;      /*!< Enable or disable the filter.
    2 m$ N% i" C+ D! X6 Z* S9 U
  35.                                        This parameter can be set to ENABLE or DISABLE. */
    ( P5 C9 a$ K( C! s

  36. 2 e6 M- \3 J, f
  37.   uint32_t BankNumber;            /*!< Select the start slave bank filter.
    5 V8 T. \1 _4 j+ K5 R, N
  38.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 28 */
    9 y( s  p: p- y6 q
  39. / j' y  T/ t7 O+ ]8 v9 S
  40. }CAN_FilterConfTypeDef;
复制代码
  1. // 模式  我们使用普通模式
    ' B; R/ X4 q% r1 d
  2. #define CAN_MODE_NORMAL             ((uint32_t)0x00000000U)                     /*!< Normal mode   */7 D/ ^: ?. H$ E: s2 j
  3. #define CAN_MODE_LOOPBACK           ((uint32_t)CAN_BTR_LBKM)                   /*!< Loopback mode */$ o5 Q: J/ S. ^
  4. #define CAN_MODE_SILENT             ((uint32_t)CAN_BTR_SILM)                   /*!< Silent mode   */* d: e5 B% j) Z) y$ W% C" Y
  5. #define CAN_MODE_SILENT_LOOPBACK    ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM))  /*!< Loopback combined with silent mode */
复制代码
  1. // 标准帧 扩展帧* q: ?5 C% x+ |1 J' ^# c, U* v- j2 B
  2. #define CAN_ID_STD             ((uint32_t)0x00000000U)  /*!< Standard Id */0 L" x, z6 {4 _& a
  3. #define CAN_ID_EXT             ((uint32_t)0x00000004U)  /*!< Extended Id */
复制代码
  1. // 数据帧 远程帧  m% b* u9 L9 m0 X
  2. #define CAN_RTR_DATA                ((uint32_t)0x00000000U)  /*!< Data frame */
    % q' v4 i( |& y( _8 n/ D4 U
  3. #define CAN_RTR_REMOTE              ((uint32_t)0x00000002U)  /*!< Remote frame */
复制代码
  1. // CAN中断使能: ~4 E# {; N( s) V
  2. __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__)
复制代码
  1. // 接收中断
    ) u5 a4 i  l5 F' B. M8 z+ }6 l+ A- w8 b: u
  2. #define CAN_IT_FMP0                 ((uint32_t)CAN_IER_FMPIE0)  /*!< FIFO 0 message pending interrupt */; J1 N! U0 T3 ~. _' x# x- b
  3. #define CAN_IT_FF0                  ((uint32_t)CAN_IER_FFIE0)   /*!< FIFO 0 full interrupt            */
    * ^' V6 m1 f3 C6 K' N- _
  4. #define CAN_IT_FOV0                 ((uint32_t)CAN_IER_FOVIE0)  /*!< FIFO 0 overrun interrupt         */
      f0 t9 @4 {6 I5 ]8 W
  5. #define CAN_IT_FMP1                 ((uint32_t)CAN_IER_FMPIE1)  /*!< FIFO 1 message pending interrupt */' F( n( E, H& O! ?, h2 e
  6. #define CAN_IT_FF1                  ((uint32_t)CAN_IER_FFIE1)   /*!< FIFO 1 full interrupt            */" v1 D( L9 d) Y/ a* |
  7. #define CAN_IT_FOV1                 ((uint32_t)CAN_IER_FOVIE1)  /*!< FIFO 1 overrun interrupt         */
复制代码

. |, |" F/ p( c9 k$ h+ ^6 \. ~四、接口设计3 n& w& \- L3 b( f% Y
与串口类似,使用中断接收。先封装单路CAN需要的几个小接口,再顶一个列表,最后使用统一的接口扫描这个列表。  |2 E: Y4 Z- @6 d4 ]1 e

( h. k/ k% Y* b  w. L. G: g
  1. typedef enum  Y& ~& W) E0 i' A8 W
  2. {& {% H3 [# J/ m" h6 t
  3.   CAN_CHANNEL_NONE,$ D* Q7 w% R. s8 l" l5 [& t
  4.   CAN_CHANNEL_1,
    * o2 r9 X! V/ y; n
  5.   CAN_CHANNEL_2,
    3 ?+ I' h$ L7 Z! ]2 b
  6.   CAN_CHANNEL_NUM& P2 c- f8 [( K8 Z
  7. } can_channel_t;
    " l' |# v1 q% t% T+ W
  8. ) n9 h2 w1 w# n, U) \" U
  9. #define CAN1_CHANNEL              CAN1
    1 E! _% _! P: x" V! D; \
  10. #define CAN1_PREEMPT_PRIO         CAN1_RX_PRIORITY
    1 A) V3 X4 @' c4 k
  11. #define CAN1_RX_IRQ               CAN1_RX0_IRQn" \2 ]2 m3 j1 J; I1 G" L6 x
  12. #define CAN1_RX_IRQ_FUNC          CAN1_RX0_IRQHandler# E2 T, E1 b- j0 F7 i. y$ q# R4 _$ r
  13. #define CAN1_CLK_ENABLE()         __HAL_RCC_CAN1_CLK_ENABLE(), Y1 R) y' E4 R* g  b
  14. #define CAN1_TX_PORT              GPIOA6 ]3 P. C  ~  i. i/ ~' m
  15. #define CAN1_TX_PIN               GPIO_PIN_12+ `+ r3 y) p- m& T  X0 |/ M* f5 z
  16. #define CAN1_TX_AF                GPIO_AF9_CAN1) p  O. Y% W0 q9 C) ]- d
  17. #define CAN1_TX_CONFIG()          GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF)
    ( a0 z% ?6 K: _+ M8 h" x+ X
  18. #define CAN1_RX_PORT              GPIOA# q9 o: ~/ f- B4 j2 {: D% a0 Q. f$ q
  19. #define CAN1_RX_PIN               GPIO_PIN_11
    4 q0 [  ], x1 c
  20. #define CAN1_RX_AF                GPIO_AF9_CAN1
    , l# B8 k$ X: k, S# V$ I
  21. #define CAN1_RX_CONFIG()          GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF)
    6 i8 Q. ^. h7 P, h/ i
  22. - Z5 H- a8 [, J9 _# B5 ~5 L
  23. #define CAN2_CHANNEL              CAN2
    + }8 ?0 m7 S! e& Q+ d
  24. #define CAN2_PREEMPT_PRIO         CAN2_RX_PRIORITY
    7 v. b4 t) b& t" o$ z$ s
  25. #define CAN2_RX_IRQ               CAN2_RX0_IRQn6 J/ q" P; }, P" K, e6 [' e
  26. #define CAN2_RX_IRQ_FUNC          CAN2_RX0_IRQHandler
    5 ^% j2 r8 ]/ S, l1 \8 R9 Z5 H" e
  27. #define CAN2_CLK_ENABLE()         __HAL_RCC_CAN2_CLK_ENABLE()
    , u* H" {) @  t( n
  28. #define CAN2_TX_PORT              GPIOB
    " o' u& p0 a1 B: M- z4 W8 o
  29. #define CAN2_TX_PIN               GPIO_PIN_64 z" y. L9 m3 w7 f$ i9 `; H
  30. #define CAN2_TX_AF                GPIO_AF9_CAN21 m$ |9 D. d) D
  31. #define CAN2_TX_CONFIG()          GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF)" X$ i, b- B. z" V9 j+ C2 p( C1 O
  32. #define CAN2_RX_PORT              GPIOB
    " _. B+ ^$ _# t9 q0 P" \
  33. #define CAN2_RX_PIN               GPIO_PIN_5
    4 `  W& A' j% Q6 a
  34. #define CAN2_RX_AF                GPIO_AF9_CAN2% c( D  V9 E, u& U5 W
  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 M! y. p0 H. l/ C
  2. typedef struct
    4 r$ r, E* X/ ]. y8 P4 @/ p
  3. {6 L3 q: d4 p, B6 ~% @
  4.   CAN_HandleTypeDef handle; // CAN操作句柄5 @5 W  p% g" D

  5. + Q2 `% n3 M% w7 k2 N% l  @
  6.   CanTxMsgTypeDef tx;       // CAN发送$ M, D3 ^$ T- d$ b
  7. . ]+ H' }+ i! c$ ], o
  8.   CanRxMsgTypeDef rx;       // CAN接收' N- {0 ]5 L5 ~1 W$ K, \5 s8 ~
  9. % Z! g5 @& i5 L
  10.   can_queue_t recv;         // 接收队列
    ! t+ C: F: @7 r) p; f. y
  11. - n0 j; c1 V. M
  12. } can_dev_t;
复制代码
  1. // 将每路CAN封装成几个小函数' T8 g1 [- v2 O
  2. static can_dev_t can1_dev, can2_dev;0 ]. u/ ?! _+ {( e& I
  3. 6 q2 f  `$ F7 k2 p
  4. static void can1_var_init(void)/ |9 @5 c: s9 H& m+ J6 H
  5. {3 q* {. }. z1 A- v$ D8 a% I
  6.   can1_dev.recv = can1_queue_recv;/ T7 D0 }% c9 E8 o: v+ r# j6 l2 B" k$ [
  7. . T2 P& e' s9 V
  8.   CanQueueInit(&can1_dev.recv);
    % T1 c5 m9 D( R
  9. }
    9 U* x1 n/ r/ f% v' I. u
  10. 5 j! R. ~6 O2 W1 Z+ Q& ^8 z; }
  11. static void can1_gpio_init(void)
      B6 h/ y/ b9 h$ t8 f; w( \
  12. {3 N% A9 t: v, B9 C! i- C
  13.   CAN1_TX_CONFIG();
    ( V3 x: d: l+ P1 P
  14.   CAN1_RX_CONFIG();
    ! B, O- X' z2 S; R
  15. }* D7 u# J0 p$ C4 j
  16. ' d6 H3 r: [/ u6 t2 c3 l
  17. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M
    2 Z6 `! U' Y& o
  18. static void can1_mode_init(void)) U9 |, m. f4 l  s- k
  19. {5 Z6 w+ I5 s( L1 K$ r
  20.   CAN1_CLK_ENABLE();; r. F6 o& v, J
  21. 5 u0 {& }/ |$ s& _  K
  22.   can1_dev.handle.Instance = CAN1_CHANNEL;$ T* X( n8 c; |( u9 R
  23.   can1_dev.handle.pTxMsg = &can1_dev.tx;
    2 y% Q8 F# \$ g3 B. z
  24.   can1_dev.handle.pRxMsg = &can1_dev.rx;
    , A$ ?) j+ F3 |6 A- Y
  25.   can1_dev.handle.Init.Prescaler = 6;
    7 v# y" b6 B  s5 v3 _5 O
  26.   can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;
    ! R) Z( i5 a; ?6 i- r5 ^
  27.   can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    4 W( p4 `! x( ?
  28.   can1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    7 k9 u5 y+ F4 R% V. r
  29.   can1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ2 N- `( t2 k  f) K+ k, @* e  L, o
  30.   can1_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    : @, M' ~: @% T  ?4 D
  31.   can1_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理* s6 b& |+ S* Q4 e" |7 F
  32.   can1_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)" n/ S1 o1 j: A+ p- w: ]7 {
  33.   can1_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    2 y* G! H3 X+ s6 S) n
  34.   can1_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
    0 g- [$ p/ c3 s8 [2 p  f, B3 B
  35.   can1_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定
    + [& d" d, a( b; Z
  36.   HAL_CAN_Init(&can1_dev.handle);
    : M5 n' P- `4 q, k
  37. }
    # o2 |+ A, R8 t# T1 E6 h

  38. ' \. [4 Z" F: O' d9 [
  39. static void can1_filter_init(void)( C; _. t9 E2 X& w( U: O* D  B
  40. {8 w- P: ?+ Y* q, M! S0 n" {  y$ t
  41.   CAN_FilterConfTypeDef  filter;
      u) f& N1 n+ |" m- N9 n8 j

  42. 4 [! ~) _# r7 g9 M% t
  43.   filter.FilterNumber     = 0; // 过滤器0
    $ |' b5 G2 q/ O; g8 w" z
  44.   filter.FilterMode       = CAN_FILTERMODE_IDMASK;
    % h3 \& Z2 v% j3 T+ N1 `. h
  45.   filter.FilterScale      = CAN_FILTERSCALE_32BIT;# }" v* U! C* q$ ?1 X5 [  {" t
  46. + m1 E6 A7 S( o5 ?' m& X! Q/ J1 {1 ]
  47.   filter.FilterIdHigh     = 0;
    0 x; b4 y+ e; N# h& v5 l
  48.   filter.FilterIdLow      = 0;/ G6 u! y! ]; l8 c7 Y
  49.   filter.FilterMaskIdHigh = 0;
    ( g  J6 F! V6 W* U
  50.   filter.FilterMaskIdLow  = 0;: {: t$ U! Y  ^) @, u/ ~

  51. - _5 X. B. d5 p6 y+ f6 y3 K
  52.   filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0
    3 n, n9 ?2 ~9 N+ C8 p  Z
  53.   filter.FilterActivation = ENABLE; //激活滤波器0
    4 b8 e& j& E" |: c
  54.   //filter.BankNumber=14;# ?$ P0 `. L$ I# k/ a

  55. ; L8 L& x% B2 k! q) e
  56.   HAL_CAN_ConfigFilter(&can1_dev.handle, &filter);# u" l: F" y* }5 o) ^
  57. }
    3 S  M- @/ D$ J4 {3 @8 U
  58. ; `+ w# c  w% J; ?+ F8 V1 L
  59. static void can1_nvic_init(void)( P  J9 ~* p3 a
  60. {! Q7 b6 M; g. t* p" P" ^: o: k
  61.   __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许.
    : p3 I: s% {. J1 I4 q! |6 `7 x
  62.   HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);  s+ V" M8 \0 [  ~9 K+ R
  63.   HAL_NVIC_EnableIRQ(CAN1_RX_IRQ);
    8 L' |4 y! s  s9 R
  64. }  X* c5 o$ O9 _, |9 J

  65. 5 d+ Y' D) n: f* o/ v6 w+ T
  66. 4 Z! m! |- X3 p/ D3 O

  67. & R1 y; F9 U% ?; Z+ T4 W0 B
  68. static void can2_var_init(void)
    % P  g! K* ]* a7 Q+ j
  69. {, u1 k9 Y. H: ]3 x: _0 O( e
  70.   can2_dev.recv = can2_queue_recv;8 s! E' `  }3 e: d& Q6 h
  71. ; c; Z7 m$ [# r5 s, P
  72.   CanQueueInit(&can2_dev.recv);
    : I$ _3 t! h; [4 h, |. ^
  73. }
    2 S( U$ h/ P$ S+ V3 b

  74. : w- ~; j+ m" m) W4 F4 n
  75. static void can2_gpio_init(void)* e  @) h- c5 z8 L7 X
  76. {
    # J6 y  A5 K! q$ G* C
  77.   CAN2_TX_CONFIG();0 u5 H+ Y  I$ W& I  H
  78.   CAN2_RX_CONFIG();" n9 i+ ^/ g5 i8 A  y7 V3 O
  79. }# J0 H7 b* P7 y2 j
  80. 6 t) E9 k6 {' l9 d) l" R( V# N& }
  81. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M
    - v; q7 J5 z5 {( u6 F- d6 Z$ f
  82. static void can2_mode_init(void)
    2 s. Z% q  n8 H, p. a8 F0 h! ]* q# t
  83. {6 N- A7 B& c8 ~* M$ U( x' \
  84.   CAN2_CLK_ENABLE();7 l- [* z# i) Z6 i  {! G  U  q3 X

  85. ! z9 q( l3 m5 h; a
  86.   can2_dev.handle.Instance = CAN2_CHANNEL;
    % Y2 F# k) C% f$ N( x* I
  87.   can2_dev.handle.Init.Prescaler = 6;; j7 n9 t$ P. {# g3 Q' w1 o0 m
  88.   can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;
    / T% \) y" I& O( R: C
  89.   can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    ' n4 |, K# I. A8 x, |
  90.   can2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    % [6 @. E9 F# n# M! B
  91.   can2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
    + a% S  G2 e) `0 |1 r+ @
  92.   can2_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    * P# L7 P* A. S3 p7 }
  93.   can2_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理# E* K3 x& `/ U# V
  94.   can2_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)( q# e4 P' @7 a7 H3 t* h8 ]
  95.   can2_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    3 \  S% |6 O1 x8 K$ ]
  96.   can2_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
    ) ?5 R+ j' R# h4 ]$ O
  97.   can2_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定
    , ~% K! k) g1 U1 h6 ^8 x
  98.   HAL_CAN_Init(&can2_dev.handle);
    7 V$ G4 b2 J7 Y, m3 L# Q9 `. X0 q
  99. }' A& ~0 v: z- }$ P% J# u

  100. * }! p9 d9 e+ h9 m- d" h# c$ H3 |
  101. static void can2_filter_init(void)
      o; r" _! K# S% F, P1 F& }
  102. {
    % e2 x7 m' V4 ], C1 ^0 H3 \5 \
  103.   CAN_FilterConfTypeDef  CAN_FilterInitStructure;6 H8 T+ d8 }' R8 b& k7 ~% [; |$ B
  104.   w4 t- S+ o0 S8 \  E
  105.   CAN_FilterInitStructure.FilterNumber     = 14;
    7 v4 ^. D& m3 u* k* M' \0 r0 E8 B
  106.   CAN_FilterInitStructure.FilterMode       = CAN_FILTERMODE_IDMASK;
    * U5 A0 W- ]- m" p1 Q/ N
  107.   CAN_FilterInitStructure.FilterScale      = CAN_FILTERSCALE_32BIT;% Y* ^: f4 ]; Y: _6 m" z4 r: z0 z

  108. 9 O) D- p+ ~& v6 u  q( J# @/ h, J
  109.   CAN_FilterInitStructure.FilterIdHigh     = 0;
    " E, V' R! ?4 a+ G, b2 W7 _2 L
  110.   CAN_FilterInitStructure.FilterIdLow      = 0;
    4 F; G- v. y  n) f- S
  111.   CAN_FilterInitStructure.FilterMaskIdHigh = 0;
    0 |5 S5 s5 T4 Z' t  |( n7 d: D+ A/ A
  112.   CAN_FilterInitStructure.FilterMaskIdLow  = 0;
    + }9 k' G( A0 W
  113. / T: o: `# ~* D* ]4 M) ~
  114.   CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0
    ; H6 ]6 N6 o* K# `
  115.   CAN_FilterInitStructure.FilterActivation = ENABLE; //激活滤波器0
    $ y/ m# b: [/ ?; o$ f9 w9 g% o9 p
  116.   //CAN_FilterInitStructure.BankNumber=14;
    / C+ U6 l# G1 T. g! a" e7 }9 l

  117. # C7 f, A3 c/ o5 B! \; s9 M7 X: `
  118.   HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure);
    1 e% O2 X4 X& ^" _3 `/ u
  119. }
    ; W2 a- A" ?  C
  120. ! P# n6 }9 E" P0 Z* p  p! L
  121. static void can2_nvic_init(void)7 z2 b8 }4 y1 p" v/ A
  122. {$ V' ?2 Q+ e3 ]( K, e
  123.   __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许1' B8 m  [2 S2 B1 ?# o
  124.   HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);& E& J' P% c7 l3 i& }/ J) ~# W
  125.   HAL_NVIC_EnableIRQ(CAN2_RX_IRQ);
    ) a3 y6 d( g5 ]* h% C! n
  126. }
复制代码
  1. // 每路CAN都有的几个操作,使用列表包含,然后统一扫描处理
    8 I! X2 m" T' C
  2. typedef struct& |( C4 w# `/ q9 G$ l+ D, E: z
  3. {
    ) o' }/ n9 W9 g( I: w9 H1 ?
  4.   uint8_t channel;
    ' t# @7 ^2 j  a& B  Y# W. U
  5.   can_dev_t *dev;% b7 D9 L! o0 H7 }% F3 A4 H
  6.   void (* var_init_cb)(void);- c8 o8 G# ^+ Y% ^2 h- U$ f
  7.   void (* gpio_init_cb)(void);9 i" C9 G3 H7 K
  8.   void (* mode_init_cb)(void);
    : p4 U1 z! Z& U% \- `) S( i! l
  9.   void (* filter_init_cb)(void);, ~: o) u  ]; H9 P8 f
  10.   void (* nvic_init_cb)(void);' y2 C+ U) H) |9 M2 [' q# |
  11. } can_config_t;
    # ~: U2 D* J* c

  12. 4 }1 g- C3 v, X# b, j5 c3 }
  13. static const can_config_t can_configs[] =
    8 W: K2 ?7 n" l8 ~! i, l" n
  14. {
    0 x% f2 C4 T5 y' f) w# k
  15.   {CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},. M; p/ r! D* j
  16.   {CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init},
    ' @* r  t* M; N6 j
  17. };
    + k* S0 n1 w6 Z. v9 z& [9 R
  18. ; M" V, H: u: d# p, x
  19. static can_dev_t *can_dev_get(uint8_t channel)) Y+ v' k( Q; p2 }
  20. {& _% F1 x0 r4 |+ s
  21.   uint8_t i;$ A! \' a" E# O  E2 o8 _: c

  22. + `2 N$ c& i. G
  23.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)  J+ e/ P8 k4 q. v4 {4 A: t* ~* D
  24.   {
    ; Q, J9 [- F- b# q0 [) n" r, Y
  25.     if(channel == can_configs<i>.channel)
    6 o# s" @9 W6 J1 F
  26.     {: g8 ?( s8 D, V: a( \) x
  27.       return can_configs<i>.dev;3 s5 |3 C: x; h8 p
  28.     }
    , S- y& w' u; o4 e# I
  29.   }
    5 v% {2 I3 o6 ]2 Z
  30. 5 g3 @- j: R6 o* d7 e! |/ d! y
  31.   return 0;/ Y1 h& q# f) j0 v, s4 T0 S
  32. }  q6 ^9 u' A% a3 T

  33. * ^/ u! Y; y0 U" Z6 B+ U2 ?' q
  34. static void can_var_init(uint8_t channel)5 z0 e  u& y" c. P) t
  35. {
    7 _# H" q' Z7 m; j" Q
  36.   uint8_t i;
      K* P" n, Z% S! u$ K% d  m" S4 \

  37. 5 G' N3 v1 h, \* `) h9 q
  38.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)% |' T6 u  b; ~* v
  39.   {' C  a) y6 r5 F. J$ W5 @/ ~. L
  40.     if(channel == can_configs<i>.channel)$ n' \) R9 _8 U: K+ O8 N
  41.     {
    ) C3 ?& }" P5 k
  42.       can_configs<i>.var_init_cb();
    8 W0 G' D$ d. f* ?6 v
  43.       return;  q3 C5 H! \: k# r0 s- k+ h, H2 c1 _
  44.     }
    " p) D" d2 s0 _  }3 Q2 p
  45.   }
    ; z% D3 o# A% Q) }+ |* [  g, a
  46. }6 N! p" {! O! |4 ?+ D! t
  47. 0 L# k. n, |% t9 u
  48. static void can_gpio_init(uint8_t channel)1 M: l' E6 Z% b4 k+ f4 w8 }/ E
  49. {$ S" x4 z7 F, b7 e& Q" l3 d2 t4 w5 T
  50.   uint8_t i;
      F" H& A, d5 s2 C2 {* i# r
  51. 1 O' x* I% v4 T6 r
  52.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    , K& L/ @; y0 O) K! y1 ~0 ^
  53.   {' z. p# u0 Q0 i( g, L  D! l) n
  54.     if(channel == can_configs<i>.channel)
    2 w$ V5 t/ b" m2 R
  55.     {
    , t' [6 ^/ y1 o- C( ^$ \" y
  56.       can_configs<i>.gpio_init_cb();
    2 z3 A# r& ^0 r' i7 s" x
  57.       return;
    " ^" \3 [2 s% j6 E
  58.     }6 y& w4 W; e1 i7 @4 X
  59.   }
    . p8 B- j+ C, T5 T& L( p
  60. }$ e, V% k5 U* M0 q# K

  61. & b( T* O! I9 V
  62. static void can_mode_init(uint8_t channel)
    $ e2 C/ Z& y5 S0 P$ N
  63. {
    : N8 t9 M) M+ r. K& @& E+ ?$ V) q
  64.   uint8_t i;! T! {8 J# S3 N/ ^, B
  65.   b0 L( v& Z' A) h
  66.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    6 [+ H" e; b  g* L  U
  67.   {% M8 ?4 B, q4 M. {) O" l. k8 d. t( U
  68.     if(channel == can_configs<i>.channel)
    % M9 x- g0 V+ _; ~/ e  @: a
  69.     {0 u9 ~6 l+ c) r  u- r
  70.       can_configs<i>.mode_init_cb();
    0 |' Q; {: I3 w2 h4 I: K
  71.       return;( G  K' U; Q6 W& |. n2 H
  72.     }
    8 q5 k# o8 B, u, X
  73.   }, Z- S4 ~: ?' x/ c, Q$ p0 m% S
  74. }$ p6 q/ \! u' z$ Q7 w! F
  75. % s5 p# L+ t% s) C' _: T
  76. static void can_filter_init(uint8_t channel)( f  a$ e* y3 a5 s; s
  77. {7 D. _  s1 j  g3 N/ z& ?9 i" w
  78.   uint8_t i;0 e; W# `, h( B( z) ?/ D' d5 I  a. T

  79. * J/ H; j. q0 N9 n' Z0 f
  80.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)( b3 k5 T; q; U4 o
  81.   {0 j* f, L: g, e' }
  82.     if(channel == can_configs<i>.channel)
    + M; M1 y: p- e; o
  83.     {
      t* {4 A0 C  n: {  f) |/ D" J
  84.       can_configs<i>.filter_init_cb();. @, a, C% L7 d* |
  85.       return;- X. R& m% I# \3 l& x
  86.     }
    & y/ U$ I( J2 q$ X7 N2 H/ |8 v
  87.   }' E/ Y& Q( I; j* n
  88. }' ~3 @) P2 _5 O0 a- j4 E9 y
  89. ! }" ~# S' ~  S' g" e3 b* y, r
  90. static void can_nvic_init(uint8_t channel)  U$ M: m7 B4 \5 ~
  91. {+ f& z! P5 {5 d; C
  92.   uint8_t i;
    " _: c" W9 o2 N3 ^1 F& P) o  J

  93. 1 q3 q" X6 X9 Y8 m! O% V0 b
  94.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    : ~$ D$ K, G1 ]! R2 r
  95.   {" r8 d$ U# m+ E' k
  96.     if(channel == can_configs<i>.channel)
    ( S2 Q7 e; c9 h: u  _2 P$ b
  97.     {% X, |$ K8 t& ]
  98.       can_configs<i>.nvic_init_cb();5 h- @( [; q- ~7 b& z0 `( T% W
  99.       return;
    7 j( G& k% k. P3 j9 j+ W
  100.     }' ^! A( P- D3 K0 y) {2 z
  101.   }
    9 ]# E" b' L3 X  l$ l3 }  X2 C: P
  102. }</i></i></i></i></i></i></i></i></i></i></i></i>
复制代码
  1. // 对外的接口 初始化 发送和接收& H8 Y5 ?" \6 S* h
  2. void CanInit(uint8_t channel)
    6 P, a% O+ m+ @8 N, ?
  3. {" D8 B' o7 r3 j) G3 Q/ I. K
  4.   can_var_init(channel);
    6 U+ e. S4 l6 a
  5.   can_gpio_init(channel);7 q, X1 B5 m1 }$ r7 ?3 W. E$ s
  6.   can_mode_init(channel);
    : E4 o" k2 h; W7 g1 c
  7.   can_filter_init(channel);+ B" i( ]* l+ H5 Z: I
  8.   can_nvic_init(channel);, R; l# R( d; _: f
  9. }" x2 T. T& f! u3 _2 P% B# ~6 i
  10. - P; x. R, k/ I+ A/ O
  11. void CanSend(uint8_t channel, can_frame_t *frame)
    " C/ K' a7 p4 X+ u! Z, f
  12. {
    2 u% d0 X$ |- `- T, v! G# v' N
  13.   can_dev_t *dev = can_dev_get(channel);7 o5 Z+ A1 T4 c
  14. 2 t1 F0 [6 ]8 C8 z+ E
  15.   if(dev == 0): i: E+ n  g5 T2 B  |
  16.   {, t' D' }5 j5 P
  17.     return;& L  N/ o8 j2 m; ~% Q; q
  18.   }0 I9 h, L# c8 k, s# t8 J; W( u
  19. * o; i* x  |$ y
  20.   dev->handle.pTxMsg->StdId = frame->StdId;1 n% \" ?4 K! D2 a; d
  21.   dev->handle.pTxMsg->IDE   = frame->IDE;
    8 b8 Q* S; `3 ~2 v! n% _
  22.   dev->handle.pTxMsg->RTR   = frame->RTR;6 M0 w( |5 [) Z7 U1 M
  23.   dev->handle.pTxMsg->DLC   = frame->DLC;
      P1 f, Z3 o: {
  24.   memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);
    4 i6 B$ i8 C( ^6 f. l: P: p% k. p
  25. & y% T* f5 r3 _6 h: H5 A8 Y
  26.   HAL_CAN_Transmit(&dev->handle, 10);
    / g; L$ N- Z# }5 Z, u
  27. }
    ! C. [3 j& A. ~+ S
  28. / \5 h8 c) L1 d" A7 Y
  29. uint8_t CanRecv(uint8_t channel, can_frame_t *frame)+ R  T% _. g$ z& w
  30. {: N6 A# S' j% B( I# S! ~+ |
  31.   can_dev_t *dev = can_dev_get(channel);
    / j8 F& Z0 c0 @: r: @$ o. {, _
  32. - z' _; u7 \, W% \
  33.   if(dev == 0)6 Y+ ~! C' t+ ]" C7 O* f& o" E
  34.   {4 F2 p3 t" l' ]" T1 P0 @
  35.     return 0;" s% F5 \+ `3 A3 A5 Z* c6 d
  36.   }
    3 g+ t2 g1 W/ _# e' Q

  37.   }$ W' C3 N1 K! n
  38.   return CanQueueRead(&can1_dev.recv, frame);
    4 O# }, X9 J; i& z- _/ k* M% ^# ~
  39. }
复制代码
  1. // CAN中断
    : U! r$ t4 i8 Y/ x
  2. void CAN1_RX_IRQ_FUNC(void)
    / G2 |4 p$ \6 }4 G
  3. {- D2 B$ z* E/ u. r& Q* b. L
  4.   HAL_CAN_IRQHandler(&can1_dev.handle);- R0 U; `* \8 i& S# y5 I
  5. }
    * t- P3 _# |: o" x

  6. - v, R# z; k, W% }; f4 n6 `6 Q# p
  7. void CAN2_RX_IRQ_FUNC(void)
    / B, C8 B1 \( n$ Z& o, K/ w
  8. {+ k3 M: p, s, d
  9.   HAL_CAN_IRQHandler(&can2_dev.handle);; g8 H4 Q7 l, E1 U( u
  10. }' z0 ^* w  _8 _% K. L
  11. 9 G4 h0 H9 P; N( e8 F
  12. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)( c. c+ I* l0 h  b% P0 D; C, ^
  13. {
    1 ?8 ~6 R$ h6 N9 L9 O: H6 n: U
  14.   if(hcan == (&can1_dev.handle))
    ; J" I" V. X2 x' @! N. i7 b" I
  15.   {
    4 w" y! b6 R+ k& y
  16.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开. D( K8 m; H0 s
  17.     __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断
      o( `* a  R# X! y& x
  18.     CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);
    6 Y% ]. _; ]! a+ i
  19.   }. ]% C& {; L" _8 Y: d" ^  Z& r
  20.   else if(hcan == (&can2_dev.handle))! E7 Q2 a1 ?, m8 Y& c
  21.   {
    ( a  z  |% H8 j( t& s0 a' [- t( [
  22.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开. W# J0 Q" \: x) G! n% v6 `
  23.     __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断$ l. ^( `1 z( P2 M% S) q9 J, r* a
  24.     CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);
    , j/ W" S4 C: A2 A7 I1 n1 u
  25.   }
    / j7 Z3 a1 A" k9 Z1 ]' J7 V
  26. }
复制代码

( z; `+ j8 o* D* U" N9 ^        之所以使用列表的形式,是为了方便增加和删除CAN通道和使对外的接口更统一,不会出现CAN1Init() CAN2Init(),个人习惯问题。+ L) `8 o4 g; _

4 s' D. o; [/ f2 `$ _
8 k5 t' I( J$ a) i
. C6 l; u, z7 }! G- R  K7 K9 ?) T# B
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版