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