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