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