☰
WaveDrom Editor win-x64:用JSON生成可diff时序图
2026/10/27 6:28:37 网站建设 项目流程

简介:Wavedrom Editor v2.3.2 的 Windows 64 位离线安装包,面向 FPGA 开发者、电子工程师以及需要绘制数字信号时序图的硬件学习者。它把通常依赖在线网页的时序图编辑器搬到本地,可缓解官网访问不畅、无网络环境下难以出图的问题。

压缩包共 124 个文件、约 83.72MB:主体是 56 个 pak 与 53 个 info 资源文件,另有 9 个 dll 动态库、2 个 exe 主程序及 bin、dat、html 等运行依赖,属常见的桌面封装结构,解压即可启动,不必另行配置环境。

工具以简洁文本语法描述波形,涵盖上升沿、下降沿、高低电平、脉冲等元素,支持注释、标签与配色,输入即实时预览,成图可导出 SVG、PNG,或复制代码嵌入文档与网页。已有 2170 人学习下载,适合需要长期稳定积累时序图素材的读者。

1. wavedrom-editor-v2.3.2-win-x64.zip 不是画图软件:它把时序图变成了可 diff 的 JSON

拿到 wavedrom-editor-v2.3.2-win-x64.zip 的人,十有八九不是闲着没事。多半是手里正攥着要写进接口文档的一张时序图:SPI 的建立保持时间、总线的握手窗口、某个器件的上电时序。用绘图软件拖半小时,改一个时钟周期就得整张重画,改完还得对着数据手册一格一格数。

WaveDrom 把这事倒过来做:你用一段 JSON 描述信号名、波形字符串和数据内容,它渲染成矢量图,改周期只改一个字符。这个 zip 是 Windows 64 位桌面版,解压即用,左边写 JSON 右边实时预览,不用装运行环境。适合三类人:写数据手册和协议文档的、做时序验证要出图的、给同组讲清楚某个握手到底差几拍的。下面从解压开始,一路讲到把几十张图变成能跟着代码一起 review 的资产。

2. 解压到能跑:win-x64 桌面包里有什么、首次启动查哪三件事

2.1 目录里哪些能删、哪些动了就起不来

这类桌面包基本都是同一个套路:一个主程序 exe,加一个装着界面和渲染核心的资源目录,再配一堆 Chromium 运行时文件。所以它不挑机器有没有装 Node,也不写注册表,扔 U 盘里拷走就能用——这是优点,也是坑的来源:很多人一看“绿色免安装”,顺手就把自认为没用的文件清了。

条目作用能不能动
与产品同名的主 exe启动入口,双击它不能改名,改名后资源目录的相对路径会失效
资源目录(界面与渲染核心一般压在单个归档文件里)编辑器前端 + 渲染逻辑不能改,改完启动即退
一批 .dll 运行时文件图形、网络、本地存储等底层库一个都不能删
locales 之类语言包目录界面本地化只留中文和英文可以,其余删掉通常无碍
许可与第三方声明合规材料对外发文档、截图前建议留着

血泪经验是:网上流传的“单文件精简版”“只有 exe 的版本”一律别碰。渲染核心不在 exe 里,它一定在资源目录里,砍掉之后最常见的结果是双击闪一下就没,连报错窗口都不给你,黑匣子一样。

2.2 首次启动前的三步:校验哈希、换纯英文路径、解除网络锁定

从下载目录直接双击 exe 试运行,是新手最容易翻车的一步。压缩包内双击时,系统会把内容临时解到一个带随机名的目录,工作目录不可预期,配置写不进去——你改完图点保存,转头发现文件根本没落地。

# 1) 先算一次哈希,和发布方给出的值逐位比对,确认包没下崩、没被人塞东西 Get-FileHash .\wavedrom-editor-v2.3.2-win-x64.zip -Algorithm SHA256 # 2) 解压到短、纯英文、无空格的目录;路径越长越容易撞上资源加载的长度限制 Expand-Archive -Path .\wavedrom-editor-v2.3.2-win-x64.zip -DestinationPath D:\tools\wavedrom # 3) 解除"来自网络"的锁定标记,否则部分机器上首次运行会静默退出 Get-ChildItem D:\tools\wavedrom -Recurse -Include *.exe,*.dll | Unblock-File

第一条命令输出一串十六进制,重点不是记住它,而是养成“先比对再运行”的习惯。第二条里的目标路径建议就按这个格式来:盘符加一级目录,别用D:\工作\项目\时序图\工具\这种,中文加长路径在这类运行时上是老问题。第三条解决的是 Windows 给下载文件打的标记,Unblock-File把它清掉,只对当次下载的文件有效,重下一次得再跑一遍。

注意:如果机器上有安全软件拦启动,不要关防护了事。先把整个目录加到信任列表,再启动,这样出问题时能分清是软件本身的问题还是被拦了。

