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