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