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