语言
English English Vietnamese (Tiếng Việt) Vietnamese (Tiếng Việt) Chinese (简体中文) Chinese (简体中文) Portuguese (Brazil) (Português do Brasil) Portuguese (Brazil) (Português do Brasil) Spanish (Español) Spanish (Español) Indonesian (Bahasa Indonesia) Indonesian (Bahasa Indonesia)

把 UART、SPI、I²C 或 CAN 抓包里的比特数除以 8,读出固件缓冲区真正要存放的字节数,帧开销也一并算清楚。

把总线上的比特换成缓冲区里的字节

用逻辑分析仪去夹 UART、SPI、I²C 或 CAN 的信号线时,抓到的波形是按比特计的。可固件这一侧全是字节:64 个表项的接收缓冲区、12 个寄存器的映射表、上限 8 字节的数据场。每次在这两种视角之间来回,其实就是在除以 8;而凌晨三点盯着一帧校验失败的报文心算这个数,正是差一错误被带进量产版本的典型场景。

换算系数:字节 = 比特 ÷ 8(等同于 比特 × 0.125)。一帧 108 比特的 CAN 2.0A 报文是 108 ÷ 8 = 13.5 字节的纯线上时间——其中只有 8 字节是你的数据。

除法本身没什么难度,真正让人栽跟头的是:你刚才数的到底是哪一批比特。一个字节的应用数据,几乎从来不会在物理链路上刚好占八个比特时间,因为成帧、同步和检错都要在同一根线上分走位置。

线上比特与载荷比特

示波器把线上每一次跳变都算进去,包含起始位、停止位、校验位和填充位。这些数除以 8,得到的是折成字节的线路占用时间,而不是单片机会存下来的字节数。

寄存器位宽

数据手册描述外设时用的是位:12 位 ADC 结果、24 位累加器、40 位传感器采样。换成字节,才知道每次读取实际要占几个缓冲槽、要垫多少填充。

时序预算

中断延迟和 DMA 长度都要看比特时间。把一次突发传输的比特数换成字节,就知道下一帧到来之前 FIFO 能不能排空。

一步步换算一次抓包结果

1

先想清楚你数的是哪种比特

先确定你要数的是载荷位,还是分析仪看到的每一个位。对一个 8N1 的 UART 字节来说,这两个答案分别是 8 和 10——同一个问题,两种结果。

2

把比特数填进去

在比特一侧输入数值,字节结果随打随变,整帧拆解可以一路看下来,不用按任何按钮。解码器导出的长数据常带空格或用逗号当小数点,两种写法都能识别,空格会被直接忽略。

3

把数字直接复制进代码

每个输入框的复制按钮给出的是不带单位、不带空格的纯数字,正好适合塞进 #define、缓冲区长度或一条测试断言。

4

回到示波器时把方向调过来

按交换单位按钮就能从字节反推比特——已知载荷是 32 字节、想知道它在线上要占多少比特时间时很好用。两个单位菜单都支持搜索,不离开本页也能跳到千比特或每秒字节数。

UART 成帧开销:从波特率到每秒有效字节数

经典的 8N1 配置给每个数据字节套上一个起始位和一个停止位,于是十个比特时间只送出八位载荷——固定 25 % 的开销。这就是为什么「波特率除以 8」这种粗算法,永远会把链路的真实吞吐说高了。

波特率(bit/s) 粗算比特 ÷ 8 实际载荷(8N1,每字节 10 位) 一个字节耗时
9 6001 200 B/s960 B/s1 042 µs
19 2002 400 B/s1 920 B/s521 µs
38 4004 800 B/s3 840 B/s260 µs
57 6007 200 B/s5 760 B/s174 µs
115 20014 400 B/s11 520 B/s86.8 µs
921 600115 200 B/s92 160 B/s10.9 µs

再加一位校验,一帧就变成十一个比特时间,9 600 波特下的载荷掉到大约每秒 873 字节。用两位停止位又要再让出一格。这些都不改变 ÷8 这条算式——它们改变的是你该往里面填多少比特。

