本篇用起来, 连接关系如下:$ p: s3 }" a/ i) m% X
3 n; U( w. l$ I0 f; R0 i9 K0 c
, O% e, ^' c& {% X' v( O% F; Y4 T0 Y+ S1 w0 }
CAN收发器均选用支持2M及以上CANFD的收发器, LPUART到PC用STLINK连接.9 ? \4 m1 r/ Z' N! N3 `0 ?2 D
) Y& F* ]3 q) t6 _STM32工程搭建% j% _3 c, C G/ j
STM32CubeMX配置步骤如下:, {( N8 U2 c& S
; x+ J8 }% @! y' r0 s4 RMCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32G474VETx
2 f+ }. m* G+ x# _ \! o5 S5 {6 m# I9 v3 d7 V
调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire8 y; C! L8 o: P) {
, K$ N: V$ T7 c2 ?: s u( c" NPinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
. f, ?( w' ]; H' \1 _/ N/ R+ V- a, o$ u q+ H4 f3 P
Clock Configuration(我板子上用的外部12M晶振, 主频配置成160MHz, FDCAN的时钟来自PCLK1=160MHz):$ d( E2 o: E! J7 d% e" a- \
$ A/ w. U) y4 b5 W9 B
6 P6 u$ g8 L1 x) q2 T3 c
( d" }( S+ t& O3 y# V. s0 b3 x开启100us定时器中断: Pinout & Configuration -> Timers -> TIM6 -> 勾选Activated, Prescaler设置为160-1, Counter Period设置为100-1 -> 勾选TIM6中断:
8 A1 p0 z, a; Q; k- A+ e# y" q3 @0 Q1 p t
: C" k' g0 K; H U% {
6 h' X6 q1 I- ?! J/ ?6 p. d% A- ~9 [9 f7 n( m
3 Y2 U8 G- b+ o! W3 W, FLPUART1配置: Pinout & Configuration -> Connectivity -> LPUART1 -> Mode选择异步Asynchronous, 关闭 Overrun 和 DMA on RX Error, 波特率配置为2M-8-N-1:. O) n8 f5 z, j1 s8 Q7 q
4 W5 n/ Q; ]+ A5 ]& O9 P e
; T# X) S- { ~6 `7 d* b* M5 l8 T: R
# L/ i4 E8 Q9 T5 k7 u& L3 r
FDCAN1配置: Pinout & Configuration -> Connectivity -> FDCAN1, Mode选择FD, Frame Format设置FD mode with BirRate Switshing启用位速率变换, Auto Retransmission设置为Enable开启自动重传, Trasmit Pause设置为Enable开启传输暂停, 速率和采样点设置参考上一篇 STM32 CANFD 基础知识的位时间和采样点小节, Nominal仲裁段设置500Kbit/s(160M/NPre/(1+NTSeg1+NTSeg2) = 160M/4/(1+63+16) = 500Kbit/s), 采样点0.8((1+NTSeg1)/(1+NTSeg1+NTSeg2)=64/80=0.8); Data数据段设置为2Mbit/s((160M/DPre/(1+DTSeg1+DTSeg2) = 160M/4/(1+63+16) = 500Kbit/s)), 采样点0.75((1+DTSeg1)/(1+DTSeg1+DTSeg2)=15/20=0.75), Std Filter Nbr标准帧过滤器数量直接设为最大28, Ext Filters Nbr扩展帧滤波器数量直接设为最大8(虽然后面并没有全用上), 勾选FDCAN1 interrupt 0中断, 引脚也从默认调整到板子上用的引脚PD0/PD1:; H0 }4 G& O- s& S7 n! _: k
2 K& O/ J. g# q/ g) |
4 o* g9 v. \" [: C( n
% o# c& {6 W: t' Q9 _6 O
' J! c. S% O u$ ~: ]# ^5 e; O1 Q' Q
! o7 ]! k# ^# P2 ]. VFDCAN2, FDCAN3的设置同FDCAN1, 注意引脚要从默认改为板子上用的, 最终引脚位置为:
s' ^, D1 c4 Z
8 {! C `0 N# a. v8 y6 E
+ ^' E2 \' x* T. f. b+ w
+ S) P: z; E3 d& v, f) `Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM, 把Minimum Heap Size改为0x1000, Minimum Stack Size改为0x1000. 或者更大一点.
# o1 `/ u7 t; W- L6 O( K3 N! x& L0 N# c! p+ T7 r
Project Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral
" ?8 J, d6 P# D- U ~. V7 n6 A& G) F; X. P. Z+ \/ }
点击右上角 GENERATE CODE 按钮生成代码, 点击Open Project按钮打开工程.& s/ d2 Q6 q) z$ O9 y$ W) g* i% N/ M
" D0 d/ r8 G7 D- ?
Keil配置, Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置Debug为ST-link Debugger, 点击Setting:
# g" D1 A0 \' J6 ^, P5 m
" |; P& j; i- M0 y. [$ V* ^1 a; xFlash Download选项卡 -> 勾选Reset and Run, 这样下载后可以自动复位运行.
8 z3 e2 Z9 j! {* K# p6 ?Pack选项卡, 去掉默认的Enable勾选( N. r- T, I# e! T% J w
到此配置结束. 下面是手动添加的代码详解. I5 }4 m: G! L5 e
$ R, D' H* B" w; E" x7 F1 f
串口配置
& k1 ^# s* a/ s! U1 X为 LPUART1 添加printf支持:, T! v( z7 Y0 D+ m
1 W9 H6 R0 \/ |% i: v3 R
- #include <stdio.h>3 r% Y. Z& z6 G; E! S0 J# E
- ; e( w. s# ]% N, M- G. L
- #ifdef __GNUC__
; W' S7 G( a; }9 b" h( k6 |! Q+ x+ e' s - #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
$ k5 r5 R& M4 K' G3 _, k - #else
b: D5 ]# p& a; u& `) z - #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
- C+ }5 ^* g$ L# N - #endif /* __GNUC__ */
, d4 m- m8 `& b
" ^$ v0 w3 o6 A3 j$ \- PUTCHAR_PROTOTYPE% ^7 |, T: {" @7 r
- {
, R n! R" _) \$ s% Q5 K - HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);( q: b4 Y" U! d' g; t$ W
- return ch;
复制代码 ; Q8 t2 O$ J# j$ @! F4 @) R& j
100us定时器
5 a ^4 s9 w/ E8 N因为用最大64字节测试的, 实测只发送的情况下, 1s传输最多2490+约2500帧, 再多就丢帧了, 也就是400us/帧, 保守一点, 这里设置500us传一帧, 如果没传出去, 100us后有一次重传的机会, 这就是100us定时器的由来.
( C4 U! G' I: _' {; \: e D7 t1 W7 b4 C* Q5 D% I; l9 v2 q, |
- /* USER CODE BEGIN 2 */4 j( q- ~8 L* x5 f6 M. F- T7 e
- HAL_TIM_Base_Start_IT(&htim6); //Starts the TIM Base generation in interrupt mode.3 x& x4 n- C4 a# Y" k% M% v# h
- /* USER CODE END 2 */3 J3 m; i; \# ~# b0 B3 o c& K
- g; D% J0 Q" H
- uint8_t tim6_flag = 0;
* j7 R' d& N2 ~; A; o! c5 { - void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) / v* x7 x4 t* l$ C: q8 L$ A; G* ~* r
- {
$ O) ~2 B. ~8 q - if(htim->Instance == TIM6) {- g9 B6 D4 ?/ @6 c
- tim6_flag = 1;6 E0 ~5 S1 Q R; s9 X/ d1 g
- }* l) t) t" }: {) t/ R
- }
复制代码
a- v; h, N* r; J' U) n8 l2 K5 V( P; Y& ^FDCAN配置
) k7 C+ o+ n( S* s V: [主要是标准帧滤波器, 扩展帧滤波器设置, 开启新消息接收中断, 开启Bus-Off中断, 设置发送传输延时补偿等.
" |5 {7 S" e% C% c9 @& R4 `5 v6 K/ z- X
- FDCAN_FilterTypeDef sFilterConfig1;
% t3 A+ \" [3 r* t+ X* s* L$ @* H" F$ |& D+ z - " _: O' U2 Q0 u. Z2 n
- void fdcan1_config(void)* i% c5 N. ]( I% m: }) J
- {
6 u9 ], U p* g - sFilterConfig1.IdType = FDCAN_STANDARD_ID;
, z7 j- {9 Y4 B& v- b! a - sFilterConfig1.FilterIndex = 0;6 L2 I: ?1 E, c: w" {6 w% G
- sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;% Z# v/ }. M1 }1 ]% U
- sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
5 a& f) F! t$ } - sFilterConfig1.FilterID1 = 0x00;
% n0 m7 ]/ l0 A! @/ e - sFilterConfig1.FilterID2 = 0x7FF;. k f) g6 O3 |, H
- if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK), g; X* V- ~+ q7 O% g' S% |
- {
) y3 f) H5 Q; X6 J1 u: |9 Z3 E) l - Error_Handler();
3 l0 q" _; [5 S' s9 O - }, |! W, P0 ^1 j6 W) j
- ) |* w2 N" y" \$ r6 r: ~ ?" @
- sFilterConfig1.IdType = FDCAN_EXTENDED_ID;7 _, W0 Q) s4 f7 C1 ?
- sFilterConfig1.FilterIndex = 0;
- j* [: i* i: E8 ]+ C - sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;
% h" @+ D d: \* U1 Q - sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
" M6 N* V9 w5 V3 I4 C" i. J - sFilterConfig1.FilterID1 = 0x00;
! j: L" @& q% S% C - sFilterConfig1.FilterID2 = 0x1FFFFFFF;/ C( T6 A8 W- w8 q
- if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)
' M9 c; d9 E: s/ N* T' W6 B - {
* t+ A9 H5 k2 x C6 g! `9 b0 k - Error_Handler();
% i( Y+ Q3 L6 o; S - }
* l+ ]. n) H/ Q& {5 |4 Z - 5 \! l* T# a8 M: V6 @4 a
- /* Configure global filter on both FDCAN instances:% }' ~) B4 N C, ?) f7 x% A
- Filter all remote frames with STD and EXT ID, c/ W$ N& e% |& L8 I
- Reject non matching frames with STD ID and EXT ID */
' ^+ h) _7 X0 r: u; M- d - if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)4 b: q2 Q0 |4 L. X' Q
- {
3 M- q5 a; w+ a" b: h% h - Error_Handler();
# L5 o% Y3 B) _9 O; @4 Q; e* y/ G - }
K# b. P: _3 E- E9 p# _
' J$ Q' H6 R8 x/ e; C- f$ [- /* Activate Rx FIFO 0 new message notification on both FDCAN instances */& G+ Q7 e" k+ ] }
- if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)! {5 i' n2 d k" ^3 A" c% U. ~/ E
- {9 e# ]: ?9 q; G
- Error_Handler();
3 G" A2 O% k$ }& \: `/ k$ } - }
! C- d. p" }& u8 z/ g! W - 7 C# E* q x1 f6 y/ E( u
- if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK). g! T# b6 N/ M9 m4 e5 N
- {
' W( R+ \9 N" N: r' E1 ?8 S# y6 V - Error_Handler();
8 U9 j! i5 m) i0 }( h+ i - }. l+ c& }2 ^, t3 o$ P3 y, j
- - ^8 p; V5 X7 F& k) A
- /* Configure and enable Tx Delay Compensation, required for BRS mode.- n' T( k, t# y: T4 Y9 K7 n _
- TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler( E# _% i" d6 A6 u- ]9 c! }- [
- TdcFilter default recommended value: 0 */
3 r( Z4 ~8 Z7 [4 g: I - HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);" C# D; j" j% \3 G* f p
- HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);
' @" G# n8 v7 L4 y0 O - 8 Z+ P8 m& e# n% _0 m' c
- HAL_FDCAN_Start(&hfdcan1);
* X8 @( z1 `5 U, O - }
复制代码
- b/ }2 u2 j3 a$ @ y# ^这里设置了用一个标准帧滤波器设置了标准帧的全接收, 也可以用掩码的方式设置全接收:
1 l: J+ j! G5 ~' r( d& k- sFilterConfig1.FilterType = FDCAN_FILTER_MASK;1 j8 e1 z" X E% W9 V
- sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;; |, c6 O1 ^( K
- sFilterConfig1.FilterID1 = 0;
( A. `' G3 {' v - sFilterConfig1.FilterID2 = 0;
复制代码
& g8 G" J& p" O% m' W7 X用一个扩展帧滤波器设置了扩展帧的全接收, 消息扔到RXFIFO0中, 设置了RXFIFO0的新消息来的中断, 也可以扔到RXFIFO1中.
8 J- w& J7 q V" e6 e* E% h
' _$ Y+ B, ]) `1 @4 i- ?有别于STM32H7, STM32G474在STM32CubeMX软件中能设置的最大标准帧滤波器是28个, 扩展帧滤波器是8个, 这里程序中只各用了一个(index = 0), 如果想用更多, 不知可否手动更改stm32g4xx_hal_fdcan.c中213行这个值, 如把扩展帧滤波器数量从8改为28, 有兴趣试试:. v2 J& p$ P9 m8 t
% }8 i! y$ l% L# u, s/ g- #define SRAMCAN_FLE_NBR ( 8U) /* Max. Filter List Extended Number */
复制代码 3 T7 R, ~8 G1 R3 {5 ^ I
FDCAN2, FDCAN3的配置和FDCAN1类似.
: W: P9 ^$ E/ O4 m* b8 o! _: w- V- Y; E, }+ w1 R
Bus-Off处理0 c+ O- K! G! \% Z
如果CANH, CANL短接, 或者和其它节点的传输速率/采样点不一致, 会引发Bus-Off, 上面开启了Bus-Off中断, 发生Bus-Off时, 直接在中断中初始化FDCAN外设:0 R2 T7 E1 G* P# u7 g. p; k
4 y% T# a$ d7 Q- void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)# k# S0 ?- I! }0 i( }
- {
H8 ~( `& C" c$ H - //__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_BUS_OFF);
- @" o- Y: W/ G7 a( o - if(hfdcan->Instance == FDCAN1) {8 O- O) l/ @9 w8 h0 z9 Y8 i4 f
- MX_FDCAN1_Init();
3 T4 H- _" i' v' c5 `' p; D - fdcan1_config();3 e# e3 s N& V8 g
- } else if(hfdcan->Instance == FDCAN2) {
+ y$ |6 ~( ], }$ ? N9 W - MX_FDCAN2_Init();8 O; B- U) }& F, G0 x. P m: J0 p
- fdcan2_config();
2 `+ b/ x) w) x" b$ ~ - } else if(hfdcan->Instance == FDCAN3) {- F1 |' X7 T, @2 M" u% v. @
- MX_FDCAN3_Init();
Q- D8 n. y% h - fdcan3_config();
9 w- I9 w0 c( C7 z - } else {
6 l! _% z; y6 p! D - }
4 e( V* J9 `# |9 o5 M% m - }
复制代码 ( [3 |; J! b. p/ F
新消息接收处理
3 `7 v* `/ |: z; }8 ~& M直接把接收的消息通过2M波特率的串口打印出来.
, P$ d' D- L( Q; N' a6 g- E$ h. F; N
- FDCAN_RxHeaderTypeDef RxHeader1;# P7 D2 }& F [
- FDCAN_RxHeaderTypeDef RxHeader2; R, Y1 U* \! n: j; C
- FDCAN_RxHeaderTypeDef RxHeader3;
S3 ?: a u- j7 ]6 A, {# `' K - " c/ n2 C# \+ W \2 N
- //RxHeader1.DataLength => can_dlc5 I0 i, n* p: v$ I
- //0x00000 => 0 & m, u9 g6 L9 u7 v5 ^" u
- //0x10000 => 1 7 Y4 J' K3 n4 [: p2 x/ a
- //0x20000 => 2
2 R: q! @- H) B$ t - //0x30000 => 3 . W& e/ k' o5 m4 `" K9 z2 P5 _
- //0x40000 => 4 , `9 i6 N1 |8 T
- //0x50000 => 5 9 Q3 Z! B2 `* E9 M! N% u3 U
- //0x60000 => 6 m0 g1 P3 Q3 O9 }
- //0x70000 => 7
. r5 Y" w4 K3 O/ p* B - //0x80000 => 8
0 L. m5 a e# @9 n. C1 {: N - //0x90000 => 12
7 t' k0 V. n: O7 B% }$ @4 @ - //0xA0000 => 16
5 O. m- k0 S$ R* ]2 n; o* E - //0xB0000 => 201 }' e9 v* l! }. `5 W
- //0xC0000 => 24
9 Q3 g" |1 Y9 P4 i0 }; b ], n - //0xD0000 => 32. w: I5 Z8 g2 _* n$ k+ n% L, Y
- //0xE0000 => 48- g( p2 c- z8 u: A
- //0xF0000 => 64
; n4 W$ ~* d% j6 _0 ?- m - uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
+ P3 O" m$ F$ w, J" B5 v6 J - uint8_t can_dlc2len(uint32_t RxHeader_DataLength)" L4 Q9 |! U" u2 K
- {
. t* P' c0 q. m! l* R - return dlc2len[RxHeader_DataLength>>16];: c* m u* ?8 A. R
- }
( W. V, _" v5 o0 G6 w) k
~; {0 O6 E: m- V7 ]$ H! C- uint8_t cnt = 0;
. o7 o0 |4 x% k7 C0 z) O: {3 N k - uint8_t brs[] = {'-', 'B'};
2 L% ~7 f5 N/ O' g: F5 ` - uint8_t esi[] = {'-', 'E'};% X; Q7 z! Z+ @1 {
- void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) i5 {' l* D' Z$ m) {6 j3 V% d- p6 ]
- {* R1 L! C& C0 B
- if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {
) j1 q6 g6 F3 v! t& q1 I# x4 p1 l - //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);# R2 t% p0 h$ ^- E! U: x5 `3 n& b
- //RxHeader2.Identifier++;8 W2 j/ T: m/ m
- //fdcan2_transmit(RxHeader2.Identifier, RxData2);
0 @6 q' \5 V w. l" w1 j- G - - K# Y8 O3 z/ i- L# e
- //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
8 o/ e# A1 D' Y, ~1 v3 U; E - //memset(&RxHeader1, 0, sizeof(FDCAN_RxHeaderTypeDef));
7 ^: E8 R: I2 Q! y! C - 7 v9 r: u8 M, O6 [0 K1 A
- HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);" q$ }2 f% t% q1 |9 @7 Y
- if (hfdcan->Instance == FDCAN1) {, o- b& ]' o# s0 w7 j
- printf("fdcan1, ");: l% q+ I, t1 k3 T$ x
- } else if (hfdcan->Instance == FDCAN2) {
4 k$ P9 d! B9 }& }, F$ | - printf("fdcan2, ");* j! e1 W' P% I4 q
- } else if (hfdcan->Instance == FDCAN3) {
5 A+ L9 B ~- B" O! |# u; ^ - printf("fdcan3, ");+ u% A5 X2 G1 r. d+ f9 e9 A* h
- }9 X6 [+ K! K4 C4 Y8 |
- printf("0x%8X, %02d, %c, %c:",RxHeader1.Identifier, M9 ~/ p1 n6 Y0 L2 ~$ I% r6 o
- can_dlc2len(RxHeader1.DataLength), 8 z9 d) W) o, v) M0 D$ \
- brs[RxHeader1.BitRateSwitch>>20 & 0x1],
9 V0 I. {; d7 k* J' V2 R: y - esi[RxHeader1.ErrorStateIndicator>>31 & 0x1]);; z* Z9 Y6 v4 |$ t: k3 I: Z
- for(cnt = 0; cnt < can_dlc2len(RxHeader1.DataLength); cnt++) {
/ Q1 f7 e9 l/ W1 v! N0 G# j - printf(" %02X", RxData1[cnt]);0 }$ t! q: p3 Q% w# i, @2 P7 ]
- }8 A- ?) W9 y+ P# ]) p3 e
- printf("\n\r");# g/ y4 o3 _& u4 [# u
- / V8 i( n" f" g; z1 G# J6 k
- 2 R! n; U# K1 \
- //if (hfdcan->Instance == FDCAN1) {7 q: b4 @! }2 e+ i: z2 y
- // HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
/ P, T! b: R6 a) O1 G/ v) Y0 X - // //echo$ k) Y- Y, a, J' t
- // RxHeader1.Identifier++;/ H5 O8 x& R# [! y4 X
- // fdcan1_transmit(RxHeader1.Identifier, RxHeader1.DataLength, RxData1);1 J, _4 m1 l: t6 d S3 ]! n
- //} else if(hfdcan->Instance == FDCAN2) {) T5 G' e1 {4 S, j3 y
- // HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);# Z2 b; u, L7 A
- // //echo
% E5 k. o2 s/ W. s) ` - // RxHeader2.Identifier++;& X, o9 M+ D. n7 y% `
- // fdcan2_transmit(RxHeader2.Identifier, RxHeader2.DataLength, RxData2);
' L, @% n4 f$ a& D, v - //} else if(hfdcan->Instance == FDCAN3) {. |4 W- d) C2 \4 |
- // HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader3, RxData3);
9 E! Q1 S$ r$ j' u - // //echo
/ d4 q! `6 d, D1 Q3 B4 | - // RxHeader3.Identifier++;7 N) G( H$ {( G
- // fdcan3_transmit(RxHeader3.Identifier, RxHeader3.DataLength, RxData3);
0 k# }- h# `3 [. a9 Q8 R; ~ - //} else {
: |& ?9 } y, Y" u) t% [% Y0 w - //
# [; i j" t0 _3 K - //}
& f6 L. q6 q! E, A/ V: k- ~, W8 _# ?- Z L, ^ - }
# u; s! a# t+ a6 @. t3 T) B+ V - }
复制代码
5 G# p* U' _6 B+ h J( z& O+ m注意注释中 RxHeader.DataLength => can_dlc 的对应关系./ F% r4 ?6 p& A# O7 s
7 P2 h* w3 u0 d# Y2 u示例如图:
* G! |) r! m% Z# N) O5 c) {( _7 p4 m% \
/ a. D3 Z# E6 O1 W
3 s2 N4 t+ B6 X" y7 Z9 k图中消息来自fdcan2, can_id为0x18FF0005, 64字节数据, 开启了BRS和ESI, :后面是64字节的十六进制数据.8 s5 r# u$ Q0 x1 N& t" ^
, ?0 u# m/ ~1 y. g; W1 f3 Kprintf还是比较耗时间的, 这里仅做低负载下的演示, 实际使用不建议中断中这么搞.
2 Y8 j/ \9 ~3 r+ w+ a p" \: t
m5 {' }3 X* i; D3 Q F发送处理
3 h( @, O4 O, \& F! X发送开启了BRS和ESI, 如果发送失败, 就延时100us后重发一次.6 G/ Y; U9 R5 t" C
+ ]0 x( c7 L Z2 O$ ~8 e
- #include <string.h>" y3 R% |2 K% b& Y5 \
- 3 e4 ?& R* f& \) F
- FDCAN_TxHeaderTypeDef TxHeader1;: p8 n$ s( _2 p1 O4 _- W/ X: @
- FDCAN_TxHeaderTypeDef TxHeader2;
) ?* Z* v6 S1 {+ | - FDCAN_TxHeaderTypeDef TxHeader3;
6 X/ d+ U# e* o/ p7 h# ]' B0 o
7 {' P0 {+ W2 T6 F8 @' ~' v- typedef struct {' ?% c' U. F. y/ p9 `5 X
- uint8_t flag;
0 c# g0 |( G9 k& `' P# m - FDCAN_TxHeaderTypeDef TxHeader;( ^: n- D) ?! h8 }- W7 L
- uint8_t TxData[64];
: a& S: x2 [& k- d3 W - } FDCAN_SendFailTypeDef;/ K) m, N& `0 p
- & L1 ~' ?# R% [ g9 B' k3 c
- FDCAN_SendFailTypeDef fdcan1_send_fail = {0};& ~' I! t9 Y2 c3 H9 ~+ u9 B, r9 b
- FDCAN_SendFailTypeDef fdcan2_send_fail = {0};# E8 I9 P3 r) U% }( W6 R
- FDCAN_SendFailTypeDef fdcan3_send_fail = {0};5 u. D3 A0 {& o- J5 \
- - w1 {( c p4 K" l
- void fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])
: o8 Z3 c; R9 E* [; x - {) H# P7 L( y s2 i; T) I7 Z% w
- TxHeader1.Identifier = can_id;
5 q5 p9 a9 g* T/ e$ _$ O - TxHeader1.IdType = FDCAN_EXTENDED_ID;2 R" R4 g' ~& w3 q/ T
- if(can_id < 0x800) { //exactly not right
" r" N* G x3 R, {7 z6 _; P, f - TxHeader1.IdType = FDCAN_STANDARD_ID;- |& {, {2 r7 Y7 J# |9 Z7 N
- }
0 a( c. x- `- N: r3 _ - TxHeader1.TxFrameType = FDCAN_DATA_FRAME;% v; t8 N: D( m6 M
- TxHeader1.DataLength = DataLength;
% G0 ~3 J0 @" r9 g - TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;8 W/ j' \8 H/ N+ V) k0 b
- TxHeader1.BitRateSwitch = FDCAN_BRS_ON;
3 \6 ^( {8 A+ ~2 } l0 f - TxHeader1.FDFormat = FDCAN_FD_CAN;
, D7 Q1 h0 T* q; R$ N) U4 R; f - TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS; R# ^3 N6 u# U( n
- TxHeader1.MessageMarker = 0; //marker++; //Tx Event FIFO Use
" o, S+ i: i- P' w& D1 o, ]/ h5 t - if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {
1 P; A4 A: q" w' ] - fdcan1_send_fail.flag = 1;/ s: s8 J. d& t8 u" W& x+ @
- memcpy(&fdcan1_send_fail.TxHeader, &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));8 K" a, d( _& O0 V$ I3 U7 \
- memcpy(fdcan1_send_fail.TxData, tx_data, can_dlc2len(DataLength));( F$ j8 t- d2 I1 |4 {7 L N2 s
- }
$ ^" c6 o k* j9 i - }- I9 |- y- M0 r
- 9 t* r Q0 r6 L
- int main(void)2 L2 S* e2 l( h7 a2 C
- {( {: P R! y, F' l1 ?
- ...
0 d* n8 l% C1 Q! \5 s; a - /* USER CODE BEGIN 2 */
' o' i: M' J0 X; `7 {1 d" v8 z - fdcan1_config();% `7 V) ]/ d; y/ c+ B+ v0 G% y) s
- fdcan2_config();
: x, y% q7 `- n" ]% l, F6 A - fdcan3_config();
0 v# k& P1 M8 S - ( U3 H' x6 l4 n( Y8 V
- for(uint8_t i = 0; i < 64; i++) {
0 a M: `6 y, L+ i' c" ? - TxData1<i> = i;</i>
/ J$ s$ y: k V8 f# o: Q G+ F4 H, | - <i> TxData2 = i;</i>
! C6 y; Y5 w I6 Z# D3 Y0 d4 k - <i> TxData3</i><i> = i;
, b' [( U# I3 R - }
4 n7 d- \7 u. ]2 i5 E
N4 U& g6 S" g: {1 `- HAL_TIM_Base_Start_IT(&htim6);# a) t* c8 q4 h) k
- </i>uint32_t count = 0;1 G5 |! w) c' C9 n
- uint32_t cnt_100us = 0;
- t# A3 }/ G2 D3 u {9 L! P, V: a; ? - uint32_t cnt_500us = 0;2 _, v' j3 h& G3 r B
- /* USER CODE END 2 */# C$ c) V1 n0 i3 g
' o1 {8 g' ^4 M! Z- /* Infinite loop */
$ S+ c+ Q- c/ k& f - /* USER CODE BEGIN WHILE */
6 H a+ I2 j! V$ X j - while (1)
1 }. K* ^- v0 D' w - {/ Z( B i4 p4 F/ h3 ^
- /* USER CODE END WHILE */0 k0 H7 t+ A) A& [+ N
3 Q) ~: w# K$ O0 z) i7 b/ k/ Z8 Z" { u- /* USER CODE BEGIN 3 */( f$ H7 S, \6 }) ]+ l: l5 D& x
- if(tim6_flag && count < 1000) {
( t0 q# V" S* }5 y) ~ - tim6_flag = 0;. }! H+ D* D' }* r* P
- TxData1[0] = count >> 8 & 0xFF;7 [* V0 a' o$ J4 @
- TxData1[1] = count & 0xFF;# T$ k/ N* |; h2 |
7 @* n$ p' D/ N A- ++cnt_100us;- F( v) o' \7 v4 K* F# `
- cnt_500us = cnt_100us / 5;/ }2 ]* r2 L0 t E. y0 `$ l
- if(cnt_500us && (cnt_100us%5==0) ) {
* I+ B( H+ _. ~6 K - switch(cnt_500us) {' T; i7 L5 t9 N% K$ _; ]- M2 Y
- case 1: fdcan1_transmit(0x123, FDCAN_DLC_BYTES_64, TxData1); * b+ ^! s. u& g" i R6 ?8 `9 q$ N
- fdcan1_transmit(0x124, FDCAN_DLC_BYTES_64, TxData1);
" B- J1 K7 Y8 R" } - fdcan1_transmit(0x125, FDCAN_DLC_BYTES_64, TxData1); break;! R/ h; o* J/ K3 ^( O
- case 4: fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1); break;
) o4 K, G- `/ X* G/ W& Z- } - case 5: fdcan1_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData1); break;
9 O2 q* V4 a3 W1 z- y1 [- E+ o - case 6: fdcan1_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData1); break;
- Z5 F& Q- E) \5 H - case 7: /* next send */ break;
. G% j, C' ~ F7 s% D( S - case 8: break;
, S1 N* H; |$ B3 [+ a3 L( i' L - case 20: ++count; cnt_100us = 0; break; //10ms$ \! a' S3 S! e3 F, m6 j
- }
. E i% o0 o- j0 U( y& t - } else { //fail retransmission once( |3 s1 @; ]: E/ }7 p. s4 ?
- if(fdcan1_send_fail.flag) {' N) ~2 Z$ h' l4 g
- fdcan1_transmit(fdcan1_send_fail.TxHeader.Identifier, 4 v; T6 J( X/ i+ {$ R: h
- fdcan1_send_fail.TxHeader.DataLength,
- ]' b) K6 c) V7 H - fdcan1_send_fail.TxData);9 j( p: B8 K" P! S- }. \. W
- fdcan1_send_fail.flag = 0;! e% V" w8 }1 B6 N/ M0 d5 C
- }
' _9 Y* J% M1 g! d5 z8 J - if(fdcan2_send_fail.flag) {
7 @- o- B! Y! W9 N# U& o! n2 u' i - fdcan2_transmit(fdcan2_send_fail.TxHeader.Identifier, 4 P5 j* w& U* m; U% e' H! |: r
- fdcan2_send_fail.TxHeader.DataLength,
W$ R/ m$ ~7 j( e - fdcan2_send_fail.TxData);
8 J5 J B# u: U4 x% M' |' i3 Y7 y - fdcan2_send_fail.flag = 0;1 K( ?' _& k: q- O# s) n3 Y' r8 t# W1 x
- }1 g h" U) z) o( u# y$ ^3 Y# S
- if(fdcan3_send_fail.flag) {
, j3 ? l- `2 B9 n - fdcan3_transmit(fdcan3_send_fail.TxHeader.Identifier,
; }6 E& I! B A! x - fdcan3_send_fail.TxHeader.DataLength,
1 q- a) @' A% \5 n7 S' \7 E) w! a - fdcan3_send_fail.TxData);( P+ R/ ]* R4 y2 E
- fdcan3_send_fail.flag = 0;) C1 w1 U7 Q/ M
- }$ E2 _$ u0 S4 _: t9 [
- }
4 H. D8 l, l4 j7 S - }. D( p- o, b' Y. v# m& a5 i
- }5 W. k2 x* r$ j9 A( j+ w9 N
- /* USER CODE END 3 */
2 P- A" n! J: {6 G, Y( M3 P- y7 I - }
复制代码
: \4 ?* ~6 l6 A+ Q; \/ {fdcan2, fdcan3和fdcan1的发送类似, 3个发送函数可以合并成一个, 这里没有合并.
! }9 U' J1 |5 A% Q4 U, X# E4 H% X! R# C8 ]$ c' c& V, H
发送函数中的DataLength指的是类似FDCAN_DLC_BYTES_64这种的宏定义, 而不是数字64.
- t; W* X3 O2 k1 Q! Y% a, v0 r3 v
8 `1 ?& e: \% } @% R) S这里用can_id < 0x800只是为了简便, 其实不正确, 这种情况下也有可能是扩展帧, 但通常不会这么用.$ n; b7 s3 G/ @' X, ?: `( ]
+ F5 g8 q! Y4 b! m因为发送最多可以缓存3帧, 所以可以一口气发送3帧, 如case 1处, 也可以一帧一帧发送, 如case 4, case 5, case 6. 这里是1.5ms/3帧或者500us/帧., ?) p% P; v2 G. b, n. F
4 E& {8 {. v# Y0 B
因为总线中还有其他节点发送之类的, 有可能发送失败, 这里留了一次发送失败后延时100us重传的机会, 具体情况根据现场可另行调整.
9 n5 ~: \9 Q: f" c0 B/ c4 Z: L
0 z, t/ D5 z- `: \( A如果fdcan1, fdcan2, fdcan3没有在一个网络中, 可以一口气 fdcan1发送3帧 + fdcan2发送3帧 + fdcan3发送3帧.
9 @: \, `* z& y6 k6 T; W8 t8 p5 ~& l) p% O
一般车辆总线中发送都是最快10ms内把要发的不同ID的数据一股脑发出去(当然也有20ms, 50ms, 100ms周期的数据这里暂不考虑), 所以这里100us中断计数100次就是10ms.
z& }: y6 u$ u
1 \+ e1 k7 V% m* L# g- I5 V程序中发送1000*6=6000帧后停止发送, 10ms发6帧, 所以10s后数据就发完了.) x# y2 p/ b: a0 X* ?; A
; k) Q T* j8 c0 U使用Xavier配合测试一下
4 A" f) p3 J5 S7 ~% ^把STM32的FDCAN1连到Xavier的CAN1上, Xavier CAN1设置:
5 v9 j0 U% i b6 q4 y9 ~4 P+ O, P2 j4 t9 [5 X* q
- #!/bin/sh
1 N, x2 j5 p+ j7 z! }
6 ~2 n% _$ {9 t* J- sudo modprobe can
) j+ U3 `% c" d# e - sudo modprobe can_raw# `0 |0 [* O! k+ k$ v$ { P
- sudo modprobe mttcan
: V4 S5 d) w4 g: P% t: s2 ^ - * M4 l+ Z1 x" l. J, z1 V/ _6 {7 ^
- sudo ip link set down can0/ w( b$ Z* E" t* Y, @7 R t
- sudo ip link set can0 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 100
7 V9 r: H6 A) J# Y% L! l - sudo ip link set up can0
1 A7 @6 H' ~+ `8 J - sudo ifconfig can0 txqueuelen 1000
- Z7 q% G( ^: g0 n1 k( _* }. i3 C
0 n( K" U0 m7 W' E2 Y- sudo ip link set down can1; Z7 k- _# G2 g1 H: z3 N0 p9 O7 C
- sudo ip link set can1 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 100
! s3 L: v9 _/ k2 K/ c( I' x/ [3 n - sudo ip link set up can1
( q' h1 }" j' W# }& J4 s) B - sudo ifconfig can1 txqueuelen 1000
复制代码 Xavier也是仲裁段500Kbit/s, 采样点0.8, 数据段2Mbit/s, 采样点0.75.
" j5 {8 u+ Q' g9 B8 v. S4 h
$ h1 N* K1 G- D4 G) g5 m6 ~( jrestart-ms 100设置总线Bus-Off时, 100ms后重启.5 ?- p. t0 X- \7 X" z& {% p
) y4 U9 \; D2 |4 v) H0 y; K: m; s, E
设置完后查看设置状态 ip -details -statistics link show can1:, d4 S5 ]! @4 W+ L
9 ?0 I. z# l1 I: E2 M! g- $ ip -details -statistics link show can14 P1 i1 U9 y2 T U" B
- 6: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
, }' }) }" R! v' S* O - link/can promiscuity 0
! w8 L- |7 }* q! h7 O - can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100 9 \' V' d' k' a7 }
- bitrate 498701 sample-point 0.792 . Z2 X7 N, Z; H. ?% D1 u2 ]
- tq 26 prop-seg 30 phase-seg1 30 phase-seg2 16 sjw 1
- X E( L2 v$ e - mttcan: tseg1 2..255 tseg2 0..127 sjw 1..127 brp 1..511 brp-inc 1
8 E' g8 E" A' @" E% O! J; @ - dbitrate 2021052 dsample-point 0.736
! p5 g" `6 K# _/ c- A/ J; ?# S6 z - dtq 26 dprop-seg 6 dphase-seg1 7 dphase-seg2 5 dsjw 1: A& w/ G/ }7 k. S" o
- mttcan: dtseg1 1..31 dtseg2 0..15 dsjw 1..15 dbrp 1..15 dbrp-inc 1
7 X8 o/ k9 M& o& `0 j+ u - clock 384000001 J5 D; D# {+ d1 p! A
- re-started bus-errors arbit-lost error-warn error-pass bus-off
5 n, R$ X9 w) q8 P: [ - 0 0 0 13 20 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 1 K) x8 _1 r k
- RX: bytes packets errors dropped overrun mcast
1 x2 ^! k7 d+ D$ K- P( ?% k - 64578440 1013451 0 0 0 0 / c' Q/ T0 w g8 v
- TX: bytes packets errors dropped carrier collsns # ?; d! `( ]* M2 v0 ]0 |: d% ~; s
- 952448 15914 0 0 0 0
复制代码 位速率和采样点的些许误差测试并无影响.- d2 H7 g- f! v# F/ X, \
( \& t9 {1 H, E# G' b3 p7 d+ m" I1 J使用 candump -ta -x can1 >24.dat, 这里-ta显示绝对时间, 然后下载STM32程序运行, 上面的6000帧数据全部存到24.dat文件中了, 共计6000行, 这里截取首尾部分显示:" Q! o: r& k$ W: X! M0 i$ d% |
4 E, w- E+ r2 E& d2 J8 k
- (1613988959.105805) can1 RX B - 123 [64] 00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F7 M+ b5 q z' d5 E
- (1613988959.106191) can1 RX B - 124 [64] 00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
& J0 x( E+ b% [% F4 q6 ]( N; F - (1613988959.106609) can1 RX B - 125 [64] 00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ e/ X) a% O/ U6 |( d - (1613988959.107337) can1 RX B - 12345678 [64] 00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F. O; |7 N5 a* V5 Z; m! `
- (1613988959.107865) can1 RX B - 12345679 [64] 00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
?$ y5 C$ W. L" ?# {) c - (1613988959.108332) can1 RX B - 1234567A [64] 00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
, j! E3 b+ L3 C' i5 o! j - (1613988959.115791) can1 RX B - 123 [64] 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F# U0 P9 z& h( l
- (1613988959.116215) can1 RX B - 124 [64] 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F1 F! u; F6 ^" k& |' T
- 7 V" B4 c, ^% l( f1 p0 p
- ...
Q; x) j9 u6 c4 {
$ O6 e" M3 T" E8 R# F- (1613988969.087131) can1 RX B E 12345678 [64] 03 E6 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F" N h, a4 i4 r* p \$ o
- (1613988969.087612) can1 RX B E 12345679 [64] 03 E6 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
( |! N+ u% D! j* f) f& m7 K - (1613988969.088160) can1 RX B E 1234567A [64] 03 E6 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
2 }: _ I/ j0 | - (1613988969.095802) can1 RX B E 123 [64] 03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F0 ?$ `, D& \5 L
- (1613988969.095935) can1 RX B E 124 [64] 03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F0 a$ ?4 \$ i) ` m0 p: A
- (1613988969.096294) can1 RX B E 125 [64] 03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F* T8 ^. Z M: \8 y6 @" U
- (1613988969.097116) can1 RX B E 12345678 [64] 03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F0 {$ q- B6 A2 J$ ?
- (1613988969.097604) can1 RX B E 12345679 [64] 03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F1 I8 g6 ~4 `3 i4 ]6 E! Y$ h- W
- (1613988969.098102) can1 RX B E 1234567A [64] 03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
复制代码
, m. P# ]% w& P) \) e这里前三行的格式问题, ESI的404行之前是-, 404行及以后是E, 暂时不解. 其它正常, ID顺序和数据都对得上.
0 A; _$ E+ |# s4 w$ ^
+ a5 l/ R7 y: fXavier发送脚本, ##后面的3表示开启BRS和ESI: p& ~& c! _# u7 O# V0 Q& f
% Y8 k* O0 H' x+ R G" {
- #!/bin/sh4 p( D, o3 {8 `* c0 l$ D
- 1 i3 \8 Q/ @+ q$ R) ?
- while true; do5 @! ~* L/ ?' E- h+ G* B
- cansend can1 18FF0001##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
# U) a6 H7 U9 N - cansend can1 18FF0002##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
" E7 W) V: }2 ^# ? L3 |$ k - cansend can1 18FF0003##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
4 H8 b" ~( J( w. ~ - cansend can1 18FF0004##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
. _+ u1 G8 l( S- X; \: ?( [ - cansend can1 18FF0005##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
! M# \* R# J! d6 P' O+ f - cansend can1 18FF0006##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16 7 T8 l. H6 O* C& x" s" `% z
- sleep 0.01
" a! c) q! o; T9 a3 P2 P# I7 W - done
复制代码
3 k& f% U$ ^7 S8 t& X2 F可以在LPUART1串口中看到收到的数据, 如上面 新消息接收处理 小节配图.
/ j4 K2 J- \# H1 b: g1 \# J4 O2 Y, m( m6 x1 ?
核心思想是:
5 x* h. [( S; R
6 c* o9 d. K" i& LMode 设置为Classic Master或者Classic Slave, 而不是FD" p* N6 d/ Z/ Y
仲裁段和数据段的通信速率都设置为500Kbit/s& M L/ S& c( b% e, [
* I1 j' u" y7 `& b4 a7 K5 y
- c- F- o1 r& _5 h
; O! |% s' s$ B# r( z& Z' I |