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