对比不同帧格式时两栏都是活的

在任意一栏输入,另一栏立刻跟上,于是你可以一手拿着载荷数、一手拿着线上时间数来回比对,不用反复重输。

长突发的结果依然读得清

千位之间用空格分隔,特别大的抓包量会切到科学计数法,几百万比特的波形记录也不会变成一堵数字墙。

总线常用单位都在一个下拉菜单里

可搜索的单位菜单涵盖比特、千比特、字节以及各种每秒速率单位,CAN、SPI 或 UART 的数据换个说法就行,不必再翻别的页面。

数据不出实验台

页面加载完之后,所有算术都在浏览器里完成,从客户抓包里抠出来的数字不会被传到任何地方。

串行协议相关问题

9 600 波特的链路为什么每秒只走 960 字节,而不是 1 200 字节?

因为波特数的是线上的符号,不是载荷位。标准的二进制 UART 一个符号就是一个位,所以 9 600 波特等于每秒 9 600 个比特时间——但在 8N1 成帧下,每个数据字节要吃掉其中十个。除以 8 得到的 1 200 B/s,是假设线上只跑数据的理论值;除以 10 得到的 960 B/s,才是应用层真正收到的量。

起始位、停止位和校验位各占多少?

起始位是一个下降沿,用来通知接收端开始采样;停止位把线路拉回空闲态,保证下一个起始沿不会被误判。两者都不携带信息。校验位启用后会在数据位旁边再加一位,纯粹用于单比特错误检测。所以一帧 8E1 是 11 个比特时间——一个字节的载荷,占掉 1.375 个字节当量的线路时间。

先发高位还是先发低位,会影响换出来的字节数吗?

不会——两种顺序数出来完全一样,只是拼出来的数值不同。UART 是低位先出,SPI 和 I²C 习惯上高位先出。搞混之后得到的是位序颠倒的字节,占用的比特时间一个不多一个不少,所以症状看起来像数据损坏,而不像长度对不上。

CAN 的位填充会怎样改变比特与字节的关系?

CAN 在连续五个相同电平之后会插入一个相反的位,好让各接收节点保持时钟同步。一帧 11 位标识符、载荷占满 8 字节的标准报文,填充前是 108 比特,最坏情况下可以涨到大约 135 比特。多出来的都是纯线路时间:不管收发器插了多少填充位,你的载荷始终是 8 字节。

解码器导出的突发长度是比特数,怎么跟接收缓冲区对比?

用帧长去除,而不是用 8 去除,再拿得到的字节数跟缓冲区深度比。12 000 比特的突发在 8N1 下是 1 200 帧,因此需要 1 200 字节的空间;而 12 000 ÷ 8 = 1 500 这个原始数字描述的是线路占用。把错的那个喂进 FIFO 容量计算,是溢出标志莫名其妙被置位的常见原因。

b
B

串口帧长度对照

8 比特(仅有效载荷)=1 B
10 比特(8N1 帧)=1.25 B
11 比特(8E1 帧)=1.375 B
64 比特(CAN 数据场)=8 B
108 比特(CAN 2.0A 帧)=13.5 B
9 600 比特(9 600 波特下 1 秒)=1 200 B

比特(b)

总线上的一个比特时间。115 200 波特下一个比特持续 8.68 µs,分析仪画出来的起始沿、停止电平、填充位,都是按它计数的。

字节(B)

八个有效载荷位,也是单片机真正存下来的单位:一个 FIFO 槽位、一条寄存器映射表项、CAN 八字节数据场里的一个元素。

填入分析仪读到的总比特时间,而不只是数据位——8N1 每个字节要占 10 个比特时间
每个输入框上的复制按钮只给纯数字,可直接粘进 #define 或缓冲区长度
已知载荷是多少字节、想反推线上长度时,点交换单位反着算
两个单位菜单都支持搜索,千比特或每秒字节数一敲即到
想了解更多? 阅读文档 →
1/5
开始输入以搜索...
搜索中...
未找到结果
请尝试使用不同的关键词搜索