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