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