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