一、CAN基础
0 F; @" y: J/ T6 j" B+ s- a: B差分信号:显性电平对应逻辑0,CAN_H和CAN_L差为2.5V;隐形电平对应逻辑1,CAN_H和CAN_L差为0V。) Y( u2 i4 Z9 N! F j; \
# @; Y1 Y3 b. Z
CAN总线的开始和结束都有一个120Ω的终端电阻。% o( w3 G0 I& {
0 T) y+ I9 s5 R R2 S2 G数据帧:标准帧11位, 扩展帧29位。
- n0 Q h8 f5 _4 F7 V; q# r: C% P1 Z1 C! X* R
其他的一些理论知识就不再赘述了,可以参考维基百科对于CAN的描述。
( f: q/ l$ u8 R1 O K2 q2 U: w, J0 {7 f
STM32F7xx的bxCAN主要特点:支持CAN2.0A和CAN2.0B,波特率高达1Mbps,支持时间触发,具有3个发送邮箱,2个接收邮箱,可变的过滤器组等。
1 y( r* S; b1 ^9 q$ C- {' ?1 L. S' |. E4 [3 q0 ^
二、几个重要的CAN函数
, L" K9 y* j: k+ H \- HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan); // CAN初始化
9 {; t' ~/ r3 v( o0 }% m# x - 4 v7 P! l8 R; V: ~1 m, {' K' F
- HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); // CAN发送- s* r! [, | l7 b1 ^6 F
6 M/ ?7 \" \# s- HAL_StatusTypeDef HAL_CAN_Receive(CAN_HandleTypeDef *hcan, uint8_t FIFONumber, uint32_t Timeout); // CAN接收
复制代码 6 ?3 k4 y4 Q) U7 o! Q' _+ b5 W7 Y$ O
三、几个重要的结构5 f, `' b# G& B& t" Y' G
- // CAN操作句柄 包含CAN基地址(CAN1/CAN2/CAN3) 初始化结构 发送接收结构体 其余三个是过程变量. ]" b3 y( N/ s6 a! x) U+ X
- typedef struct
+ Q b f. E8 b; u& Q - {
/ q) h+ f5 b& `3 w; k - CAN_TypeDef *Instance; /*!< Register base address */
- y( T; m7 S# c* Y8 m+ u! ?
$ S9 q& o8 l* x0 F& Z! Q- CAN_InitTypeDef Init; /*!< CAN required parameters */0 }' O: z% o4 g6 c4 c# F. Z
& F! _, y2 o! v" C: ^5 e1 \- CanTxMsgTypeDef* pTxMsg; /*!< Pointer to transmit structure */
9 w$ ? a/ e' p' K% ^, e# C& G
# V5 p, M; n1 W9 T' z2 l$ a3 y- CanRxMsgTypeDef* pRxMsg; /*!< Pointer to reception structure */
( R9 N R+ o9 q - 2 [. {8 }4 y/ k. ?9 a2 Q; w
- __IO HAL_CAN_StateTypeDef State; /*!< CAN communication state */
: K$ r* {0 l3 E& A - 8 e2 T5 K; i k0 I/ B
- HAL_LockTypeDef Lock; /*!< CAN locking object *// q" G& ]$ @$ A
- ' E- O% ^6 J1 b8 m$ L& S7 ^
- __IO uint32_t ErrorCode; /*!< CAN Error code */
6 y' S$ N! h% E5 x' p
" A9 G H( q- u7 u" p% ]( @- }CAN_HandleTypeDef;
复制代码- // CAN配置结构体 4 o: |2 C" C. C
- // 前5个参数来设置 CAN_BTR —— 波特率+ B2 c3 b) m, i# s N; o
- // 后6个参数用来设置 CAN_MCR —— 通信相关的控制位
/ f. I- f# F8 p* R; u - typedef struct
! A, w2 a& | C7 r K* O - {$ W, W( s# `5 r0 G4 C7 N
- uint32_t Prescaler; /*!< Specifies the length of a time quantum.
5 P8 k- i# z4 p. H& T2 b - This parameter must be a number between Min_Data = 1 and Max_Data = 1024 */
; [( R- H2 s" W
5 m: g/ ~1 `& s* t- uint32_t Mode; /*!< Specifies the CAN operating mode.
2 j: j6 {) ~4 d - This parameter can be a value of @ref CAN_operating_mode */5 r) ]- [5 C8 ?7 O- F, b% ~
4 i( J% w2 U! y n- uint32_t SJW; /*!< Specifies the maximum number of time quanta
" R0 o2 w$ ^: h - the CAN hardware is allowed to lengthen or
1 x' o) R4 B+ r: }1 m& \- b - shorten a bit to perform resynchronization.1 ~7 e W4 ~, `+ U0 i6 `4 K
- This parameter can be a value of @ref CAN_synchronisation_jump_width */: C) k! J/ L. e, ~
9 w: S3 M) [- d8 \1 l; a- uint32_t BS1; /*!< Specifies the number of time quanta in Bit Segment 1.
) g/ Q; f# o, |0 I' S4 Q - This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_1 */
- t! @2 i! K/ ^! j% s - ! o6 \8 C1 s% n' V* |' {1 O
- uint32_t BS2; /*!< Specifies the number of time quanta in Bit Segment 2.
2 s- t* I& i& t3 u6 G# g6 W - This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */* I4 g" I1 w @' F
- 4 Y! Z* K/ o( j& y' c
- uint32_t TTCM; /*!< Enable or disable the time triggered communication mode.$ Z: z- H! [# }* m( V
- This parameter can be set to ENABLE or DISABLE. */
e+ T2 q: H) r1 M/ Y
9 E$ {1 ^2 j$ S2 E! \. @+ j- uint32_t ABOM; /*!< Enable or disable the automatic bus-off management.
, s: s) H: X! ]) P# P - This parameter can be set to ENABLE or DISABLE */
7 ~: ~' P3 g% V. ]. ?& h' l2 P - 8 |; _- X+ ~, ^4 H5 F
- uint32_t AWUM; /*!< Enable or disable the automatic wake-up mode.
- E# j+ o, o9 Z. s6 Y w* T2 t. O8 k - This parameter can be set to ENABLE or DISABLE */
% C' n( |' }6 d9 G, w% N - 0 m. S3 E- o+ K6 v& e5 D
- uint32_t NART; /*!< Enable or disable the non-automatic retransmission mode./ g0 ^3 I/ o% {6 y z; M1 E* e
- This parameter can be set to ENABLE or DISABLE */+ o) n U1 ]7 n0 T8 g, Z3 Z
8 \2 J& F# B: A8 k; C: w- uint32_t RFLM; /*!< Enable or disable the receive FIFO Locked mode.
7 m9 }8 r; F A/ E& U' c - This parameter can be set to ENABLE or DISABLE */
& O- W' |1 j$ K5 w& n. e; |
7 Q9 `/ \4 b- W- Y; v- uint32_t TXFP; /*!< Enable or disable the transmit FIFO priority.3 h: P1 q2 e/ [: M# { x( }# ?
- This parameter can be set to ENABLE or DISABLE */
9 m/ b) @' T' N) O, L, m - }CAN_InitTypeDef;
复制代码- // 过滤器设置
9 Z/ l" z5 Z- i# m1 e - typedef struct
1 z2 C9 y2 V+ y) X0 c- G - {( e4 @( A( O, N; b- R ~
- uint32_t FilterIdHigh; /*!< Specifies the filter identification number (MSBs for a 32-bit1 o6 w {& a! E" j* o" k, K* l
- configuration, first one for a 16-bit configuration).: y# g5 N; ?1 V& O( U+ D
- This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */ y0 t/ Q% _$ v; U; X
% K* U9 m" ~) E2 L& N- uint32_t FilterIdLow; /*!< Specifies the filter identification number (LSBs for a 32-bit
+ M* d, T3 p0 u/ U' [. x - configuration, second one for a 16-bit configuration).4 |! O$ ?5 y2 T) e! D& i( ^
- This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */' s/ g* q6 Z B0 P2 ^9 I
- 0 G2 B# L4 P% y$ g: X9 Q
- uint32_t FilterMaskIdHigh; /*!< Specifies the filter mask number or identification number,9 }6 q+ G# C1 h# y2 e' [$ [1 e" T( r8 D
- according to the mode (MSBs for a 32-bit configuration,
! F4 Y( @* u' G( n1 x+ E2 g& x% E - first one for a 16-bit configuration).
) ^7 ^( {2 Q% X - This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */( K9 A: \% s1 M* `/ k' Z
- 9 W' C" M8 r$ {- Y: G
- uint32_t FilterMaskIdLow; /*!< Specifies the filter mask number or identification number," [/ a3 J& V- V( U' h8 M1 F; E
- according to the mode (LSBs for a 32-bit configuration, ~1 `. N% z% G& G
- second one for a 16-bit configuration).
% y3 v* ^* b; a) D [1 y3 a - This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
: n' }# Q+ [* I; m4 D - 4 u2 f9 u& Z8 J0 S9 [
- uint32_t FilterFIFOAssignment; /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.: B+ F) b, e) X" n1 [$ x
- This parameter can be a value of @ref CAN_filter_FIFO */ |- B3 \" n, i# Q* X' G
- 3 y& e8 y9 ]1 |: `# ?6 Y6 o
- uint32_t FilterNumber; /*!< Specifies the filter which will be initialized.% D" ?+ D0 E* x* P* q
- This parameter must be a number between Min_Data = 0 and Max_Data = 27 */
! Q3 b, i% n& ?. {3 f6 c- [ _ - ' \+ S2 i0 N8 @# R/ z8 f; h
- uint32_t FilterMode; /*!< Specifies the filter mode to be initialized.
" [+ s. i: s5 i - This parameter can be a value of @ref CAN_filter_mode */7 d8 O) x: \; a `! V, t/ k) F% v. G: H
- 1 f7 U% g2 A) C# j5 \
- uint32_t FilterScale; /*!< Specifies the filter scale.
: L4 O1 R2 r$ M# \$ E) R" B - This parameter can be a value of @ref CAN_filter_scale */
" u5 c5 A4 e: [% l - ; z# u. r( {& R" [ }/ S5 D
- uint32_t FilterActivation; /*!< Enable or disable the filter.0 J6 B6 a) p' `% i. L7 A; H
- This parameter can be set to ENABLE or DISABLE. */& C# z* ^1 L9 a4 ^5 o
; k' q) C# K* S' z$ R5 z- uint32_t BankNumber; /*!< Select the start slave bank filter.* ]5 `& f- R* S( [) U2 S) V6 X8 G
- This parameter must be a number between Min_Data = 0 and Max_Data = 28 */- k( O! X, ~) I# q9 F
- 2 I' N# V4 a8 o
- }CAN_FilterConfTypeDef;
复制代码- // 模式 我们使用普通模式0 Q# x8 k3 Y) r- N. `; }7 k- f
- #define CAN_MODE_NORMAL ((uint32_t)0x00000000U) /*!< Normal mode */
; |% a# s% M: i2 | - #define CAN_MODE_LOOPBACK ((uint32_t)CAN_BTR_LBKM) /*!< Loopback mode */
6 n& D- b% i9 p4 R# _ - #define CAN_MODE_SILENT ((uint32_t)CAN_BTR_SILM) /*!< Silent mode */' h& k# o7 g% ~1 o: b" P; |
- #define CAN_MODE_SILENT_LOOPBACK ((uint32_t)(CAN_BTR_LBKM | CAN_BTR_SILM)) /*!< Loopback combined with silent mode */
复制代码- // 标准帧 扩展帧( b ~% n; l3 J, w
- #define CAN_ID_STD ((uint32_t)0x00000000U) /*!< Standard Id */
6 f! ]" e/ S: ?* d1 K" N: O9 r3 @ - #define CAN_ID_EXT ((uint32_t)0x00000004U) /*!< Extended Id */
复制代码- // 数据帧 远程帧
8 M$ E2 u, d1 G- v2 ~ - #define CAN_RTR_DATA ((uint32_t)0x00000000U) /*!< Data frame */
) [+ g: U2 d3 R& |) P - #define CAN_RTR_REMOTE ((uint32_t)0x00000002U) /*!< Remote frame */
复制代码- // CAN中断使能
0 B8 s9 p I6 E* m! c% [8 f - __HAL_CAN_ENABLE_IT(__HANDLE__, __INTERRUPT__)
复制代码- // 接收中断6 o- b! n, B' a$ A
- #define CAN_IT_FMP0 ((uint32_t)CAN_IER_FMPIE0) /*!< FIFO 0 message pending interrupt */
& [) r$ O+ r6 c1 E5 [ F9 { - #define CAN_IT_FF0 ((uint32_t)CAN_IER_FFIE0) /*!< FIFO 0 full interrupt */- u6 A8 a! z! \- B2 Z; P' X3 E. i
- #define CAN_IT_FOV0 ((uint32_t)CAN_IER_FOVIE0) /*!< FIFO 0 overrun interrupt */. Q: x& ]- p' K* x3 {( m: e
- #define CAN_IT_FMP1 ((uint32_t)CAN_IER_FMPIE1) /*!< FIFO 1 message pending interrupt */% R0 W- U U( \! S; Z5 t* Q' h
- #define CAN_IT_FF1 ((uint32_t)CAN_IER_FFIE1) /*!< FIFO 1 full interrupt */
7 X6 z8 K8 h7 J6 N! T0 z - #define CAN_IT_FOV1 ((uint32_t)CAN_IER_FOVIE1) /*!< FIFO 1 overrun interrupt */
复制代码 # |; r& } i9 M2 z
四、接口设计2 ?/ d9 ?# O4 A; _+ U
与串口类似,使用中断接收。先封装单路CAN需要的几个小接口,再顶一个列表,最后使用统一的接口扫描这个列表。
% Q, k- z8 J6 w! B
$ i* q7 |) s" @7 j% I1 X+ e1 F- typedef enum
/ L/ O& Q" N7 Q" H! K8 Q6 A- J - {5 `' U$ a; O& a5 R9 I
- CAN_CHANNEL_NONE,
1 q/ `! m' u+ ^' }% E - CAN_CHANNEL_1,
& y3 r) h/ j8 B' u" \; y3 N - CAN_CHANNEL_2,( ?( V- B! s- Y* X0 q: {& D! f& [
- CAN_CHANNEL_NUM5 Y/ ~$ M& |& q5 ^7 Q
- } can_channel_t;4 k7 W+ [( f* \! j7 J" }3 X
* q8 z; ?# u1 e- #define CAN1_CHANNEL CAN1
) L6 V8 a. @' w4 k - #define CAN1_PREEMPT_PRIO CAN1_RX_PRIORITY
/ N. D- `( f, J3 |# e- [ - #define CAN1_RX_IRQ CAN1_RX0_IRQn. Y- v/ @ A( B' N* F) Z0 B/ R: w
- #define CAN1_RX_IRQ_FUNC CAN1_RX0_IRQHandler
) f$ c9 T( I* D5 g( f% ^ ?0 A% b - #define CAN1_CLK_ENABLE() __HAL_RCC_CAN1_CLK_ENABLE(). q7 c! \$ J+ w0 H. ?( c
- #define CAN1_TX_PORT GPIOA
- v6 M4 g$ W- x) V - #define CAN1_TX_PIN GPIO_PIN_12& }; | H1 t2 O" V; [3 x$ V
- #define CAN1_TX_AF GPIO_AF9_CAN1# z! e) \* e$ v1 E+ t" x
- #define CAN1_TX_CONFIG() GPIOConfigExt(CAN1_TX_PORT, CAN1_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_TX_AF)
) d2 s8 S O& }5 Q+ z7 F3 E- n - #define CAN1_RX_PORT GPIOA |" Z6 s" u9 o; |
- #define CAN1_RX_PIN GPIO_PIN_11# L5 n: Z; `" N0 e L3 B/ {
- #define CAN1_RX_AF GPIO_AF9_CAN1
- ^: v+ O1 |4 Q4 {2 I* P - #define CAN1_RX_CONFIG() GPIOConfigExt(CAN1_RX_PORT, CAN1_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN1_RX_AF)
! `3 v* S4 l+ F$ n$ `4 z! o - 5 G6 c- [! {/ l. S: u
- #define CAN2_CHANNEL CAN2
" E( R/ ]" w3 q - #define CAN2_PREEMPT_PRIO CAN2_RX_PRIORITY
9 w1 g# H$ K) K$ F - #define CAN2_RX_IRQ CAN2_RX0_IRQn# V8 C- d* p, N- t
- #define CAN2_RX_IRQ_FUNC CAN2_RX0_IRQHandler$ a& L' e6 [" Q& n
- #define CAN2_CLK_ENABLE() __HAL_RCC_CAN2_CLK_ENABLE()
* C: g- M( k- p- i- c7 c2 z - #define CAN2_TX_PORT GPIOB0 m/ P9 J- U7 V
- #define CAN2_TX_PIN GPIO_PIN_6: [6 Y( B( h% k% j- u( |6 l6 X
- #define CAN2_TX_AF GPIO_AF9_CAN2, t1 S1 d" |- w y7 t7 y- [' h
- #define CAN2_TX_CONFIG() GPIOConfigExt(CAN2_TX_PORT, CAN2_TX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_TX_AF). M, g7 s/ S$ H% s9 [
- #define CAN2_RX_PORT GPIOB
( o' ?0 ?3 l+ t! V' _' y+ T - #define CAN2_RX_PIN GPIO_PIN_5
4 A F, d' b# s8 h D9 V6 ]9 D! c! g - #define CAN2_RX_AF GPIO_AF9_CAN25 P/ j( w8 S+ w6 H: N
- #define CAN2_RX_CONFIG() GPIOConfigExt(CAN2_RX_PORT, CAN2_RX_PIN, GPIO_MODE_AF_PP, GPIO_PULLUP, CAN2_RX_AF)
复制代码- <span style="background-color: rgb(255, 255, 255);">/</span>/ 抽象出一个CAN设备结构体
+ _8 @, A2 R$ S; |5 e, {0 U D8 H - typedef struct6 @0 g& ^2 P: _6 [6 a
- {! c6 U6 ^* a$ z, _
- CAN_HandleTypeDef handle; // CAN操作句柄
! E B I) y# _4 Q' j- E6 z' T
3 U' d) Z- A4 L1 s- CanTxMsgTypeDef tx; // CAN发送3 x* E9 B" l. H+ _# x
- ) z7 g% t6 a. n* w
- CanRxMsgTypeDef rx; // CAN接收
) t4 l/ ^/ o4 @7 u9 }, [# J6 @
! L/ }3 S" [1 A! C, `# }7 p- can_queue_t recv; // 接收队列 ?, e2 x. l6 D g4 {/ M
- " n- J2 l3 V6 ^
- } can_dev_t;
复制代码- // 将每路CAN封装成几个小函数9 {2 _3 M* q0 ~; ~# S' A' j5 r5 f
- static can_dev_t can1_dev, can2_dev;" N4 |6 x& w4 J, N% y4 P3 r( w* D
: g$ }$ T2 s6 f& Y: s( @$ i% ^- static void can1_var_init(void)
5 L# U7 P) `3 T& B; m: ` - {% @7 }! s- E( X* _* d: ^3 c4 W
- can1_dev.recv = can1_queue_recv;
9 D$ p) z- c- ~; `6 a
7 |! T2 g9 v t R" S" X' a* e! R- CanQueueInit(&can1_dev.recv);
' C) e' v! u& v8 ]) a* ~ - }
+ {' J6 x* Y1 B6 W9 Y - + f9 |% K; r1 `) C+ I
- static void can1_gpio_init(void)
: Z$ d5 l u+ U9 a) ^3 R - {, d! Y: w( F F2 j! x* I1 _/ a$ W+ }' f
- CAN1_TX_CONFIG();
. }% W, O! r2 I! V# [ - CAN1_RX_CONFIG();
4 s# l1 i8 ^3 Z: P - }3 p2 A, d. l. E' D6 s3 C
b7 K6 w7 N% F: |- // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp) Fpclk1 = 54M
, Y& Q4 ~# Z+ g( E - static void can1_mode_init(void)
- _# ?: L9 i: U) ?+ Q+ T - {
- B4 |6 }' |# J1 f - CAN1_CLK_ENABLE();
+ N3 B9 P1 F; a5 B) }
) L& B- ]0 f% z2 a% x6 _- can1_dev.handle.Instance = CAN1_CHANNEL;
: E% j, z* @, \- n, [% t$ @ - can1_dev.handle.pTxMsg = &can1_dev.tx;9 f7 K( k* X$ e6 t
- can1_dev.handle.pRxMsg = &can1_dev.rx;
) K5 Y/ B; v/ c" U& S' G - can1_dev.handle.Init.Prescaler = 6;
5 k- }) p! B' ?; C - can1_dev.handle.Init.Mode = CAN_MODE_NORMAL;. R/ R5 f1 @. o3 i2 G1 e! Y% v2 ?2 R
- can1_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
$ e2 w! F. R, N9 `' S - can1_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
, s! N8 B3 K5 v" N' n& v - can1_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ) G. \- n3 R, V. B/ F! ]$ Z1 H
- can1_dev.handle.Init.TTCM = DISABLE; // 非时间触发通信模式
& J" l1 T2 e6 S - can1_dev.handle.Init.ABOM = ENABLE; // 软件自动离线管理
* v0 ^, s+ O# @+ Z - can1_dev.handle.Init.AWUM = DISABLE; // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)9 j0 D9 q3 d- h& r
- can1_dev.handle.Init.NART = ENABLE; // 禁止报文自动传送+ K" I# I; j; P v
- can1_dev.handle.Init.RFLM = DISABLE; // 报文不锁定,新的覆盖旧的4 K/ P: o' d' S/ @1 K
- can1_dev.handle.Init.TXFP = DISABLE; // 优先级由报文标识符决定3 G; v: |. ^9 f* s1 L
- HAL_CAN_Init(&can1_dev.handle);
5 Z# M, `: ?1 C, R9 c# { - }
3 x" N8 W a* C5 j! c/ X - * d* H# w( n/ Z/ y8 U
- static void can1_filter_init(void)# G% ]! \; K; @ l& x
- {( U1 q" G4 B3 b5 ]
- CAN_FilterConfTypeDef filter;
$ T. F6 A7 w- o1 Q
2 i! x" p, o) t- filter.FilterNumber = 0; // 过滤器0
! e9 Y7 D& Q* S& I6 t - filter.FilterMode = CAN_FILTERMODE_IDMASK;/ i: X% O3 K- J+ }" ~. f
- filter.FilterScale = CAN_FILTERSCALE_32BIT;7 s, A; p% w; r
2 R( }6 ^* Q1 Q7 G6 E6 C- filter.FilterIdHigh = 0;
& E) b, O/ I2 e - filter.FilterIdLow = 0;" j0 u, l0 z- Q3 M* x6 r v( P, n
- filter.FilterMaskIdHigh = 0;
/ h- U( N& a' L, A" t* P+ }) ` - filter.FilterMaskIdLow = 0;$ p0 L2 x: Z0 v% H9 v: s7 D; K
- z' }9 f1 G6 r% Q/ b! z* F
- filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0: b( ~2 {. }( g3 ]. [1 K7 s6 Y+ e* b
- filter.FilterActivation = ENABLE; //激活滤波器0
* b( Z0 _( J: O V9 P) ]$ }# o9 G5 M - //filter.BankNumber=14;# p3 |8 W' k2 k C
! i' x- V @+ h- ]- HAL_CAN_ConfigFilter(&can1_dev.handle, &filter);. u4 r4 S' b0 U
- }2 q$ F5 ]8 V' L% w; @( G$ a& B
- % X3 X; z) c' _3 |' w/ x5 n
- static void can1_nvic_init(void)) Y( C' g' _ v
- {
7 p8 Z: c% }8 f) \4 X9 Z - __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许.
8 d' z! ~$ [8 |7 D) _ - HAL_NVIC_SetPriority(CAN1_RX_IRQ, CAN1_RX_PRIORITY, 0);
5 M. t' ^' v5 I# T2 ~5 f) ? - HAL_NVIC_EnableIRQ(CAN1_RX_IRQ);! L! r4 |- r+ o# m0 O/ z' H! z' |
- }
4 Y( ]9 |2 G" h* o( } - 6 T! }( D4 S, S" C( o8 ~; s
" j% N7 m# M7 ?7 m- W: q5 O
2 \) R+ U9 V" Q) I- static void can2_var_init(void)' ]# x0 B* L/ d- s& j# A3 c2 ]
- {2 t: n5 T J' j; ~
- can2_dev.recv = can2_queue_recv;4 E" ?. Z# [4 N0 \$ B
- 0 d7 c' _7 B) g% J3 K3 a
- CanQueueInit(&can2_dev.recv);
$ R( x' b; P, Q; y7 ~ - }) Q+ J$ R; j% b
L- S( H/ p6 [. _/ {) A- static void can2_gpio_init(void)
* e& ^8 f9 {9 L0 `: ~/ d - {
# f1 I0 ] r$ B; n, S - CAN2_TX_CONFIG();
( P$ I2 u# e+ p - CAN2_RX_CONFIG();
5 G* F+ D* [' d P) r0 P- A0 c - }
) S$ V. K( e$ `; q! D) n0 E - P& r: b2 D* m
- // 波特率 = Fpclk1 / ((ts1+ts2+3) * brp) Fpclk1 = 54M
1 R y+ O/ R6 a3 D* S - static void can2_mode_init(void)9 |2 I Z/ k1 Q# ^4 N2 T: {
- {
5 ~. S/ R, L2 n: i) n& |7 c - CAN2_CLK_ENABLE();: J* l; V7 j& E3 x3 Q* ]
* D9 p& ~6 j0 e+ _( p* [1 h* @# `$ {6 b- can2_dev.handle.Instance = CAN2_CHANNEL;
! J- M' q1 {; s+ g; c - can2_dev.handle.Init.Prescaler = 6;$ M Y3 A0 j4 g3 ?; x
- can2_dev.handle.Init.Mode = CAN_MODE_LOOPBACK;' I% m2 f! y" x9 D
- can2_dev.handle.Init.SJW = CAN_SJW_1TQ; // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
, M& w2 E" Q* }: u- f( S0 w - can2_dev.handle.Init.BS1 = CAN_BS1_11TQ;// tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
. r" @/ | B4 C4 P; D. x4 q - can2_dev.handle.Init.BS2 = CAN_BS2_6TQ; // tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ, o4 H6 O. X. N) u
- can2_dev.handle.Init.TTCM = DISABLE; // 非时间触发通信模式
: A3 N! J9 @1 W3 d6 M - can2_dev.handle.Init.ABOM = ENABLE; // 软件自动离线管理
, g ?; ?4 h" c5 u4 _ - can2_dev.handle.Init.AWUM = DISABLE; // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
6 g+ }4 a4 P' M( v - can2_dev.handle.Init.NART = ENABLE; // 禁止报文自动传送
/ z0 P* C Q# ` - can2_dev.handle.Init.RFLM = DISABLE; // 报文不锁定,新的覆盖旧的1 s! q0 r8 W+ f9 M0 n! _& }
- can2_dev.handle.Init.TXFP = DISABLE; // 优先级由报文标识符决定$ E' f8 A# c& U
- HAL_CAN_Init(&can2_dev.handle);0 B! S- p* w; ~! N! s5 |+ i. ?, u, L
- }. e _6 |, b. A& K! q
- & X& j. }' l* Z0 C- ?: W
- static void can2_filter_init(void)
% f+ \0 [5 [5 S9 S& y6 F% N - {, E+ T% F7 n3 q; }/ i/ X
- CAN_FilterConfTypeDef CAN_FilterInitStructure;
) L7 x, `0 `+ `$ I' a - ) H, v' R6 V* S
- CAN_FilterInitStructure.FilterNumber = 14;
% J3 R8 _& u z; y! [ - CAN_FilterInitStructure.FilterMode = CAN_FILTERMODE_IDMASK;* O" Q& l) m$ g# I
- CAN_FilterInitStructure.FilterScale = CAN_FILTERSCALE_32BIT;
' v# R* [+ S, k+ R4 T
9 k& m' Y V Z( r: i6 d; f- x- CAN_FilterInitStructure.FilterIdHigh = 0;7 W7 J8 o. ?; Q+ I9 |* d
- CAN_FilterInitStructure.FilterIdLow = 0;
$ X( m4 E6 h* o) k" |: v - CAN_FilterInitStructure.FilterMaskIdHigh = 0;" D5 B' |% l8 j3 i% H# \, Q
- CAN_FilterInitStructure.FilterMaskIdLow = 0;& Z; Y+ Y' `' i9 o5 a
- 5 }6 z' K, C1 `8 B$ X
- CAN_FilterInitStructure.FilterFIFOAssignment = CAN_FILTER_FIFO0; // 过滤器0关联到FIFO0' i& ?3 @' u. I9 @; g0 b, a
- CAN_FilterInitStructure.FilterActivation = ENABLE; //激活滤波器0
/ d) d& s5 r3 ?3 V. z0 @ - //CAN_FilterInitStructure.BankNumber=14; q O1 ~' ^2 J' T% Q2 k
/ }8 q1 j% _9 A2 b1 I" E- HAL_CAN_ConfigFilter(&can2_dev.handle, &CAN_FilterInitStructure);6 ~( j4 j$ W1 ^4 [* k% c+ g
- }% o- R. u% v% n* f
5 z# W% R9 x8 g( X- static void can2_nvic_init(void)
+ f# B0 t5 I, u6 }* ]9 { - {, B+ W0 w7 Q" e( I7 p
- __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0); //FIFO0消息挂号中断允许1
% X% K% v: s6 K3 y* B6 E! ~ - HAL_NVIC_SetPriority(CAN2_RX_IRQ, CAN2_RX_PRIORITY, 0);
; H! @: T% ]0 a - HAL_NVIC_EnableIRQ(CAN2_RX_IRQ);: ?/ `9 N" b2 m5 D5 B
- }
复制代码- // 每路CAN都有的几个操作,使用列表包含,然后统一扫描处理
# f$ e c5 ?% O. j - typedef struct
) h7 O; `. B8 i7 W/ H$ K* l - {
G) {# v6 k G' S7 i4 v3 `( W - uint8_t channel;) u* K2 D8 M! G/ I: _' W
- can_dev_t *dev;
- \+ Z) t: R& Q7 ~# V3 X8 W# J - void (* var_init_cb)(void);
$ `5 z% l! \) R5 Z4 [2 k) k - void (* gpio_init_cb)(void);
# @0 @. c. Z) Z1 r5 `' |! e - void (* mode_init_cb)(void);
, C. q) L: Y- g& H/ J; p - void (* filter_init_cb)(void);6 W! Y' E% _) U7 L& O w/ g7 e
- void (* nvic_init_cb)(void);( T5 M$ g! `9 s' h% o: W
- } can_config_t;% z- x& A9 n7 w- p8 ^ q
- $ O' ] X" y; m( Q" X
- static const can_config_t can_configs[] =
4 T0 F5 h. C$ K# |. S - {( ?) O+ ]8 Y8 j. Y0 p" _6 `
- {CAN_CHANNEL_1, &can1_dev, can1_var_init, can1_gpio_init, can1_mode_init, can1_filter_init, can1_nvic_init},( {' c1 Y$ ?) l( c% l- S& s
- {CAN_CHANNEL_2, &can2_dev, can2_var_init, can2_gpio_init, can2_mode_init, can2_filter_init, can2_nvic_init},/ L d2 i1 d, l2 {7 F/ g" \
- };# g- U& h8 _) |, |
; _( j( ]) \6 r; L0 C- static can_dev_t *can_dev_get(uint8_t channel)
3 u: [* E6 q d( X* O6 P0 e9 J8 V4 y - { u) Z4 ?0 b) `9 A" k
- uint8_t i;
; O& _0 o2 Y9 g8 S+ v
$ t( T# T1 s: z6 ~- h- for(i = 0; i < ARRAY_SIZE(can_configs); ++i)3 B. [' m9 p! j
- {$ t7 v, f" b+ p! k" p
- if(channel == can_configs<i>.channel)
2 A$ A4 g l: ? V3 R! X - {4 `* Z) r1 c( W/ j! r. Z$ Q# Q
- return can_configs<i>.dev;" \, m' B9 @. w+ `
- }. x# Z2 G: {! l0 A! p: K
- }
# ], ?# H @$ H) [8 q
. Q. N* N& L( @2 _ |/ D- return 0;
) l/ Z* f; g* A _! q e7 [) q8 G - }7 [: S0 A6 Q. m4 p
- ( m1 ]" b, q/ f5 \
- static void can_var_init(uint8_t channel)
2 m1 K8 X3 X3 j# G* m3 w - {
) v( d- S; G+ @5 Q+ W - uint8_t i;
' I/ L L U2 x% V4 F3 M: b0 t% @
+ ~5 _4 ^8 |) k0 X& A; s: w9 `- for(i = 0; i < ARRAY_SIZE(can_configs); ++i)
( L; E. B! V5 y" K7 t$ z7 i - {4 J F# L' B2 h) b: y
- if(channel == can_configs<i>.channel)
G- {* K9 V' |; `# ^. X - {
; z9 J- e/ E+ {/ Y; Z - can_configs<i>.var_init_cb();
' X' v, B, _! N& X - return;% R& B# U h2 } i( L6 {
- }; [' h7 W0 O- [% n" S% x
- }
7 u/ E/ M. P! z5 U) q - }0 A! c! R1 L0 R4 V9 f
1 ? d& |' k0 x! p, I- static void can_gpio_init(uint8_t channel); ]8 L' r0 b9 s' k5 U$ z' {* _, p
- {& C' W! k6 Q" l( M2 ~; p! P
- uint8_t i;
! v! Z6 l, h% U! |5 r
1 N; x7 C# G# J# t V! R- for(i = 0; i < ARRAY_SIZE(can_configs); ++i)' H! G' H( A) \. l
- {1 ^5 n* m+ O% C4 z
- if(channel == can_configs<i>.channel)
# R. s: C; K- R0 D, N; y5 O - {
8 V% o+ R k3 z5 o1 s - can_configs<i>.gpio_init_cb();
0 V7 m2 L ]4 u - return;# V) D- y* C2 V# ^0 c, t4 q
- }
. v" g, c8 E, h1 F, ^ - }7 A* i* B0 O: x* k# T
- }
* ?4 L- y* T' C, I L% E
2 M& S# R0 o& M" |- static void can_mode_init(uint8_t channel)1 z# T8 r4 ?0 t9 Z
- {, c# N1 ]1 U1 e: Z5 J% ]4 d- F7 B
- uint8_t i;
9 M) I" T- k, g3 B
. H/ q/ H2 o& w. \- for(i = 0; i < ARRAY_SIZE(can_configs); ++i)1 N. O1 s: F; e! q0 Y% N
- {# g( }- ]* V4 i& S
- if(channel == can_configs<i>.channel)" L+ G3 J: R! i3 Q9 E3 \+ e
- {
# c* a0 O! K+ ] - can_configs<i>.mode_init_cb();2 o( F9 S9 N% {2 B
- return;/ e+ ^) S# \! k5 b3 G1 R# W
- }$ ~3 a! _9 ~0 W
- }
5 G# x( n9 J. q - }
- M+ w, v0 W! ^9 \6 k% _
. s6 Z. c% \( R7 l) N7 O- static void can_filter_init(uint8_t channel)
) e0 f% D' G2 M2 {& w% n# F w: @! Q - {. }0 Y# C; i/ O" u/ }# r
- uint8_t i;6 e) w3 k0 b9 {8 o, }7 C# {
- & } R) b7 o& @* e4 p
- for(i = 0; i < ARRAY_SIZE(can_configs); ++i)' v% w# k" | O& z: o7 e, m) y
- {4 @7 |( w' A. `3 w& [9 A6 W; z- n
- if(channel == can_configs<i>.channel). m! ?) e ~! s
- {: Z& Y7 [8 b! D
- can_configs<i>.filter_init_cb();
) \; `. V5 I& x; l r - return;# Z* E! X4 j3 L
- }
& q: a3 {9 g% [8 O `2 Y( T - }' r$ _. g( ]. n2 g! k. J
- }
8 y4 |- u5 Y3 @
4 H8 M' }. g. X8 L2 h- static void can_nvic_init(uint8_t channel)! z0 B. ^. A1 A$ h7 ^
- {
+ j+ M, K, N" @" d1 R' r2 N - uint8_t i;) M( |% j8 E- y5 F
- 6 J3 \5 M, ~1 e
- for(i = 0; i < ARRAY_SIZE(can_configs); ++i)) z6 a6 u" @' Y5 w
- {
% m/ d3 n/ w: Q! N - if(channel == can_configs<i>.channel)* m, S" X& g& N; J' X3 L* ~0 P, q
- {
. L4 {- F1 E$ n) D, v7 V - can_configs<i>.nvic_init_cb();
# F; @0 ]0 o7 {" Z3 k" Y) p! r - return;) ]' X" o/ @+ G
- }$ g' J; H# ^: J' M! m+ O/ f
- }
3 E6 c6 @2 g0 e$ u - }</i></i></i></i></i></i></i></i></i></i></i></i>
复制代码- // 对外的接口 初始化 发送和接收
! }" y7 M X9 Z* x) {7 R - void CanInit(uint8_t channel)4 b4 X% l. e' _; j3 B; Y
- {
- V. |6 o9 [5 H6 Q - can_var_init(channel);
1 \3 T& p# u3 W# R* o0 j1 s7 A - can_gpio_init(channel);! a7 ?$ }8 m. S7 ]9 F
- can_mode_init(channel);4 {2 B) I3 o3 ]
- can_filter_init(channel);
0 |, ^# I: `9 k, T1 @, V& |) p - can_nvic_init(channel);0 D9 q0 F, N" g
- }. [4 h8 d; o5 @6 B$ z" b" [+ a
+ c& w, h8 p0 `* C8 u* N' j- void CanSend(uint8_t channel, can_frame_t *frame)
1 ?1 a# m8 z z/ P2 k9 e - {
1 E/ x* x1 H* r4 U2 s( N - can_dev_t *dev = can_dev_get(channel);! d( G4 m( [/ q
- X. m/ R0 W3 E+ _( x/ H1 i- _% K- if(dev == 0)
+ f i0 O) M0 z4 I L; Y' h8 u - {
4 i/ Z* q+ F) G1 Y - return;( c' M- ?! ]" x& d, ?" e$ @
- }! ]. p4 M( ]3 v+ P. N6 |( M
1 |+ T9 s. j2 D# I- n( @" T, _# A- dev->handle.pTxMsg->StdId = frame->StdId;% `1 t( V/ T1 R+ e: N2 W9 [, \
- dev->handle.pTxMsg->IDE = frame->IDE;) z4 U$ ~: D) p" x3 }
- dev->handle.pTxMsg->RTR = frame->RTR;
* T2 i+ p5 M1 C. c; h - dev->handle.pTxMsg->DLC = frame->DLC;8 m' I7 W- G' q! U
- memcpy(dev->handle.pTxMsg->Data, frame->Data, frame->DLC);
9 u9 y, E: B' d
5 s! u/ f+ u" U, t. g' Y( g& M- HAL_CAN_Transmit(&dev->handle, 10);$ E0 A w9 l$ `$ q7 D( f/ H/ I
- }
6 Z* ?% D1 I1 G. G - & z0 O6 w) L4 \- i f& F/ D
- uint8_t CanRecv(uint8_t channel, can_frame_t *frame)
3 f3 A+ W8 \1 V, R - {& O- m- c" m( X3 c
- can_dev_t *dev = can_dev_get(channel);
) b3 N0 m7 ]! }' M5 R0 x
4 h- @$ w7 H9 X% t- if(dev == 0), Y! H# r! d0 H6 K) g/ v
- {" g" Z8 i. u1 P$ w0 L [, E
- return 0;4 k e$ Q1 F/ Q! Q( \( w# M) B
- }
( U; a9 |. q# I: T" H8 E
( Y N( U: @; S: y* S+ L! V$ a- return CanQueueRead(&can1_dev.recv, frame);
. r$ ~3 f) _$ w/ r% U! I - }
复制代码- // CAN中断
* h7 i$ O2 M2 t/ i& ^4 _5 O, C - void CAN1_RX_IRQ_FUNC(void)
8 j* [/ r" h8 U3 w* j+ ^! b - {( \0 M T! Y5 W \+ J/ _9 X
- HAL_CAN_IRQHandler(&can1_dev.handle);
1 D* W- e) `# e# }; F, P - }& z: @" @/ a5 f7 P1 T- d d
- 6 A$ E3 d+ e' G( W4 W* y
- void CAN2_RX_IRQ_FUNC(void)2 G& u7 B0 Q% y: f+ I
- {' g' @" T: R( d) Z
- HAL_CAN_IRQHandler(&can2_dev.handle);
( J' Z: |0 R* h% Y7 C# t - }
! Y! g) ~; ^7 e: g: O4 a
: u" v( m/ K. `- ?& o) @5 I- q- void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan)! K6 }3 D" \. s J3 x3 V
- {0 L+ L# ]5 k* }& s1 g3 @( H' B2 W
- if(hcan == (&can1_dev.handle))
" r2 [# a3 c5 D& z/ Z; }) c+ V8 ] - {
0 Y8 k* \$ S$ [5 Q' O! L0 J - //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开
# b6 Q$ @; u$ N* U& P9 n7 f: p - __HAL_CAN_ENABLE_IT(&can1_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断
( Y, u& k- z; m - CanQueueWrite(&can1_dev.recv, can1_dev.handle.pRxMsg);
, _, H/ b. M2 n1 w - }
5 K3 l0 `; B u8 X" Z8 U - else if(hcan == (&can2_dev.handle))! U* Y/ T$ v. m+ a5 ~9 _. G
- {
@7 h2 g8 h( R* D& q - //CAN_Receive_IT()函数会关闭FIFO0消息挂号中断,因此我们需要重新打开
2 Z: \/ K) v' x- M0 b1 z3 X. m - __HAL_CAN_ENABLE_IT(&can2_dev.handle, CAN_IT_FMP0);//重新开启FIF00消息挂号中断; B3 S& T+ c% T! `, I
- CanQueueWrite(&can2_dev.recv, can2_dev.handle.pRxMsg);
2 F) K2 p1 f. i. e9 ^ v. u7 P, \' ~$ b - }8 @/ d) J* @. S' y# B- O
- }
复制代码
" a: o1 |6 ?+ a3 A2 @ 之所以使用列表的形式,是为了方便增加和删除CAN通道和使对外的接口更统一,不会出现CAN1Init() CAN2Init(),个人习惯问题。
* R2 m( O, z- J% U) a% [7 O+ v& y" Q1 F e y- N
' F- n8 H! m9 j8 l2 h3 K3 ~) x7 M
# e+ J: E# e9 R) s H; A# q- o U* ?( [, D
|