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