一、遇到的问题 1、发送单包数据,我想都非常简答,例子一大堆包括,demo。但是发送多包数据怎么处理?* A, c) R* }! M" p$ k9 s7 ~% I8 q
2、发送多包数据,网上基本上就两种说发* Y1 X4 V% E5 v' ~
*两个数据之间加延时
t+ H$ O. W% }4 V. E*查询邮箱是否满了& Q- {: a& }8 l2 X. q4 O
HAL_CAN_GetTxMailboxesFreeLevel()) V$ v7 P; }9 y
对比上面两种方法,为了效率我们选择第二种
$ S& E$ S. E5 |% W }
; E+ c. m8 Y0 E1 F6 ?2 n0 Z7 l9 n2 ~
二、配置与代码
/ h, e M" P% [0 O- P' V' ~
! e3 n# B& G/ `直接上cubemx配置
; a7 Z/ S- h: n' ?: ^( T
0 g& d- S/ g) f4 ?! s8 W3 c& [, z
/ C6 l3 }) R1 I# h9 H. D- \
2 t2 ?6 O" }+ c5 c$ R" E- I
; e) ?5 w6 m- c' n9 l7 P# D" V6 @8 B
直接生成后,cubemx没有设置过滤器,需要自己添加,结合网上各资料总结代码如下 C5 ~* D! d, V
- int main(void)
: x- \* {: U9 J6 j3 U# U - {
% b. h8 D$ t" W - /* USER CODE BEGIN 1 */
( H0 J2 | p5 B8 Y6 \5 B
, h% \; P. L7 b* n- /* USER CODE END 1 */& y# K4 C- j( C; E R* L( q! V3 ^/ V
- + D* k4 K- `" T- b
- /* MCU Configuration--------------------------------------------------------*/
9 j3 K, V2 U; z' i
% j0 g. p2 z. `/ X- V- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */$ z+ {; O8 ~" ?4 p% M7 X
- HAL_Init();; B5 P! {& c0 B# Q( j& }$ K$ x
- T) _. N q* [7 N- c* y; R
- /* USER CODE BEGIN Init */* J6 P7 D" G {+ x, G$ z& r
0 g0 n: F) `& n% ^! r% C- /* USER CODE END Init */+ z5 W$ ]9 w+ Y8 W4 C
* Q! A& b/ `- u- /* Configure the system clock */
! P( F) N8 c; `5 M - SystemClock_Config();
. H+ W' d; v% |# a: z - & n( @# D( E" A, J6 ~& l; n
- /* USER CODE BEGIN SysInit */
" p, o) Z; H6 f# T% u( E - ( }- h. P8 h- p3 T' o( S, n6 G7 S
- /* USER CODE END SysInit */8 t- I `" v) u/ `
) j$ V! z& ~- h5 L) \; q- /* Initialize all configured peripherals */" D7 H, B( b# v8 y1 c( J
- MX_GPIO_Init();
3 J _3 \; r! j; O8 X; V - MX_CAN1_Init();
7 {/ o* n! i, L+ @6 s: L. N1 o% S - /* USER CODE BEGIN 2 *// l4 l$ n' g# N, a7 L2 Q) W1 k
- CAN_Init();! T. O; {5 U) @# ~6 E8 G( G& k
- /* USER CODE END 2 */
: O% I$ T8 J* Y% a, u& N - ' D( d4 a4 V( b- \2 P/ X
- /* Infinite loop */2 e( K: o- y" g6 P8 q7 V. `. |6 [! K
- /* USER CODE BEGIN WHILE */1 `) a& K, `6 M2 m* d
- while (1)
4 k1 t, _4 o* [6 b& W - {/ Q9 x; a7 I; c# l
- /* USER CODE END WHILE */
/ ~' Q. q9 j% Z. R# y k0 m - * i4 u: R# I6 T9 }$ H) l+ a( B
- /* USER CODE BEGIN 3 */
; m. W7 k0 y y0 M5 h1 Y6 l- w% @ - uint8_t TxData[100] ;1 N8 Q9 R6 G J$ M! w# ?% f% v
- for(uint8_t i=0;i<100;i++)' S" m+ D8 T+ W" U; O; v# G
- TxData[i]=i;; v; [3 C+ ~- f* y. L
- CAN_SendStdMsg(&hcan1,TxData,sizeof(TxData));
0 P& \1 o2 }- _1 ^2 u - HAL_Delay(100);
6 r3 x) q5 ^; F2 Q. S: W d: J - }! }4 [3 z# u! Q& K: G2 Q8 s. B
- /* USER CODE END 3 */# g' ] z% H8 ^: T* {
- }
复制代码
# G9 s$ G( W( c3 u% P* A# qbsp_can.c ) u# r/ ~: B3 X. Z/ p
- #include "bsp_can.h"
8 S1 t! ^. Q( }! M
! I7 V# D7 o9 P2 U" U
5 ~2 q# y& S# ^# K2 P2 R/ |6 j6 m- /// CAN过滤器寄存器位宽类型定义
) G4 Y2 J2 S% V, f( P, a! ^ - typedef union
Y0 w6 U3 u; u: A# w - {
- }: E- E, X/ g - __IO uint32_t value;
% Q, p& G. S) \. W; }1 c0 C - struct6 \# k( o0 p v1 a- Q0 I
- {# i# v$ g: m5 N2 n ^) J
- uint8_t REV : 1; ///< [0] :未使用! A% _ r' i1 V7 g- V& ~; A5 J/ p9 Q
- uint8_t RTR : 1; ///< [1] : RTR(数据帧或远程帧标志位)
$ _8 B! j# [8 |9 T+ C E" O - uint8_t IDE : 1; ///< [2] : IDE(标准帧或扩展帧标志位), U- X, M! t @. X& \* x
- uint32_t EXID : 18; ///< [21:3] : 存放扩展帧ID6 w+ ~# B) f! b3 A2 H+ t
- uint16_t STID : 11; ///< [31:22]: 存放标准帧ID$ c3 C( s4 d& S' ]
- } Sub;8 F5 m- V8 ~ \/ k$ `
- } CAN_FilterRegTypeDef;4 [) K6 ]4 D5 k4 R9 X
) `, h4 F9 V9 b- . I+ m5 j" @& N3 _3 d1 }. b2 p2 ~( U
- #define CAN_BASE_ID 0 ///< CAN标准ID,最大11位,也就是0x7FF' B/ T% Q3 ~/ i8 f& K) R6 n1 h5 _# x
+ r" Q% e( f+ E7 a' }7 E; b- #define CAN_FILTER_MODE_MASK_ENABLE 1 ///< CAN过滤器模式选择:=0:列表模式 =1:屏蔽模式
4 O+ ]% y6 w; b5 B4 U' Q/ y7 D) l
# |& c, t9 E* j- #define CAN_ID_TYPE_STD_ENABLE 1 ///< CAN过滤ID类型选择:=1:标准ID,=0:扩展ID
# X% ], N' l$ V, P - ; v, h/ f. `3 J9 G. p& p
- void CAN_Filter_Config(void)
2 S$ |: w2 }/ z& Y, ? H - {1 q* A* E$ t/ j+ z
- CAN_FilterTypeDef sFilterConfig;* y- ^# R7 R% E2 C5 K
- CAN_FilterRegTypeDef IDH = {0};' E+ @+ a# F, ~ d+ y/ b* r2 m# B$ _
- CAN_FilterRegTypeDef IDL = {0};: G. V; M( y4 r9 s1 M6 d( \* O
- ' u, v P1 H6 Z3 C: W, F+ ]
- #if CAN_ID_TYPE_STD_ENABLE, Q- T% S" h! o+ v# v. I/ }
- IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF; // 标准ID高16位( k- k7 O5 a( k, G w% L: v! j i
- IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF); // 标准ID低16位
8 m' P, C' a& [- Y2 s - #else4 H Y: y+ ^3 T* d& x8 \
- IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF; // 扩展ID高16位
\1 o8 Q7 _5 J6 a% a: G6 C0 g - IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF); // 扩展ID低16位3 W# t, `* ^$ ?; u6 M5 q% ~ `
- IDL.Sub.IDE = 1; // 扩展帧标志位置位
# ~; ^8 l% \6 N `- [, f+ T$ D6 g1 C - #endif3 M+ \. G. B2 C0 b$ E
- sFilterConfig.FilterBank = 0; // 设置过滤器组编号
9 Z. W4 ^5 t/ X3 w* V! ~' ], H( } - #if CAN_FILTER_MODE_MASK_ENABLE% H4 Q4 Z* B& [; s# ?
- sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 屏蔽位模式; E+ d. }4 e F8 d/ A
- #else% l3 v" T# \9 o6 J0 _' b
- sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 列表模式
3 j' H. H6 O/ W7 X( S! a1 z/ v; t; Y - #endif7 k+ @4 @8 H) h/ b' d4 O8 G
- sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位宽 x6 T+ }- s4 T r+ S
- sFilterConfig.FilterIdHigh = IDH.value; // 标识符寄存器一ID高十六位,放入扩展帧位
5 A- m' ], F" `1 O: i - sFilterConfig.FilterIdLow = IDL.value; // 标识符寄存器一ID低十六位,放入扩展帧位* N' G6 K+ p( E3 A
- sFilterConfig.FilterMaskIdHigh = IDH.value; // 标识符寄存器二ID高十六位,放入扩展帧位" j, ]$ E" S# \9 K
- sFilterConfig.FilterMaskIdLow = IDL.value; // 标识符寄存器二ID低十六位,放入扩展帧位& u. f! Z$ c/ ?' P# e
- sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 过滤器组关联到FIFO0' f+ n7 U- d1 n! z$ q. P
- sFilterConfig.FilterActivation = ENABLE; // 激活过滤器
+ ^7 W" @# x* F! F - sFilterConfig.SlaveStartFilterBank = 14; // 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效, C% w$ _0 W3 C- a* ?
- if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
- t6 U- l7 z1 G - {
; ?- i" b2 N5 V6 u8 N - Error_Handler();$ h6 [$ K: K' ]7 G8 n, o$ N: X6 l; ~
- }
' `; s- X( Y: t, c { - }$ }; n& S- M' G2 B4 b
6 O" _" j5 q1 F' f* Z9 I; l- 0 X8 z" [; z- Q9 n9 y1 a( Q) |- s/ {
* [7 w) k) e4 r5 A) i0 ?- void CAN_Init(void)
$ i, n; s( I" M- {$ Y - {
. O3 n4 K0 j! Z) W: o1 \ - CAN_Filter_Config();) @6 e2 f. F1 |, O1 b" W
- HAL_CAN_Start(&hcan1);: J* {' a5 h; `1 Z* u2 _0 w
- HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING); // 使能CAN接收中断8 \. n. S F6 @, d. x6 ?
- }8 m/ [6 K7 e5 U0 ?1 h8 L
5 f0 Z' B1 w' o# R6 p$ c- void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
/ ]. D& }- H8 O" N1 X! \ - {/ I8 m( [* a) V0 b# k. y0 {" M# |
- static CAN_RxPacketTypeDef packet;
8 Q: _- m* d3 c4 J - 5 ]" `7 a+ D! i, g/ S
- // CAN数据接收/ P& W! ]( w/ g9 R% g$ p4 N
- if (canHandle->Instance == hcan1.Instance)3 a3 h) V2 o; Q& a" X; S T4 i
- {
( E6 F9 g7 V4 ~/ b5 k$ T8 A% c - if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &packet.hdr, packet.payload) == HAL_OK) // 获得接收到的数据头和数据
) H" d9 k, Z+ T1 \2 Y - {4 i: z% X [9 s, l0 V, v/ b) s- @- q
- // printf("\r\n\r\n\r\n################### CAN RECV ###################\r\n");3 g7 E q* p: Z% O8 E2 `
- // printf("STID:0x%X\r\n",packet.hdr.StdId);
2 @5 w& t( {2 N- W' m$ |9 E1 Q - // printf("EXID:0x%X\r\n",packet.hdr.ExtId);
" b/ x9 q$ Q5 K: n& d# w - // printf("DLC :%d\r\n", packet.hdr.DLC);
6 s" K% f/ Z2 R8 V. Y - // printf("DATA:");
9 _, f" e% H0 G - // for(int i = 0; i < packet.hdr.DLC; i++)
' v, W/ Q) E& l; |1 p( @ - // {
* }8 M0 X8 c$ g* u. x - // printf("0x%02X ", packet.payload[i]);1 X! m- E" s7 B& g
- // }* v2 _+ E4 ~6 a/ \6 Q7 R' f2 I
- HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING); // 再次使能FIFO0接收中断5 ?5 ]4 a1 a+ @/ j
- }
# @3 D% n9 {* P6 v- M3 r# g+ o - }0 H* B3 u2 O' }4 H
- }
( @7 F/ r4 @/ X1 Y! B2 I
* O& Z' b7 S5 e: _* H, B- , Y/ l; g, l- s9 ~# Q8 a }" v
- uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)
+ X6 Y9 J5 q+ Y8 i% e% K( ^- K - {. } P3 ^. ], d- {- F/ ~
- if(HAL_CAN_AddTxMessage(&hcan1, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
6 |0 l1 x; q- M0 Z. R$ c8 V0 k - return 1;! n/ q3 b: o9 z
- return 0;
7 a( {) _1 |; ~, c/ a) a - }- I% v1 `& ?6 N. `& @8 j7 b
( m* O$ X0 E7 L5 `& R
0 |+ `8 H4 m1 O% _/ M. p( `. J- CAN_TxHeaderTypeDef TxMeg;
( J; y1 m) ~, R- a. T# f$ G - uint16_t TimsRepeat;* U3 w ` A ]/ x6 T
- uint8_t CAN_SendStdMsg(CAN_HandleTypeDef* __hcan,uint8_t *pData,uint16_t Len)4 ~- V# l% G; `$ Y
- {! n' t- Y8 R7 j6 [2 ]
- uint16_t SendCNT=0;9 B0 K& i8 c2 G/ t
- uint32_t TxMailbox;# X- X) x6 {% u2 `# l
- HAL_StatusTypeDef HAL_RetVal;% X- r; J7 N$ [5 r3 t
-
9 x+ j8 y6 O1 g# u! e# h/ k; K - TxMeg.StdId = 0x321; //标准ID
4 j4 Z9 f% ^0 W4 l* Q/ | - // TxMeg.ExtId = 0x10F01234;( q" |& V0 a8 g$ t' Q. W* _
- TxMeg.IDE = CAN_ID_STD;// 标准ID类型
; V1 }* N+ R: x2 a8 J N$ Y4 a0 | - //TxMeg.IDE = CAN_ID_EXT;// 扩展ID类型
2 }) P+ h3 p# i6 K8 r7 }7 }, ^4 E - TxMeg.RTR = CAN_RTR_DATA; // 数据帧
& B4 e" Y7 h: H+ v - //TxMeg.RTR = CAN_RTR_REMOTE; // 远程帧
4 p& T0 ?, b: M% `4 P( R% K - TxMeg.TransmitGlobalTime = DISABLE;9 w( O- }& F+ X! H! ]
-
- ~. o4 T) M, q# Q2 B% u - if(!__hcan || ! pData ||!Len) return 1;- ]) n$ I9 q. N" t! J# I( R
! D' J5 Q/ d) K( I! }! g- TimsRepeat =Len/8+(Len%8?1:0);1 ^$ X1 t- B0 e. J! t3 I" J( @' Z$ e& ?
- while(TimsRepeat--)
' `% U0 X( y! `; d, t - {
0 N, @% q6 h0 G+ S, g' o% c - while(HAL_CAN_GetTxMailboxesFreeLevel(__hcan)==0);
3 Q4 q( R7 K, u- i; @9 X - if(TimsRepeat>0)
0 E+ J# s- K( Y/ s9 h - {
( d B- F: ?. Y% _% U/ s. m6 q3 G% y - TxMeg.DLC=8;
# A+ s3 |6 z4 K" V - }( m1 [' m: o8 w, t3 G& n5 x
- else# _2 @9 `2 |6 A0 C; o! Q1 R
- {& ?2 a* U$ y" B- M9 I
- if(Len%8): b. \+ p4 P, e4 t5 {
- TxMeg.DLC=Len%8;- Z @3 k. ?/ U: r6 `; ^
- }
# b- K# G/ D0 `& q$ s - HAL_RetVal=HAL_CAN_AddTxMessage(__hcan,&TxMeg,(pData+SendCNT),&TxMailbox);
/ ]/ G9 S, f! z3 R& ?& n& R - if(HAL_RetVal!=HAL_OK)
& D; P$ X' x. s4 ` - {
- x9 u' j( |8 p* N+ k, z- V; @ - return 0;) q) g2 b5 A5 f
- }
; }- ?6 `& b7 `; d - SendCNT+=8;- A+ C/ G& _$ b* V. I8 ]: g/ t1 t1 W5 I
- }
/ h* c0 m; u/ u# |* S+ B& f - return 1;
复制代码 ( |* q) r7 k$ m7 I
9 A0 N+ q7 N; h$ \ l. ]) G
bsp_can.h & o' @1 h7 ?" _6 a& ^* z
- #ifndef _BSP_CAN_H7 B/ {/ S3 d1 l/ S- f9 H1 m7 T9 g
- #define _BSP_CAN_H
& S$ e! C/ e* Y - #include "stm32f4xx_hal.h"; d2 K0 C1 X) V" }7 e' N! b
- #include "can.h"
3 Q# H. u# v+ G
% o1 M* j- l/ I3 z( U- //typedef struct+ H' p8 Q2 R0 `: b: N
- //{
- Z4 r* r8 h: B5 i/ I% a: d7 Z# u - // uint32_t mailbox;
# C' P7 v7 H: s! o8 ` - // CAN_TxHeaderTypeDef hdr;
- n& v2 c4 |! _" ^( w% H, c - // uint8_t payload[8];
! r) E* A7 C6 E% m* Q - //}CAN_TxPacketTypeDef;8 X* q$ E/ c8 Z8 s
* a- O6 \" G9 g0 M8 N- typedef struct
, {5 V2 d* t4 g' K, K+ c - {
% `8 |: ]' f( t4 n7 }, t0 w0 O" X$ \ - CAN_RxHeaderTypeDef hdr;
7 O2 U% }* P, |1 m4 y/ y3 w - uint8_t payload[8];
5 X7 ^/ w* s) N* W6 R7 x; a - }CAN_RxPacketTypeDef;4 B" @0 A. t1 C
+ k6 j( b$ N3 K- 8 O: C" D9 b1 q
- void CAN_Init(void);5 d* ]: J% V* D
- uint8_t CAN_SendStdMsg(CAN_HandleTypeDef* __hcan,uint8_t *pData,uint16_t Len);
4 Q$ O! |/ p" S7 Y' l5 K - #endif
复制代码 4 z5 r& R( l6 s' W. L: A" K7 `
就可以工作了???非也
N7 e; L2 w% D) o! s/ ?其实我发现还是有问题
6 h* t' q1 R% K0 e! @. V, N5 y; Z
0 p! O R/ g2 o" j
5 F1 I! A6 u& G: X" L4 j6 N. L- [1 Q% V* k( h( Q+ P3 m" {
为什么第2 3包数据到最后去了?
6 K' E/ {4 T J6 t" r
查了一些资料发现了问题:
1 A" }; s z9 y”发送邮箱“是用于CAN总线数据发送的,总共有3个,并且存在优先级关系。优先级越高表示其里面的数据会被优先发送。数据在发送前都会被送到优先级最高且空闲的发送邮箱,然后依次发送。最后说明一点:“发送邮箱有3个,且每个邮箱只能装一个报文” 原因是,三个邮箱有优先级,我发送前会检查三个邮箱是否都满,没满就发送。导致 第 2 3包数据在两个优先级低的邮箱,导致才最后发送 & x6 y4 x1 n- t0 a$ P! e- ]1 ~
查看库函数
+ e. n7 x0 W) V& N u3 w
) }0 |- g# X# \9 \2 k. l: ~$ s/ a
- /**- S# ]( z2 W6 W9 G* C
- * @brief Return Tx Mailboxes free level: number of free Tx Mailboxes.
4 k4 ~2 x6 y- \! e& \ - * @param hcan pointer to a CAN_HandleTypeDef structure that contains* }! S" q. T+ P6 r
- * the configuration information for the specified CAN.$ h/ c8 k3 J' c2 ?& R* A
- * @retval Number of free Tx Mailboxes./ T& M( \6 Q" ]. R) }& o
- */
, q* t. I2 j- v0 e2 P - uint32_t HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *hcan)
' q/ z5 i( E! @6 [) d - {" U) N, f6 p" Q: x( d# T( @7 V
- uint32_t freelevel = 0U;
# Y2 U! D* L. b2 L( Q - HAL_CAN_StateTypeDef state = hcan->State;
4 _5 f1 H G8 b9 O, ?+ k! Q: } - . |+ }& h' i5 p" P3 \
- if ((state == HAL_CAN_STATE_READY) ||
- |& t2 D# t9 B0 c9 `0 I% d( V( w) h - (state == HAL_CAN_STATE_LISTENING))
/ s. b9 ^2 p# j5 C - {
, g6 _' `5 B- `6 W - /* Check Tx Mailbox 0 status */
: j- K, \: j4 L+ _ - if ((hcan->Instance->TSR & CAN_TSR_TME0) != 0U)0 [4 M' G8 S5 J8 F0 k
- {5 p* `5 M* A K
- freelevel++;+ S5 D$ v" Q# p1 z6 U
- }( x( n' {; [" U( y! }! l# }+ k
- , p" p& Z, U Z% m8 `, J+ d6 D
- /* Check Tx Mailbox 1 status */
; |: ?( v$ e) G+ u5 o" F3 k - if ((hcan->Instance->TSR & CAN_TSR_TME1) != 0U)! P9 h% L3 Z! G& a
- {; w& ?" v2 L. h h' V# ]7 v
- freelevel++;
( `' p$ t( _ N% |# d$ ?, X - }6 W2 j; Z7 |# }& s5 k5 E
8 u" T7 p: n. A: d( F1 b- /* Check Tx Mailbox 2 status */
9 L' J$ P* z" p - if ((hcan->Instance->TSR & CAN_TSR_TME2) != 0U)
# H+ U5 G! V) v0 o1 H - {
' T( ]$ H& ]2 F- \- V1 d F - freelevel++;
9 m: i( H! T. {6 p" K+ @ - }
' L" ]- y9 T u( a( A/ J - }
3 R/ Z o+ W, Y+ j9 L2 [
" u9 Y( ^# F; o2 {! X- /* Return Tx Mailboxes free level */$ i, d# F; ]$ F% w Z/ U
- return freelevel;
2 F1 u5 M& s9 e. g% j - }
复制代码 ! v a% f" r/ f0 I3 Z
解决办法如下:当然你也可以自己封装一下 4 i8 I% e- }) Y# D9 y
- uint32_t HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *hcan)
9 { r" |* R- a; h0 @) [$ Z$ B - {
5 h1 t7 L0 W; m7 [ r% z' { - uint32_t freelevel = 0U;
* z" ]3 | ^7 } - HAL_CAN_StateTypeDef state = hcan->State;
) s [8 C: o2 I
+ t% Y5 B0 L; {, L' d- [- B- if ((state == HAL_CAN_STATE_READY) ||' S& g% w* r) L
- (state == HAL_CAN_STATE_LISTENING))9 n9 t4 u: p* D% F# j$ x
- {1 d' z3 r$ @* m/ G7 T
-
; `, u* u! ^8 g# _ - if (((hcan->Instance->TSR & CAN_TSR_TME0) != 0U)&& \8 i1 e5 i7 }) Y m+ r! N
- ((hcan->Instance->TSR & CAN_TSR_TME1) != 0U)&& \
" d2 a1 M4 O. x - (hcan->Instance->TSR & CAN_TSR_TME2) != 0U)
; A, M) |6 J2 \* Y& s - {
5 ~) `# j0 c. t( U8 W' v6 T! r; p - freelevel++;
% x; R$ R7 f) Q, @+ m - }; R' c+ G9 w$ l3 l7 f
- 1 w& n* ?2 k( Q2 O2 D3 ^! H; k9 \; q
- /* Check Tx Mailbox 0 status */3 \# P: r9 u$ d! i
- // if ((hcan->Instance->TSR & CAN_TSR_TME0) != 0U)
# f- ]) S4 [3 y+ a - // {
" ?" c4 Q5 P" _7 t: Y( l# U - // freelevel++;8 M( S& A) J8 k
- // }
3 [' m- u. p* V( u# U2 i) |) ?# u
4 V% o4 o; L K; m/ B2 I) Q- M- /* Check Tx Mailbox 1 status */2 O6 i5 f& |, [1 J- N3 G( A
- // if ((hcan->Instance->TSR & CAN_TSR_TME1) != 0U)
; V7 e9 u: R% a - // {
" E5 `2 {( D K, D( r! S- T - // freelevel++;% W0 \4 A9 O8 K0 q; V- A
- // }; x; p7 y* m6 N: a& W
- ) ?; m, s- C4 y1 h
- // /* Check Tx Mailbox 2 status */; S1 |( ]* U8 s$ M" s6 z7 J1 k
- // if ((hcan->Instance->TSR & CAN_TSR_TME2) != 0U)
; C: a* w" O% Z$ N8 i - // {+ z) r0 g0 o- W) z
- // freelevel++;
4 h) Y* c+ q" K6 {: K. L' _* U& Z - // }
/ ~5 J7 r% i9 x# C8 Q - }
" O8 I- C7 ~' U
6 B: r* c, b5 c1 G* ]- /* Return Tx Mailboxes free level */, [) c7 H" J! X& |
- return freelevel;
7 J* ~: m5 m7 @" |# I" _7 T4 G8 r - }
复制代码 % [% z) L G% E* z- E
! O3 V, J# k) G% v三 总结: [; d! r7 L( a9 ?' T
CAN数据在发送前都会被送到优先级最高且空闲的发送邮箱,所有发送完后 我们不能检测三个邮箱是否有空邮箱,而是应该检测三个邮箱是否都是空的才对。 6 l( {8 m( `% L) l% {) x- @0 H
9 A' j! b& Z! p, d7 d6 B 四、CAN以及库函数分析& j/ n* d( N4 m3 k
CAN总线
! R+ o* f7 X$ [2 S7 A# x1、根据标示符(也就是 ID)来决定优先级的。
3 b+ s* z# v1 L) E0 k, e2、在同一网络中,所有单元必须设定成统一的通信速度,最高 1Mbps(距离小于40M),最远可达 10KM(速率低于 5Kbps)
* q8 P2 V3 E/ p) t7 g3、可通过发送“遥控帧” 请求其他单元发送数据。3 c ^5 B4 ]7 Y) L, e! Z. ~
4、CAN Model:
3 z' N' B* ~9 z6 `1 ~# WNormal 正常模式
" x Q( C9 \, P6 qSilent 静默模式
9 }: X3 I' j( }. L/ dLoopback 环回模式 测试& P2 h# f# l' t1 L
Silent_loopback 静默换回模式 测试
N1 d5 g5 D, u* e& _2 P
5、波特率
% H d* o% L- U9 p% _, f& x4 g波特率(Kpbs) = fpclk / ((CAN_BS1 + CAN_BS2 + 1) * CAN_Prescaler)
- n b4 t. [+ A2 u9 ?
6、发送数据结构体指针 - /**" Z4 w# h$ b( S+ R: O1 m7 T6 M9 u
- * @brief CAN Tx message header structure definition
% I6 Z) w/ F5 h2 H0 L Q$ ~ - */( m, f; |/ ^: v6 P' S) m: {
- typedef struct, i8 g8 _" ^* I
- {
1 A! _4 h9 |- d, B) H9 Q - //表示标准的ID
" o6 _! ]7 p6 W0 M* S - uint32_t StdId; /*!< Specifies the standard identifier.5 J4 e$ ^. E( L- D
- This parameter must be a number between Min_Data = 0 and Max_Data = 0x7FF. */
; u2 `$ @& V. e - //表示扩展的ID+ _9 Y' S- Z: Q! z# H2 |/ D% R
- uint32_t ExtId; /*!< Specifies the extended identifier.8 K6 }* G# M! _ c, i& ?
- This parameter must be a number between Min_Data = 0 and Max_Data = 0x1FFFFFFF. */ n- A* I( A2 Y! d4 z* N% i
- //要发送的是扩展帧还是标准帧5 e5 l: Y& c, B) K0 B
- uint32_t IDE; /*!< Specifies the type of identifier for the message that will be transmitted.
" q- B2 w& g5 s$ p6 O7 W% ]' _* d - This parameter can be a value of @ref CAN_identifier_type */9 T9 A; O7 J/ D! E1 ^$ h
- //表示发送的帧类型。如:数据帧、远程帧等
1 I" C2 t8 T' n - uint32_t RTR; /*!< Specifies the type of frame for the message that will be transmitted.
* z3 W% p, k" L4 n: L - This parameter can be a value of @ref CAN_remote_transmission_request */' T, M9 A5 T1 L- q: E8 ]
- //表示发送的数据长度
/ M% x5 Q+ ^3 d5 H7 S% Q - uint32_t DLC; /*!< Specifies the length of the frame that will be transmitted.
% x8 n1 T7 y; j. o5 e7 } - This parameter must be a number between Min_Data = 0 and Max_Data = 8. */7 ?5 X) }0 z% ?# f
- & X9 ?$ _( H; `5 q9 ]. O
- FunctionalState TransmitGlobalTime; /*!< Specifies whether the timestamp counter value captured on start( }# H( d+ _' a2 F. F* _
- of frame transmission, is sent in DATA6 and DATA7 replacing pData[6] and pData[7].5 E* u( Y! q4 M( t ]) D
- @note: Time Triggered Communication Mode must be enabled.
' f; U- [% x0 e' J - @note: DLC must be programmed as 8 bytes, in order these 2 bytes are sent.- y- _( G2 R3 o( Q# j: T& h
- This parameter can be set to ENABLE or DISABLE. */
2 Z$ a0 r2 w, c3 o3 @9 ]- L - 6 y' V+ m* R6 S1 n0 H
- } CAN_TxHeaderTypeDef;
复制代码 % ~3 q' U. A3 u$ `$ m0 ?1 k, U$ Q
7、过滤器:为了方便接收想要的ID,过滤掉不想要的ID。28组或14组过滤器,每组2个32为寄存器% U& M8 `4 E0 d. K, j8 _
屏蔽模式
5 a+ {7 ^; L0 v; n) [2 k1 S( f屏蔽位模式: 标识符寄存器(设置想接收的ID)和屏蔽寄存器(设置关心的位)。又比如说,当你值接收一个固定的 ID 的时候,你 把屏蔽寄存器全部设置为 1(即必须比较),然后在标示符寄存器里面存放你
& l' a, i; \3 {! q想要的接收的 ID,那么当 CAN 总线上面出现你想要的 ID 的时候,它就将它接收,其他的不接收。
3 T S. s4 Y: b- X, w屏蔽列表模式:每组过滤器 中的两个寄存器全部用来做标示符寄存器,也就是说当接收的 ID 必须跟表 示符寄存器中的 ID 相同的时候才接收。
# J8 N5 v3 j; o v
& n+ L; I* p3 K. y' l. L
8、过滤器结构体 ( R/ ^% M( d8 j5 D
a$ l$ s9 E7 i' @ G; b# s1 c
- /**3 W5 X4 G3 G% {/ V: Z) R
- * @brief CAN filter configuration structure definition7 H1 g: z& p. \
- */
; h% N( l- f* ?: o6 p - typedef struct
' U. L( }& P0 z1 b - {
/ L6 q# Z5 T/ J% n- n2 k: R+ W8 ~ - //这个是标示符寄存器的高 16 位1 N* M f& }3 c3 z. m
- uint32_t FilterIdHigh; /*!< Specifies the filter identification number (MSBs for a 32-bit
, E! I; W5 F: O' `4 Y: v+ E - configuration, first one for a 16-bit configuration).2 Y# h: ?( Y5 w6 |
- This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. */6 M* w* S3 O" A
- //这个是标示符寄存器的低 16 位2 E2 {0 k, q; Z$ y3 f1 K
- uint32_t FilterIdLow; /*!< Specifies the filter identification number (LSBs for a 32-bit; K* O, h9 g2 I, x
- configuration, second one for a 16-bit configuration).( I/ B0 e6 v: m" }) X% o% P* }
- This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. *// L$ o: r8 f# z
- //这个是屏蔽寄存器高字节的设置
! _! _8 o; r( W4 F - uint32_t FilterMaskIdHigh; /*!< Specifies the filter mask number or identification number,$ l5 {3 F1 s4 r% e) C! A; R
- according to the mode (MSBs for a 32-bit configuration,! J1 j1 e* I8 ], `
- first one for a 16-bit configuration).
- l$ N) l4 L0 X1 O+ H% P - This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. */
# V2 j( F' u( G. h2 J6 @1 Q9 m - //这个是屏蔽寄存器低字节的设置
" O, O6 _) ?- ^+ H; G2 r t - uint32_t FilterMaskIdLow; /*!< Specifies the filter mask number or identification number,
: q3 n. j; I$ n# z3 R6 Q - according to the mode (LSBs for a 32-bit configuration,% p1 p5 R+ j* S) x7 Q0 x. |" a
- second one for a 16-bit configuration).+ X" ]/ V% R( }+ k" \
- This parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. */
@* N: M3 m+ [7 E( f4 ? - //选择你要使用的邮箱,它有 0 和 1
( d0 `7 W$ n' D - uint32_t FilterFIFOAssignment; /*!< Specifies the FIFO (0 or 1U) which will be assigned to the filter.7 ~' P5 L0 f) f
- This parameter can be a value of @ref CAN_filter_FIFO */4 x% c) G& Z! [8 M# J. {
- //表示标示符寄存器的ID,)我们这里使用第一组寄存器设置为:1。
' E7 L3 e6 d, H6 D( d' c - uint32_t FilterBank; /*!< Specifies the filter bank which will be initialized.% b2 k; ]( T7 H V P* ~
- For single CAN instance(14 dedicated filter banks),
_1 r# t7 ^7 W- ?+ t! S% \3 ` v - this parameter must be a number between Min_Data = 0 and Max_Data = 13.# J" x8 s4 l$ R
- For dual CAN instances(28 filter banks shared),
# O0 E. {- @! o) K9 u' U7 l" G7 e - this parameter must be a number between Min_Data = 0 and Max_Data = 27. */
& g$ n" Y* e6 y; C/ N - //表示过滤模式。我们上面讲到它有屏蔽位模式和
4 p2 E" {0 k8 a. t+ \ - //标示符列表模式。我们使用屏蔽位模式,所以设置为 :* _7 b& l) p5 A( T' c
- //CAN_FilterMode_IdMask。
% J1 w% f7 Z9 t/ y+ `4 c1 ~ - uint32_t FilterMode; /*!< Specifies the filter mode to be initialized.
+ { R+ a# A5 C: j - This parameter can be a value of @ref CAN_filter_mode */& R$ m, F% U# U* R+ o
- //表示设置过滤器的长度。过滤器是可以设置为16位和32位两种模式的(即接收标准帧和拓展帧的区别)。$ _; [. ~) o. E6 R/ [
- uint32_t FilterScale; /*!< Specifies the filter scale.
1 M* u1 i3 k3 w, D; R: N9 A1 U - This parameter can be a value of @ref CAN_filter_scale */7 o8 ^# U2 l& @' F$ j3 f" w, B- c
- //表示过滤器的使能) a( w1 h7 e/ D b4 ~# u5 K: e5 l
- uint32_t FilterActivation; /*!< Enable or disable the filter.
! w# @+ x9 _4 Q( u( g0 l - This parameter can be a value of @ref CAN_filter_activation */
- @+ |4 y4 D+ O2 n m6 C - ( } _2 }, n# y& f9 g
- uint32_t SlaveStartFilterBank; /*!< Select the start filter bank for the slave CAN instance.( @, ~6 @# H" d
- For single CAN instances, this parameter is meaningless.
/ P/ f! V/ h2 Z% o& t( A" [6 g' N7 U% e - For dual CAN instances, all filter banks with lower index are assigned to master
% }2 q" Q: q- E; B# o - CAN instance, whereas all filter banks with greater index are assigned to slave% g D( E- l' o8 |$ J% i8 U
- CAN instance. v% v/ k6 ^4 R: G
- This parameter must be a number between Min_Data = 0 and Max_Data = 27. */) H8 F( {$ _; `! `8 {
- } CAN_FilterTypeDef;4 L8 W+ @6 G9 v
复制代码 8 Y1 K: D1 F% F9 z! [# ?+ `
+ t) P3 Z# O0 y q
|