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