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