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