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