2.3 界面里真正天天用的四块区域

打开之后界面非常朴素,能用的就是四块:左边编辑区、右边预览区、文件菜单、导出菜单。没有模板库,没有拖拽元件,也不会有“新手引导”。这种朴素是有意的——它假设你知道自己要画什么,只负责把 JSON 变成图。

左边编辑区有语法高亮但没有严格语法检查。JSON 少一个逗号、多一个尾逗号、用了单引号、中间插了 // 注释,右侧预览就是一片白,且不告诉你错在哪。这就是后面避坑章第一条要展开的事。

文件菜单负责打开和保存,导出现在通常是 SVG 和 PNG 两条路。这里有个小习惯值得早养成:所有图存成.json后缀,别存.txt也别存.wavedrom。因为到了第 6 章要批量跑脚本时,筛文件的依据就是后缀,前期随手存的名字越乱,后期改得越痛苦。

3. WaveJSON 骨架:一条 lane、一个 wave 字符、一排 tick 怎么对应

3.1 最小可渲染结构:一个 signal 数组就出图

{ "signal": [ { "name": "clk", "wave": "p...." }, { "name": "req", "wave": "0.1.." }, { "name": "ack", "wave": "0..1." } ] }

这段贴进编辑区,右边立刻出现三条波形。signal是数组,数组的每个元素对应图上的一行(业界习惯叫一条 lane),数组顺序就是从上到下的行序,别指望它自动排序。name是左侧的标签文字,渲染器不会替你加单位,所以想写sclk (10MHz)就把单位一起写进字符串。

wave是这条 lane 的字符序列,一个字符占一个时间格。三条 lane 的时间格是共享的,同一列字符在图上落在同一竖直位置——这是整张图能对齐的唯一依据。所以写的时候不要一行写完再写下一行,先在纸上数好一共几格,再每行按同一个格数填。

3.2 wave 字符串里每个字符干了什么

字符画出来的样子典型用途
0低电平实线片选拉低、复位有效
1高电平实线复位释放、空闲态
x灰色填充的不定态总线没人驱动
z中间一条细线(高阻)三态总线释放
.延续前一字符的状态拉长一段电平
=蓝色数据块通用数据总线
2到9不同颜色的数据块一张图里区分多组数据
p正相时钟,一格一个周期,前半高后半低主时钟
n反相时钟,前半低后半高下降沿采样的器件
P/N占空比不同的时钟版本需要窄脉冲外观时
``断开,画面上留一条缝

最需要说清的是p。很多人第一次画时钟会用010101手动拼,短图看不出问题,一旦要把 8 个时钟改成 12 个,整行得重排,还得数着别错位。p是渲染器内置的时钟语义,一个字符就是一个完整周期,改周期数量就是加几个.,永远不会相位错乱。

顺带一个容易忽略的点:x和z不是装饰。协议文档里“从设备还没接管总线”这段,用z表达比画一条低电平更准确,评审时也没人会问你“这里到底是 0 还是没人驱动”。

3.3 data、period、phase:让总线标签和时钟对齐

{ "signal": [ { "name": "sclk", "wave": "p........" }, { "name": "mosi", "wave": "=..=..=.", "data": ["A7:A0", "D7:D0", "CRC"] }, { "name": "cs_n", "wave": "1..0....", "period": 2 } ], "config": { "hscale": 2 } }

三个参数各有各的责任,混用就会画歪:

  • data:数组长度必须和这条 lane 里数据符号(=或2~9)的个数严格相等。多一个少一个,标签就整体错位,从第二个框开始全部串位。这是最高频的翻车点,没有之一。
  • period:这条 lane 上一个字符代表多少时间格,默认 1。写2就是一个字符顶两格,专门用来让 CS、复位这类慢信号和高速时钟共处一张图,否则慢信号要么占满屏,要么短得看不清。
  • phase:整条 lane 右移多少格,可以是小数,0.5就是半格。时钟上升沿要落在数据中间的那种“教科书观感”,就是靠它微调的。
  • config.hscale:横向整体缩放,1是默认,2拉宽一倍。它影响的是出图尺寸,不改变任何语义。

提示:period和phase写在信号对象里,只影响那一条 lane;写在顶层就是全局默认。改完一定看预览,别只看 JSON 觉得对。

3.4 node 和 edge:把“建立保持时间”从文字注释变成箭头

{ "signal": [ { "name": "sclk", "wave": "p...p...", "node": ".a..b..." }, { "name": "mosi", "wave": "=.=.=...", "data": ["D0", "D1", "D2"], "node": "..c.d..." } ], "edge": ["a~>c t_su", "d~>b t_h"] }

