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