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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
一、CAN基础
# I* k/ \/ i- ~差分信号:显性电平对应逻辑0,CAN_H和CAN_L差为2.5V;隐形电平对应逻辑1,CAN_H和CAN_L差为0V。
% r2 ^+ Y: H2 D* N7 P! P4 T7 Q5 e
CAN总线的开始和结束都有一个120Ω的终端电阻。
+ D' g  ^- M) S% p4 l4 n2 K+ [+ A$ b, v1 m* D
数据帧:标准帧11位,  扩展帧29位。) C! U0 A& Y3 s" e8 H# i  B( n: s

. H6 g# w/ V! l' F8 A- J其他的一些理论知识就不再赘述了,可以参考维基百科对于CAN的描述。
) I: l3 ~- _" b; Q. g2 @4 d" i; A; j- x; A, j/ }6 f- N
STM32F7xx的bxCAN主要特点:支持CAN2.0A和CAN2.0B,波特率高达1Mbps,支持时间触发,具有3个发送邮箱,2个接收邮箱,可变的过滤器组等。
: D' |  v) o4 F/ ^' F+ }9 X/ K! Z2 v" a3 H, ?6 \
二、几个重要的CAN函数
1 e+ g. ^; ~! ~5 \0 f
  1. HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化
    : \4 k/ ~) V- {) f

  2. " T0 M' u3 u% _0 p- a- G
  3. HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN发送; N" \3 m6 K+ P
  4. 4 E6 C6 h2 d0 X5 X
  5. HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收