node里的小写字母是在 wave 上打标记点,字母所在的那一格等价于.,波形照常延续,lane 总长度不变。edge里用~>画一条带箭头的连线,箭头后面跟标签文字,中间用空格隔开。

这个组合是 WaveDrom 相对绘图软件最大的优势:t_su不是画上去的装饰,它绑定在两个具体的时间点上。哪天时钟从 8 拍改成 10 拍,只要把信号位置挪对,箭头会自动跟着走,不会出现“箭头还指着老位置”的尴尬图。

注意字母不要和数字2~9混着用,数据符号会被当成数据块,两者语义完全不同。

4. 画一张 SPI 读时序:从空文件到能进数据手册的 SVG

4.1 先把时间轴定死,再动笔

动手写 JSON 之前,先在纸上定两件事:这张图一共几拍,每拍上发生什么。以一次 8 时钟的 SPI 读为例,规划是:第 1 拍 CS 拉低,第 2 到第 9 拍传输 8 个时钟,第 10 拍 CS 拉高。这个数字定下来,每条 lane 的字符数就定了,后面只是填空题。

刻度数字用head和foot控制:

{ "head": { "text": "SPI Mode 0 read, 8 clocks", "tick": 0 }, "foot": { "text": "1 tick = 1 SCLK period", "tock": 2 }, "config": { "hscale": 2 } }

head.tick是刻度的起始数字,写0就是从左起第 0 格开始标;foot.tock是刻度间隔,写2就是每两格标一个数字。图上要不要标刻度看用途:给软件同事对齐寄存器读写用,标上;纯示意性的框图,省掉更干净。

4.2 四条 lane 拼起来

{ "head": { "text": "SPI Mode 0 read", "tick": 0 }, "signal": [ { "name": "cs_n", "wave": "10.......1" }, { "name": "sclk", "wave": "0p.......0" }, { "name": "mosi", "wave": "x=..=..=..x", "data": ["cmd", "addr", "dummy"] }, { "name": "miso", "wave": "z..=..=..=z", "data": ["0x00", "0x5A", "0xA5"] } ], "config": { "hscale": 2 } }

逐行看:cs_n第 0 格高、第 1 格落到低、中间 8 格延续、最后一格回高。sclk前面一格压住,中间用p走 8 个周期。mosi首尾用z表示器件还没接管,中间三段数据块。miso同理,只是数据内容不同。

写完如果发现miso最后一个数据框比上面几行短一截,那就是两条 lane 字符数不一致,短的那条后面留白,视觉上像被拉伸——这是避坑章第二条要讲的事。

提示:模式 0 和模式 3 的区别在时钟极性,图上体现为p还是n。同一份文档里两种模式都出现时,务必在head.text里写明,否则半年后自己都分不清哪张是哪张。

4.3 补 tSU / tH:在已有骨架上加箭头

{ "signal": [ { "name": "sclk", "wave": "0p...p...0", "node": "..a...b..." }, { "name": "mosi", "wave": "x=.=.=...x", "data": ["cmd", "addr", "dummy"], "node": "...c.d...." } ], "edge": ["c~>a t_su", "b~>d t_h"] }

加箭头时最容易犯的错是先把node写上去再回头改波形,结果字母位置和实际边沿差一格。稳妥顺序是:波形定稿 → 数格子确定标记点位置 → 插字母 → 写edge。字母插入不改变波形,但会挤占原本的.,插完一定要再看一眼预览,确认边沿没被挪动。

edge里的箭头方向也有讲究:a~>c是从 a 指向 c,如果 a 在 c 右边,箭头就是反的。差一格的箭头在评审时很难被发现,但会让人误读建立时间的正负号。

4.4 导出:什么场景给 SVG,什么场景给 PNG

用途格式关键设置
数据手册、LaTeX/网页SVG保持矢量,不要二次转位图
Word 报告、PPTPNGhscale先调到 2 至 3,再导出
邮件正文里直接贴PNG同上,宽度控制在 1200 像素以内
需要后期标注SVG用矢量工具打开加批注,别在 PNG 上画

SVG 的坑在字体替换:图里的标签字体一旦在目标机器上不存在,Word 之类软件会替换成默认字体,等宽字体的对齐立刻散架。所以图里尽量用纯 ASCII 标签,中文说明写进head.text,导出前确认它能正常显示。

同一份文档里的几张图,hscale必须统一。线宽不一致、字号不一致,读者一眼就能看出是不同时间拼的,专业感掉一半。

5. 避坑:预览空白、波形错位、标签串位这五类故障怎么查

5.1 预览一片空白,JSON 看着“没毛病”

现象:左侧代码有颜色,右侧全白,没有任何错误提示。

原因:这东西吃的是严格 JSON。尾逗号、单引号、//注释、键名不加引号,任何一种都能让它解析失败,而失败时它选择沉默。

解决:把内容丢进任意 JSON 校验器先过一遍,或者用编辑器的格式化功能——能格式化成功基本就是合法 JSON。养成写完一段先Ctrl+S看一眼右侧的习惯,别攒了几十行再一起看,那时候你不知道是哪一行坏的。

5.2 时钟和数据差半格,怎么调都对不上

现象:数据框的左边缘总是压在时钟下降沿上,差那么一点点。

原因:多半是用了0101手搓时钟,而数据符号的宽度和单个0/1的宽度本来就不是整数倍关系;或者phase只写在一条 lane 上,另一条还是默认 0。

解决:时钟一律用p/n,不要手拼。需要错开就统一给相关 lane 写phase,且写成同一个值。如果两条 lane 一个是period: 1一个是period: 2,那它们的时间基准根本不同,此时不要靠phase硬凑,改period让两边一致再微调。

5.3 数据标签整体串位,第一个标签跑到第二个框里

现象:data给了三个值,图上却从第二个框才开始有字,最后一个框空着。

原因:data数组长度和这条 lane 里数据符号的个数不相等。少一个符号,标签就从后往前错;多一个符号,末尾会多出一个空框。

解决:数符号。=、2到9都算数据符号,.不算。这类错误肉眼数容易出错,第 6 章给了一个脚本,提交前跑一遍直接拦住。

5.4 导出的图在文档里糊成马赛克

现象:编辑器里看着清清楚楚,贴进 Word 一放大就全是锯齿。

原因:导的是默认倍率 PNG,位图放大必然糊;或者贴的是 SVG,但目标软件把它栅格化成了低分辨率位图。

解决:两套都出。矢量进正式文档,位图留一份 2 至 3 倍的给 PPT 和聊天工具。另外先调hscale再导出,比导出后缩放效果好得多——前者是渲染时加宽,线条和字号一起变;后者只是把小图拉大。

5.5 保存后只剩一条波形,head 的文字也没了

现象:明明写了七八行,重新打开只剩第一行,标题也不见了。

原因:顶层结构写错。signal必须是数组,写成对象就只认第一个元素;head、foot、config、edge必须和signal平级,塞进signal里面它不认识,会安静地忽略。

解决:顶层只放那几个固定的键,别自创。另外文件保存成 UTF-8 无 BOM,带 BOM 的文件在部分解析器里会读出一个不可见字符,表现同样是“少东西”。

6. 进阶:让 30 张时序图跟着代码一起做 review

图一多,手工管就崩了。我的做法是:所有 WaveJSON 统一放figs/目录,文件名带文档章节号,比如figs/03-spi-read.json;渲染产物放out/,不进版本库。这样改动在 diff 里是可读的——评审的人能直接看到“这一拍从0改成了1”,比看两张 PNG 的像素差异强太多。

提交前跑一遍自查脚本,专治那些“看着像对、渲染出来错”的问题:

// check-wavejson.js —— 提交前拦住数据标签串位和空 lane const fs = require('fs'); const path = require('path'); const walk = (signals, file, errs) => { for (const s of signals || []) { if (!s || typeof s !== 'object') continue; if (Array.isArray(s.signal)) { walk(s.signal, file, errs); continue; } // 分组递归 if (typeof s.wave !== 'string') { errs.push(`${file}: lane "${s.name ?? '?'}" 缺少 wave`); continue; } const syms = (s.wave.match(/[=2-9]/g) || []).length; // 数据符号个数 const len = Array.isArray(s.data) ? s.data.length : 0; // data 给了几个 if (syms !== len) { errs.push(`${file}: lane "${s.name}" 数据符号 ${syms} 个,data 给了 ${len} 个`); } } }; let bad = 0; const dir = path.join(__dirname, 'figs'); for (const f of fs.readdirSync(dir).filter(n => n.endsWith('.json'))) { const errs = []; try { const src = JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8')); walk(src.signal, f, errs); } catch (e) { errs.push(`${f}: JSON 解析失败 -> ${e.message}`); } if (errs.length) { bad++; console.error(errs.join('\n')); } } process.exit(bad ? 1 : 0); // 非零退出码让 CI / pre-commit 直接挡下

脚本逻辑很直白:遍历所有 lane(遇到嵌套的分组就递归下去),对每条 lane 数一遍数据符号、再数一遍data数组长度,不相等就报错;顺带把解析失败也捕获住,等于把第 5 章 5.1 和 5.3 两个坑一起堵了。process.exit(1)是关键,本地挂个 pre-commit、流水线里加一步,谁提交坏图谁自己修。

批量渲染没有统一函数名,各版本导出的接口不一样,稳妥做法是先看清楚再写:

// 先探一下渲染库暴露了哪些入口,再决定调哪个 const wave = require('wavedrom'); console.log(Object.keys <p> <a href="https://download.csdn.net/download/muxi_huang/12245976" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询