复制代码
- T1 y3 b  {% c, r4 r$ p) s5 c
三、几个重要的结构# m. N) F% h* y& m3 R- Z7 F
  1. // CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化结构 发送接收结构体 其余三个是过程变量
    - v  E! C. l; @# M* M
  2. typedef struct
    , h5 d! Y; c- B, Z+ {' S8 V
  3. {$ X( ^9 R4 Q5 W
  4.   CAN_TypeDef                 *Instance;  /*!< Register base address          */: n( l3 ?/ P1 {2 @* F
  5. 0 X7 p; n/ f6 L, ?, A7 u( _  L
  6.   CAN_InitTypeDef             Init;       /*!< CAN required parameters        */( I3 X$ V" V9 J
  7. ) R- `$ M  E: O- ~
  8.   CanTxMsgTypeDef*            pTxMsg;     /*!< Pointer to transmit structure  */$ O8 _( U8 ?: z2 v  P
  9. * x% k( x9 f; r3 Q; }8 U
  10.   CanRxMsgTypeDef*            pRxMsg;     /*!< Pointer to reception structure */
    6 Y3 ^$ j1 X, G6 _" _" A6 @3 T, @$ u/ Q

  11. / D; y. K2 }! J
  12.   __IO HAL_CAN_StateTypeDef   State;      /*!< CAN communication state        */
    % G) _* w6 W6 F( n! U. j

  13. 5 s& Y* E# D7 G4 S' Y
  14.   HAL_LockTypeDef             Lock;       /*!< CAN locking object             */9 z# N/ F0 B, C

  15. - R' a: G, Y; T. D( S6 Q  c
  16.   __IO uint32_t               ErrorCode;  /*!< CAN Error code                 */
    - {$ g0 c* \/ p: T  s# t# ]

  17. 4 h  m/ P: ]! E6 T  k2 J
  18. }CAN_HandleTypeDef;
复制代码
  1. // CAN配置结构体
    2 v, k" V7 [- `; q3 s
  2. // 前5个参数来设置 CAN_BTR —— 波特率+ I3 F) t; w3 l; H/ r" _
  3. // 后6个参数用来设置 CAN_MCR —— 通信相关的控制位/ M& P4 ]9 o0 j: D
  4. typedef struct/ Y& J; C6 h. |, K" e- P) P' V
  5. {* |1 `2 U: I, ^$ u3 A
  6.   uint32_t Prescaler;  /*!< Specifies the length of a time quantum.! _( k6 R8 }: |" T
  7.                             This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */
    * M0 O* g0 A3 ]

  8. 5 O8 r, `6 L5 B+ n
  9.   uint32_t Mode;       /*!< Specifies the CAN operating mode.6 E) G  P7 _1 f4 P) I8 Z& C
  10.                             This parameter can be a value of @ref CAN_operating_mode */7 ^, o# u2 x" h( K8 D2 u) ]1 L. A
  11. $ \3 G- V4 `4 U
  12.   uint32_t SJW;        /*!< Specifies the maximum number of time quanta2 p3 R* ^: ]6 i* E3 w# R
  13.                             the CAN hardware is allowed to lengthen or
    1 b- C6 `- \5 P  A$ q- A8 E
  14.                             shorten a bit to perform resynchronization.: D7 }1 R1 W+ c" Y( ^  @+ v
  15.                             This parameter can be a value of @ref CAN_synchronisation_jump_width */+ c) y4 k$ ]' [
  16. % C5 V, [) h% e1 P4 z6 C
  17.   uint32_t BS1;        /*!< Specifies the number of time quanta in Bit Segment 1.
    6 Q) c- J' }1 d/ V
  18.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 */
    % k& @3 \) V7 B. V

  19. 2 [! p( G1 v" ~5 `! @
  20.   uint32_t BS2;        /*!< Specifies the number of time quanta in Bit Segment 2.
    . w) u) Z2 L5 j! k* j0 {. Q6 o, ]
  21.                             This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */1 G& k; v, k3 ?) ~6 t7 x' U

  22. + z8 E3 ^/ t3 T. {
  23.   uint32_t TTCM;       /*!< Enable or disable the time triggered communication mode.
    2 x! H: e' _5 M& e" @) D$ u
  24.                             This parameter can be set to ENABLE or DISABLE. */
    ' r8 v# d( F4 P6 s. f) }, i

  25. & O0 N% `! j; e5 M% H
  26.   uint32_t ABOM;       /*!< Enable or disable the automatic bus-off management.) v- @. [8 d+ e% q; n
  27.                             This parameter can be set to ENABLE or DISABLE */6 s$ p$ M& m8 n9 W: N
  28. # f8 \7 d! A+ Z  H* F
  29.   uint32_t AWUM;       /*!< Enable or disable the automatic wake-up mode.
    . `) L3 \5 L  A: S8 `
  30.                             This parameter can be set to ENABLE or DISABLE */
    ' [3 t" l3 B- E; V: n8 K, B
  31. - U$ P% X. Z/ Z: }+ w
  32.   uint32_t NART;       /*!< Enable or disable the non-automatic retransmission mode.
    5 P- L. b$ R4 @; S: f  O7 g( z! H
  33.                             This parameter can be set to ENABLE or DISABLE */
    ) Z5 Z! U% J# u" L* h
  34. . i  E3 h# n, O# w
  35.   uint32_t RFLM;       /*!< Enable or disable the receive FIFO Locked mode.( H! @) `( X6 L' v
  36.                             This parameter can be set to ENABLE or DISABLE */
    ! q* }4 Y3 K# H+ s/ b
  37. ; c2 P7 p) o. E$ @+ \+ p
  38.   uint32_t TXFP;       /*!< Enable or disable the transmit FIFO priority.
    $ C3 U9 F, M6 Q* B: r
  39.                             This parameter can be set to ENABLE or DISABLE */
    . K0 W. n) \7 H! @2 A" ^* p
  40. }CAN_InitTypeDef;
复制代码
  1. // 过滤器设置
    ! x1 i  S0 T. d3 g" v1 R
  2. typedef struct; E' b1 X# M5 W
  3. {
    6 q* u0 @& ^1 t0 R/ z7 e7 s4 P
  4.   uint32_t FilterIdHigh;          /*!< Specifies the filter identification number (MSBs for a 32-bit
    - g5 M7 x& _( n. {1 [
  5.                                        configuration, first one for a 16-bit configuration).  S  z( ]; X, b' t
  6.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    . @7 B7 B2 c+ }
  7. # R5 r+ ?0 H; F2 H  D
  8.   uint32_t FilterIdLow;           /*!< Specifies the filter identification number (LSBs for a 32-bit0 c/ Y' R: n6 S7 p+ @- ]
  9.                                        configuration, second one for a 16-bit configuration).
    # ~3 J; g1 C6 V! e$ O* B; m0 G  d2 W
  10.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
    ! A$ j& P2 T+ q2 `& u+ Y

  11. 0 m  M7 ^% q2 c2 t5 f5 l0 Y+ H! O( q- l
  12.   uint32_t FilterMaskIdHigh;      /*!< Specifies the filter mask number or identification number,
    1 @: `: Q3 e+ o2 N# S& P
  13.                                        according to the mode (MSBs for a 32-bit configuration,
    1 ^3 P" N; y! V  x
  14.                                        first one for a 16-bit configuration).: F* \+ F5 @2 F3 {
  15.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */' L+ b% g: Y9 j" H5 ^( v% i

  16. ) s2 }4 k- D4 C
  17.   uint32_t FilterMaskIdLow;       /*!< Specifies the filter mask number or identification number,6 q  r+ j" n, {% e& J+ U
  18.                                        according to the mode (LSBs for a 32-bit configuration,
    3 l2 q1 b4 ?" Z
  19.                                        second one for a 16-bit configuration).
    # a7 Y8 X0 i  @5 ]+ P; \* w
  20.                                        This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */$ G% `! r9 c' v' m# w
  21. 3 h8 X$ n5 u* i$ F
  22.   uint32_t FilterFIFOAssignment;  /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.
      d1 {4 h- G( w
  23.                                        This parameter can be a value of @ref CAN_filter_FIFO */
    4 B6 _/ i5 J/ R+ h

  24. ! A* m7 V7 `% {' P  ?; x/ Z6 r
  25.   uint32_t FilterNumber;          /*!< Specifies the filter which will be initialized.
    + D1 A4 W- X* g7 X3 L
  26.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 27 */0 A" F( X: Y' A3 A' J8 z4 b9 O

  27. ' m" E" ^. ^  G& M4 [) p0 h6 m1 P) f
  28.   uint32_t FilterMode;            /*!< Specifies the filter mode to be initialized.8 P# d) v( t% u! R
  29.                                        This parameter can be a value of @ref CAN_filter_mode */1 {  ]. ?' P4 J: ?4 @
  30. , V6 w5 E- p0 [
  31.   uint32_t FilterScale;           /*!< Specifies the filter scale.( a$ }$ C6 j, R2 |0 Z
  32.                                        This parameter can be a value of @ref CAN_filter_scale */
    4 @7 s$ ?3 x- J8 @0 {
  33. " h  l+ |9 r' G! G9 a
  34.   uint32_t FilterActivation;      /*!< Enable or disable the filter.% G3 j0 A( L; p) ^
  35.                                        This parameter can be set to ENABLE or DISABLE. *// ?5 h7 d8 z0 W8 n

  36. 7 Z( F. F' r' i" v$ d8 Q. f
  37.   uint32_t BankNumber;            /*!< Select the start slave bank filter.
    8 v* |5 g& H' i3 `3 _; v; g
  38.                                        This parameter must be a number between Min_Data = 0 and Max_Data = 28 */
    # y0 k; p4 x/ E, {7 w+ ]8 v

  39. 5 L* J* j0 k% Q' w6 p3 R; W
  40. }CAN_FilterConfTypeDef;
复制代码
  1. // 模式  我们使用普通模式
    ( B$ @: M: ~3 G; D; @
  2. #define CAN_MODE_NORMAL             ((uint32_t)0x00000000U)                     /*!< Normal mode   */
    # r! s. k( }  o" H
  3. #define CAN_MODE_LOOPBACK           ((uint32_t)CAN_BTR_LBKM)                   /*!< Loopback mode */
    7 p+ n5 `  j* B
  4. #define CAN_MODE_SILENT             ((uint32_t)CAN_BTR_SILM)                   /*!< Silent mode   */  _% e# d4 \$ m$ C
  5. #define CAN_MODE_SILENT_LOOPBACK    ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM))  /*!< Loopback combined with silent mode */
复制代码
  1. // 标准帧 扩展帧
    " |3 n& H! L- x' K! {6 R
  2. #define CAN_ID_STD             ((uint32_t)0x00000000U)  /*!< Standard Id */
    - [" K7 [+ ~( ~( J% x# t
  3. #define CAN_ID_EXT             ((uint32_t)0x00000004U)  /*!< Extended Id */
复制代码
  1. // 数据帧 远程帧
    , R% R" y* W. |
  2. #define CAN_RTR_DATA                ((uint32_t)0x00000000U)  /*!< Data frame */
    5 y6 s9 W: O( Y  g: v& {( o
  3. #define CAN_RTR_REMOTE              ((uint32_t)0x00000002U)  /*!< Remote frame */
复制代码
  1. // CAN中断使能
    9 z8 s, Q; Q7 K4 X( z
  2. __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__)
复制代码
  1. // 接收中断1 @+ u* }, H* l7 G
  2. #define CAN_IT_FMP0                 ((uint32_t)CAN_IER_FMPIE0)  /*!< FIFO 0 message pending interrupt */! t- ]0 b! W, |5 ^
  3. #define CAN_IT_FF0                  ((uint32_t)CAN_IER_FFIE0)   /*!< FIFO 0 full interrupt            */
    ( p# A3 H0 P- v' q- Y
  4. #define CAN_IT_FOV0                 ((uint32_t)CAN_IER_FOVIE0)  /*!< FIFO 0 overrun interrupt         */' E$ }4 P  \2 [  w  m" C
  5. #define CAN_IT_FMP1                 ((uint32_t)CAN_IER_FMPIE1)  /*!< FIFO 1 message pending interrupt */
    & K4 D+ L# U) `' E  T
  6. #define CAN_IT_FF1                  ((uint32_t)CAN_IER_FFIE1)   /*!< FIFO 1 full interrupt            */" Y/ p* R  ?4 o
  7. #define CAN_IT_FOV1                 ((uint32_t)CAN_IER_FOVIE1)  /*!< FIFO 1 overrun interrupt         */
复制代码

$ `0 V4 @3 r% \+ x# K: c四、接口设计. P5 b3 h- a" ^! J/ z
与串口类似,使用中断接收。先封装单路CAN需要的几个小接口,再顶一个列表,最后使用统一的接口扫描这个列表。
; C, E* P  f4 F* D( G
* V+ O! q$ a* m- _
  1. typedef enum
    8 G/ W' `, A0 E; _
  2. {' p+ g6 y, S* z2 E( e/ B/ R3 \
  3.   CAN_CHANNEL_NONE,
    . j" `' u4 E: l- i' X+ K; U) T/ ^
  4.   CAN_CHANNEL_1,
    5 `) }* C, U, a* O: {# Z
  5.   CAN_CHANNEL_2,
    : T* T( l* I6 r! S# k5 M0 W
  6.   CAN_CHANNEL_NUM8 Q; F% ^+ L& }' h6 s, H4 B3 i5 q0 G
  7. } can_channel_t;
    + M' P. p* w7 @* K* @) k$ w9 w6 ]
  8. 8 M1 f' c, h; o/ Z+ x
  9. #define CAN1_CHANNEL              CAN1
    6 J* z& Q0 G+ W9 \/ [& s5 O7 W# t
  10. #define CAN1_PREEMPT_PRIO         CAN1_RX_PRIORITY% G0 g. B$ v2 v8 W6 E
  11. #define CAN1_RX_IRQ               CAN1_RX0_IRQn
    * D$ Z$ m3 {, z
  12. #define CAN1_RX_IRQ_FUNC          CAN1_RX0_IRQHandler
    ' I* g  Z. v8 C
  13. #define CAN1_CLK_ENABLE()         __HAL_RCC_CAN1_CLK_ENABLE()
    + O" z: \$ G: ~( x6 N1 d
  14. #define CAN1_TX_PORT              GPIOA
    / F& D" \1 o3 h* d1 s
  15. #define CAN1_TX_PIN               GPIO_PIN_12) I$ w2 G+ D. W
  16. #define CAN1_TX_AF                GPIO_AF9_CAN1
    - N& e9 l3 [9 g, E
  17. #define CAN1_TX_CONFIG()          GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF)9 n. K3 B6 h& s4 T8 u/ c2 L
  18. #define CAN1_RX_PORT              GPIOA
    ' Z* |, b) c: a
  19. #define CAN1_RX_PIN               GPIO_PIN_11
    3 W# g' u) O9 w% ^
  20. #define CAN1_RX_AF                GPIO_AF9_CAN1
    / n$ P6 F2 `  d* O+ }. I  e
  21. #define CAN1_RX_CONFIG()          GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF)0 [; \: a5 i- T# E% h0 h3 F" x* V
  22. % Y7 e' T4 s. Z0 r+ I
  23. #define CAN2_CHANNEL              CAN2% M- q$ z- C% @
  24. #define CAN2_PREEMPT_PRIO         CAN2_RX_PRIORITY4 c- C9 r: T, f( P: H0 ^
  25. #define CAN2_RX_IRQ               CAN2_RX0_IRQn' X3 m+ y$ E* g/ ?
  26. #define CAN2_RX_IRQ_FUNC          CAN2_RX0_IRQHandler( D8 a2 x. x: f; ^. }9 v4 h
  27. #define CAN2_CLK_ENABLE()         __HAL_RCC_CAN2_CLK_ENABLE()
    - S0 u( G, R5 |+ P% ~  \% b
  28. #define CAN2_TX_PORT              GPIOB
    * l0 H' y8 y0 W8 z. i4 i
  29. #define CAN2_TX_PIN               GPIO_PIN_6. ]+ `, X' [8 B9 [, j% J- |
  30. #define CAN2_TX_AF                GPIO_AF9_CAN2+ j# j! ?* Y3 F8 e
  31. #define CAN2_TX_CONFIG()          GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF)
    , h+ K  f% v- H+ [
  32. #define CAN2_RX_PORT              GPIOB
    1 y- F, D% ^- v/ m4 \5 m3 p' }7 {+ k& s* [
  33. #define CAN2_RX_PIN               GPIO_PIN_5' c3 _' s7 r5 _: S6 Q( M
  34. #define CAN2_RX_AF                GPIO_AF9_CAN2& Z3 a8 D& Z9 N
  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设备结构体* A  ^) b/ u3 S; @/ l
  2. typedef struct
    * m. j& n5 M4 q
  3. {9 r1 h  @% R% g5 y3 g! c, z
  4.   CAN_HandleTypeDef handle; // CAN操作句柄7 e, v, o! I8 F- s7 I, i4 q2 c

  5. , I- h3 O+ Y4 C8 d5 @4 d& s
  6.   CanTxMsgTypeDef tx;       // CAN发送& s* P( }2 L! p9 V7 U

  7. 0 L/ j  ~5 d! g5 b6 A
  8.   CanRxMsgTypeDef rx;       // CAN接收
    ' Y: |$ E' B+ d
  9. 6 G5 t7 O, b5 C4 ~6 I+ k- g
  10.   can_queue_t recv;         // 接收队列
      q  L$ R8 u- f- f6 n
  11. , Y7 ]( k( d# p9 ^9 A1 g6 }0 c
  12. } can_dev_t;
复制代码
  1. // 将每路CAN封装成几个小函数& |" |! ^! F: x, b
  2. static can_dev_t can1_dev, can2_dev;7 E, E1 M9 l! G5 ~2 \: J4 A

  3. & v2 c1 w) o2 g9 y& k; E) ]
  4. static void can1_var_init(void)' ^5 y: Z2 I1 A" j5 t
  5. {6 t# I" ^2 r% ^# A
  6.   can1_dev.recv = can1_queue_recv;
    % U3 a/ K. h9 B8 g( F, E8 j

  7. ; b9 z7 ^5 Q8 m
  8.   CanQueueInit(&can1_dev.recv);
    : G- q& _' k- S4 I) A/ P' K
  9. }: o: I5 O& O3 `4 [" i" o
  10. 9 D" D6 ]% u8 Q
  11. static void can1_gpio_init(void)
    8 ?) U0 p: {  A" h& K1 j5 R8 T, i6 V
  12. {
    9 Z2 ~8 m/ d8 I! v# |) ]7 k4 ~( _
  13.   CAN1_TX_CONFIG();+ U- t; r6 e: Q+ l- {
  14.   CAN1_RX_CONFIG();; i: A8 t: j1 Y5 ^9 c" }+ T6 B8 J( x
  15. }
    ( f& k8 ?- w. u1 M6 {* |+ I4 k
  16. 1 q- \% N7 c! Q. k: S) i2 b2 }
  17. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M% @1 [  @+ l% W, Y6 Z
  18. static void can1_mode_init(void)" ]) u& D; l. u; o, |- p8 _/ `! G
  19. {" R5 ^- ]) I% k
  20.   CAN1_CLK_ENABLE();0 V# B6 ?& y% F) k

  21. 8 f8 j7 B2 j3 H% p# N: W3 A/ Z
  22.   can1_dev.handle.Instance = CAN1_CHANNEL;0 h% E. U( G( E4 ^) Z, p
  23.   can1_dev.handle.pTxMsg = &can1_dev.tx;
    & Q8 R8 i# N/ h9 v
  24.   can1_dev.handle.pRxMsg = &can1_dev.rx;
    8 g4 w' ~* }& K
  25.   can1_dev.handle.Init.Prescaler = 6;
    ! p  A0 J( z1 X
  26.   can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;0 _4 P2 M% r/ Z& D
  27.   can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    + Q% K3 B4 }% r8 b" {8 X- C
  28.   can1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    / T2 y: g) S" P, m, R+ A4 J+ y" Z
  29.   can1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ. I" A  y  D' {# K
  30.   can1_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    ! C% |8 D2 g& @% f8 Y& M
  31.   can1_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理) X! _9 d. E+ O9 p
  32.   can1_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
      v& q2 \8 m/ K9 V
  33.   can1_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送+ H3 I, X3 [" E3 Q- H
  34.   can1_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的) K1 z. G  @4 E1 C
  35.   can1_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定
    7 N: K* i' f+ O& }
  36.   HAL_CAN_Init(&can1_dev.handle);( e) ~" G; m9 L6 q0 r* j
  37. }9 O, z0 G6 Q8 N6 Z3 G
  38. ' _" U* O8 [' j
  39. static void can1_filter_init(void)
    / J2 [& _0 p3 B! c% [; r9 z4 w
  40. {4 w8 E. s7 r- T7 O! I6 W4 L' a" X
  41.   CAN_FilterConfTypeDef  filter;
    % j. i) Z( P4 V9 B/ n8 H9 R

  42. 4 d; Y1 z6 `& i! U: G5 `5 b- g" h. F
  43.   filter.FilterNumber     = 0; // 过滤器0
    ; G6 j) b# u) t- y- O
  44.   filter.FilterMode       = CAN_FILTERMODE_IDMASK;" L. p+ I; r4 e% I: A
  45.   filter.FilterScale      = CAN_FILTERSCALE_32BIT;: p* s% K7 Y0 H7 M# K' r
  46. & V) z3 V0 \" |+ i- O7 v7 s& O
  47.   filter.FilterIdHigh     = 0;% I+ N6 d, p; a* A
  48.   filter.FilterIdLow      = 0;
    ( U4 g$ k, y3 Z: L# n. m
  49.   filter.FilterMaskIdHigh = 0;% a1 Q; A4 v6 K, a: T
  50.   filter.FilterMaskIdLow  = 0;
    : p- z- ?6 S3 _6 }, O

  51. 0 s; Q# k: v  z$ T6 [0 {0 y
  52.   filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO05 N1 K2 W, n& V& C
  53.   filter.FilterActivation = ENABLE; //激活滤波器03 a3 A( G* Y. V5 A" c: T5 m
  54.   //filter.BankNumber=14;
    $ W% a, X8 h: F: a- ^$ P
  55. - ]# v% e7 v: f# X
  56.   HAL_CAN_ConfigFilter(&can1_dev.handle, &filter);& C7 K* @: ?1 c# k3 ^  ~3 L
  57. }4 v3 q" ~% d6 F7 j9 b

  58. 1 a% d' q( b  F) A6 W' x
  59. static void can1_nvic_init(void)
    $ ~9 o: x6 W+ Q" z8 ?& {6 N  _* _
  60. {
    , J& ^# Y6 h; a6 b2 s/ |) \9 E
  61.   __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许.
    8 q5 y2 i& H: I2 M/ G7 f! P) w
  62.   HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);% f) r% }9 o5 M
  63.   HAL_NVIC_EnableIRQ(CAN1_RX_IRQ);
    ; O! z$ Y* _  s$ c- Y+ R
  64. }
    ( d+ D$ ]% N. ?! x- c
  65. 0 E9 k+ V: N" ~+ ^0 s! k* |
  66. * m5 R7 N; c: i! q3 c

  67. 9 b( }! X) X. k2 Y6 V! R# V
  68. static void can2_var_init(void)
    4 o! A& L3 e: e6 P
  69. {
    8 ^+ G, H; ], P* v" y$ Z, @
  70.   can2_dev.recv = can2_queue_recv;
    : Z6 s; q: d' y0 L3 W* d

  71. + j. d( {# H. j; f2 Y7 Y
  72.   CanQueueInit(&can2_dev.recv);
    5 v' h7 w0 |) s4 y# B
  73. }
    8 u8 k9 L3 s* D* t  F

  74. # v) W8 M5 {& T" D2 v+ k* g5 T6 _
  75. static void can2_gpio_init(void)
    7 `8 i& n3 E; Z- _' s, `
  76. {' L1 n& d' [& A! w- Y# U
  77.   CAN2_TX_CONFIG();
    $ y, |2 {" a: V- _6 O$ L
  78.   CAN2_RX_CONFIG();
    ( z4 u" z; I# y3 w
  79. }. Y$ E( s- S  y7 P  J0 F" h9 N# y/ d
  80. ! f2 S! a! ?) H" l& l: A
  81. // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp)  Fpclk1 = 54M
    7 O/ j6 {. z: _/ [5 u0 N
  82. static void can2_mode_init(void)
    * ?% Y$ a8 r! k
  83. {3 Y$ |7 G- C- L2 b
  84.   CAN2_CLK_ENABLE();
    . c- a! S1 \0 u  G5 H# o

  85. / C" |7 y" D6 \7 F2 v5 W4 _  G
  86.   can2_dev.handle.Instance = CAN2_CHANNEL;$ B; S, B, [7 _/ v+ l
  87.   can2_dev.handle.Init.Prescaler = 6;
    % H) O& H3 D. M( ^7 P
  88.   can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;1 F* N0 L1 O/ X* N2 W; v
  89.   can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    6 a7 n# L1 a  x: @* Z
  90.   can2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    $ I7 C3 V7 J& H# u$ s3 D
  91.   can2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ: T9 T" U' K- j* _+ O. z0 }9 x
  92.   can2_dev.handle.Init.TTCM = DISABLE;    // 非时间触发通信模式
    + d( g4 z) R7 o" N
  93.   can2_dev.handle.Init.ABOM = ENABLE;     // 软件自动离线管理
    4 h  J  J6 j% h8 M' n! A
  94.   can2_dev.handle.Init.AWUM = DISABLE;    // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)0 {* U- J6 i; V. Q8 O
  95.   can2_dev.handle.Init.NART = ENABLE;     // 禁止报文自动传送
    $ z1 q7 A" Q( A8 M! W
  96.   can2_dev.handle.Init.RFLM = DISABLE;    // 报文不锁定,新的覆盖旧的
    9 m$ r# y/ c& J' k" y) y
  97.   can2_dev.handle.Init.TXFP = DISABLE;    // 优先级由报文标识符决定/ n0 g2 f9 k! L6 g# T: |2 B
  98.   HAL_CAN_Init(&can2_dev.handle);
    " A( j) D3 h# Z& S
  99. }
    : L6 O/ g  `2 S  f) l
  100. 5 t7 Y# L: C9 s0 x8 Q& [$ D
  101. static void can2_filter_init(void)9 o* _) A1 f2 V! m2 e+ `) ?+ ~8 V7 p
  102. {* U+ {0 G* C3 k- G6 S% C5 X6 F
  103.   CAN_FilterConfTypeDef  CAN_FilterInitStructure;9 u6 u+ q2 E, [& Y& i# u
  104. 7 Q- l4 k" q$ T$ t' E
  105.   CAN_FilterInitStructure.FilterNumber     = 14;* f; r, i1 }% S, _7 T1 T: o
  106.   CAN_FilterInitStructure.FilterMode       = CAN_FILTERMODE_IDMASK;
    / o( [2 W2 g2 u5 G5 N% f* \: d1 G/ I  j# q
  107.   CAN_FilterInitStructure.FilterScale      = CAN_FILTERSCALE_32BIT;7 L: F8 x8 U& `  c. @& J# f+ x

  108. 7 f) u$ P0 H, U4 ]' L: c
  109.   CAN_FilterInitStructure.FilterIdHigh     = 0;
    ! b. C4 b) F5 c, @) V& V
  110.   CAN_FilterInitStructure.FilterIdLow      = 0;
    - T( Y. L% s5 y7 R4 @9 C
  111.   CAN_FilterInitStructure.FilterMaskIdHigh = 0;
    $ \" L; a$ ^- `) c
  112.   CAN_FilterInitStructure.FilterMaskIdLow  = 0;
    1 Y- g" A3 W2 W- |% ~/ ~3 F- s, g
  113. ( s+ }* y+ X& Y8 _# L) c
  114.   CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0) M* H/ \+ h: |$ d
  115.   CAN_FilterInitStructure.FilterActivation = ENABLE; //激活滤波器0
    1 V1 ?0 P' ]1 G) F. G0 _5 ?6 H
  116.   //CAN_FilterInitStructure.BankNumber=14;8 |9 }8 U5 G  V' N6 q
  117. 6 E4 D4 Z8 H2 X2 c5 t7 q: d
  118.   HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure);- ]' Q# J* |) P& ]0 E1 D: F
  119. }, X& R, I3 f8 k
  120. 4 C. x5 g0 Q- L0 @9 d
  121. static void can2_nvic_init(void)  I3 V$ c0 ?! n1 G, j; F
  122. {
    : I" J: B7 d. X4 S) Z  K9 ~
  123.   __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许1
    & i" V1 u7 @5 ~) C) m0 K
  124.   HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);
    % a8 b9 L9 C& d$ z4 d+ w) b$ O
  125.   HAL_NVIC_EnableIRQ(CAN2_RX_IRQ);
    " Q1 r7 F) p! f8 a/ Q( m
  126. }
复制代码
  1. // 每路CAN都有的几个操作,使用列表包含,然后统一扫描处理) M. o/ \& p; N" p7 p! [1 s
  2. typedef struct, X( ?1 S2 K& S6 I2 e- |+ k
  3. {
    ) o  G% Y8 v+ K& y. C: u9 z0 j
  4.   uint8_t channel;
    # B+ C7 L* X% }8 I6 S6 g
  5.   can_dev_t *dev;
    : K: q- n1 \8 d2 D9 W" M, L4 e6 H, [8 y1 `
  6.   void (* var_init_cb)(void);
    2 g5 L; B5 H' W& l5 @/ K% Y: v& F
  7.   void (* gpio_init_cb)(void);
    ( ^0 k* j/ @7 U  ^. d
  8.   void (* mode_init_cb)(void);
    * Z4 n' H, \' A6 f* l# S  _# W
  9.   void (* filter_init_cb)(void);
    . ^* u: P7 C2 ^7 @7 D% `* e
  10.   void (* nvic_init_cb)(void);
    , {0 E1 T0 B9 l- c9 R( ^# o
  11. } can_config_t;
    * J' t6 V, P4 r: T( A3 O

  12. * y% V& B2 I, v2 F
  13. static const can_config_t can_configs[] =, S! k1 K* K0 W. W1 }  b9 u4 N
  14. {* ]7 p; e3 w) ]0 G; i5 J
  15.   {CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},
    6 c, _, s0 g8 o0 o5 p; ?! W% G
  16.   {CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init},- U2 F) |) M: A( C9 d
  17. };5 z" q$ J9 F3 o4 A5 ?

  18. & `! S- }6 d. J# e% @$ P# k4 o
  19. static can_dev_t *can_dev_get(uint8_t channel)0 r& }0 Q8 h' W9 V5 p2 h( h
  20. {
    , R5 G, s1 f. i
  21.   uint8_t i;! n& E( x9 w0 I1 B9 D  c. L- n/ ?$ M

  22. ' D+ w, g8 k' C& i0 W
  23.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    1 k# C( f3 ?8 q- o3 S  C
  24.   {
    ! ]- K% R# ~' W0 R
  25.     if(channel == can_configs<i>.channel)
    : u' k& `. O$ D) U/ d( |% a3 C; ]
  26.     {
    & `. X; y+ k# D8 R5 N
  27.       return can_configs<i>.dev;
    , T$ v! b" B+ @$ N$ [* O
  28.     }, x7 M) C$ p/ D3 y/ T- {/ ]
  29.   }  Y& `( T4 S! ?2 P( \9 m% {) ]+ |
  30. 5 h+ R4 n$ W% ?! }" H! h/ S0 z
  31.   return 0;9 E$ Z4 ?) e* V7 e3 O1 l; q
  32. }
    ) [3 N6 D7 {) x7 \6 f: t* ]
  33. # c+ V& A, N. t& W" E: ~7 g9 E
  34. static void can_var_init(uint8_t channel)
    % b' N+ _! v9 @) _0 u
  35. {
    4 W$ g* c5 [5 S, O
  36.   uint8_t i;: T0 S6 \6 g( ]0 J

  37. + k; J! q9 a: [5 O
  38.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    4 z4 E# `) T& X3 J
  39.   {
    7 g/ r/ g6 d* a% @# C
  40.     if(channel == can_configs<i>.channel)$ `- `" P% ?5 e/ v9 U7 V1 O
  41.     {9 o% Y: r5 t, j7 ?1 W
  42.       can_configs<i>.var_init_cb();, u1 y1 l% i0 e
  43.       return;
    & }* ~- E5 x1 X
  44.     }
    # V  d# N2 ~* i6 f  s! Q
  45.   }, q+ \% A0 P% q
  46. }* j, v6 V) Z0 v8 y1 K  Z

  47. 3 E& U" n) y" [1 X+ W; ^7 g5 Z
  48. static void can_gpio_init(uint8_t channel)/ L3 P/ f4 m6 g: {
  49. {6 I, |4 _- G& O. S' n4 T) A  w+ k
  50.   uint8_t i;
    3 E. D9 l5 e# S& i; G

  51. # n7 N% @. J! G: s& ~" I: g
  52.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)" T1 p0 y# v+ W$ }  i6 R: w
  53.   {1 I  J' M# T+ M! m) D! J
  54.     if(channel == can_configs<i>.channel)4 B, j" ^' [) }: [% c! ?
  55.     {7 q' {/ L9 j2 e+ S( ?$ Z) Q7 T
  56.       can_configs<i>.gpio_init_cb();( K$ p9 W7 ?4 s9 i! N
  57.       return;
    : v6 f2 B; ?& r- T
  58.     }4 y( V- Y* E7 d8 E& S8 U
  59.   }2 Z  r# W$ [; w
  60. }
    4 ?  w3 x+ C! r7 [( C# x; G& P4 }

  61. + m+ e9 N. H6 o" t( y8 {% }
  62. static void can_mode_init(uint8_t channel)
    : c& q1 _- B9 F
  63. {
    2 ?( o* o; S, }2 p
  64.   uint8_t i;
    $ K- ?& h. F' _1 t
  65. ) J$ p4 _' m' G
  66.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)" E9 ?3 _/ p6 h0 v+ Z
  67.   {
    3 o8 k3 ?* \2 n7 j8 O+ a
  68.     if(channel == can_configs<i>.channel); j9 W( p/ w! f
  69.     {
    7 w4 S. d% H8 W
  70.       can_configs<i>.mode_init_cb();" W& c% K5 f( q# n1 E" D- M& ^
  71.       return;# t8 _$ P" C) p9 Q" {# T0 ?8 N" h
  72.     }* ]! X- a$ P% {! u( i: S- j& a
  73.   }
    5 j! `* t& q- Y  {7 x# O
  74. }8 Z. q* a! T/ p  e3 A

  75. 9 E5 P3 @% k0 o% ]2 @2 _* `7 \, k
  76. static void can_filter_init(uint8_t channel); b4 h% \9 P2 t1 R/ t& \* Y0 F
  77. {" W6 z& g+ |) V
  78.   uint8_t i;4 f1 p* k3 I( k2 X, ]
  79. " a8 i7 y% Y* }; q: A: o
  80.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    ( s8 R+ L( P& T/ I: w5 U+ D
  81.   {8 H% b, v, V! i3 a3 M  k) e. a
  82.     if(channel == can_configs<i>.channel)
    % ^1 w+ w+ C1 g4 Y9 w
  83.     {# A: z6 ^% k# _& }, N3 G! `) g
  84.       can_configs<i>.filter_init_cb();
    , f0 s, R  J& F( H. ]1 b, u
  85.       return;
    3 C/ k% @" _9 G7 L& V* {
  86.     }; s: S' n- o' J" g
  87.   }" C: m5 ]( {3 s
  88. }, X* x# H6 m) l( g$ {. N6 G

  89. 7 Y) [# P5 n* P6 o. H
  90. static void can_nvic_init(uint8_t channel)5 ~4 N; H9 n+ q* T
  91. {
    ; t3 _+ _7 R6 |0 w; R
  92.   uint8_t i;
    - ?$ R. o- [5 t

  93. : o& L; |2 [& ]% l1 a
  94.   for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
    4 t1 S9 W+ ^0 Q
  95.   {
    3 X2 l$ S4 ^! P+ W3 `. V- K% X7 D
  96.     if(channel == can_configs<i>.channel)
    2 i7 q$ M5 M* Q) S
  97.     {
    ; ?  b! s/ A' ^5 T* i
  98.       can_configs<i>.nvic_init_cb();, R) c- P0 f% Q  Z' {2 Y& ~7 T
  99.       return;: G5 b" m0 n3 v' E& j+ N0 _' n, I( g
  100.     }
    3 T$ S9 w8 V% P3 g: w+ @1 E. e
  101.   }
    + P( Z" `; L4 c( I; [; y9 d( n
  102. }</i></i></i></i></i></i></i></i></i></i></i></i>
复制代码
  1. // 对外的接口 初始化 发送和接收
    ) Q' q8 a/ A7 [% F9 ], |
  2. void CanInit(uint8_t channel)+ g' O4 M0 D( t  L& R
  3. {) v& V2 t3 V$ L0 }  _
  4.   can_var_init(channel);" N4 P+ _1 i, A  M( c9 j+ l
  5.   can_gpio_init(channel);5 d# x# H- n) |3 w& R' ]$ |
  6.   can_mode_init(channel);
    3 ?0 a" g1 [: o9 P) l4 Q
  7.   can_filter_init(channel);
    2 S7 [* L7 R# ~/ w! N6 _
  8.   can_nvic_init(channel);
    ! H: f1 h  U9 P# a
  9. }2 _  M5 M& R. ^6 U7 f4 `4 Y

  10. % I# I- N" s' D( E9 g  K
  11. void CanSend(uint8_t channel, can_frame_t *frame)
    - G7 Z& N) Y" u( c. l4 R
  12. {3 J" H# M% u5 W
  13.   can_dev_t *dev = can_dev_get(channel);! A( ~, W$ P. Q4 g1 g

  14. , s, v; @+ a: A" @
  15.   if(dev == 0)- e* I( q5 L) c) E; Z2 c( m
  16.   {
    ( E# R& v: ~5 b( F
  17.     return;1 }# J/ @/ c3 d( M& s3 [
  18.   }4 a7 a0 S- M. h* Y- H
  19. 4 D+ k, w% d. f$ P6 b
  20.   dev->handle.pTxMsg->StdId = frame->StdId;
    3 I3 y7 i/ a, l  G$ ?" F( e
  21.   dev->handle.pTxMsg->IDE   = frame->IDE;" k8 M& q: n- m
  22.   dev->handle.pTxMsg->RTR   = frame->RTR;
    & w' {* ]+ z# u+ N2 Z
  23.   dev->handle.pTxMsg->DLC   = frame->DLC;8 ?* ^6 g$ l' l& ~3 h  n+ }7 s
  24.   memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);' Q5 p$ ]+ C/ O* Y/ |

  25. & c7 g7 o1 b$ k/ R4 O  Z
  26.   HAL_CAN_Transmit(&dev->handle, 10);
    # K& I+ a0 T8 c* Z
  27. }) }$ W) u8 Z" ?/ f2 p0 p7 z
  28. : c$ D2 v& f/ ^! g% a7 o
  29. uint8_t CanRecv(uint8_t channel, can_frame_t *frame)' L; P5 Q' ?+ P& |; z( a5 r: a
  30. {5 R. |" l7 v: e; A
  31.   can_dev_t *dev = can_dev_get(channel);
    : D8 h) x0 W9 m$ l) g$ C$ u

  32. / P6 S9 |6 y" b& t9 y5 F8 B) J
  33.   if(dev == 0)
    - s6 L% i3 v* D; u, T
  34.   {
    * a$ W' Z4 O6 G( x) ]% m0 i
  35.     return 0;; k/ V& S) L1 Y; g0 K. d  h# S
  36.   }6 M  H0 t( w5 k" L) ?4 Z" V
  37. 6 \) d% f" K* B/ S3 ?
  38.   return CanQueueRead(&can1_dev.recv, frame);/ C& c7 {. g& m! A3 t
  39. }
复制代码
  1. // CAN中断
    ! K9 [4 z$ L0 g  K& a# j4 h
  2. void CAN1_RX_IRQ_FUNC(void)
    2 P1 d+ j0 h/ Y8 e, }# z
  3. {
      l/ X1 Z) V, P$ ?2 w( }
  4.   HAL_CAN_IRQHandler(&can1_dev.handle);
    # c4 a3 A/ ]9 X5 S4 ^; I
  5. }
    0 M6 v4 |. ~  Z; {( \3 i6 J2 N
  6. ; V" W- k- m) S# n& L: R5 h/ _8 L
  7. void CAN2_RX_IRQ_FUNC(void)
    8 a( `7 D; F( w9 t* W& Q$ Z$ N
  8. {9 e# l/ Z) E0 L# t
  9.   HAL_CAN_IRQHandler(&can2_dev.handle);! T: @/ Q) r7 Y& Z+ n9 C( L
  10. }1 o. V( R. c" y) ^8 Q. N' V. @$ g
  11. - Y$ ]: g0 X; Z" g/ F% Z( ]$ A+ @
  12. void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)
    $ K1 m3 d4 u0 W+ \( E+ L, }' e
  13. {: P  B3 r, W9 p3 }9 }) s6 k
  14.   if(hcan == (&can1_dev.handle))$ T9 _% S# f- W3 ^- r; C6 X( W
  15.   {& i+ T$ `  v( S, r- N+ W
  16.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开
    $ y7 t6 g! j- V
  17.     __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断2 @6 i  _9 g8 o9 Y; D$ ]2 I
  18.     CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);' U- h) @! y$ O/ L  A
  19.   }  W) r, d( f/ t2 [, s
  20.   else if(hcan == (&can2_dev.handle))
    0 y  |; q  |6 e1 C& n+ T1 J! T
  21.   {
    7 @3 d7 q) x9 S. [5 r
  22.     //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开; V: d3 @* e( k5 j) B* s) q5 a
  23.     __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断: L& k6 B4 V4 P3 r6 v# D8 `
  24.     CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);
    ( P7 {0 b& [  q7 `! B
  25.   }
    / w; b9 z; e( n( {! P- ^1 L0 E: B/ O
  26. }
复制代码

/ W. Q9 w3 o; l        之所以使用列表的形式,是为了方便增加和删除CAN通道和使对外的接口更统一,不会出现CAN1Init() CAN2Init(),个人习惯问题。0 T, C- T6 d2 W% n+ ]: v

0 _; V* I: ]: ]2 B. X& Y: O! {! Y9 Y6 N7 g& d' N

$ d. i+ h; @- R. K0 O. Y  V5 m9 H- c$ `  J3 O4 `( D
收藏 评论0 发布时间:2021-12-11 12:00

举报

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