Verilog状态机设计实战:以跑马灯为例掌握FPGA时序控制
被问得最多的不是“怎么用移位寄存器写流水灯”而是“怎么写好状态机”。借着跑马灯/流水灯这个经典题目我把 Verilog HDL 里状态机的思考方式和落地写法完整梳理一遍。无论你是刚开始学 FPGA还是写过一段代码但总被“时序跑飞”“状态乱跳”折磨这篇都值得对照着看。跑马灯之所以适合拿来练状态机是因为它的状态数量少、LED 输出直观、转移条件可控踩过的坑能直接迁移到按键消抖、UART 接收、交通灯这类真实控制器上。这篇文章会把状态图怎么画、Moore/Mealy 怎么选、编码方式怎么定、三段式代码怎么拆、仿真波形怎么看串起来讲最后再给几个工程化扩展和实战翻车教训。1. 状态机不是语法题先画状态图再谈代码很多初学者把状态机当成一种语法看到always case就以为会了。真正的问题从来不是怎么敲代码而是你知不知道系统里到底有哪几个状态、每个状态在什么条件下离开、离开之后去往哪里。代码只是把状态图画出来而已图画错了代码写再规范也是错的。1.1 跑马灯里到底藏着哪些状态一个最基本的四灯跑马灯需求通常是系统复位后 LED 全灭按下启动使能后只有一盏灯亮每隔固定时间比如 100ms亮灯位置向后移动一个移动到最后一盏后回到第一盏循环往复。这个需求里天然存在五个状态一个“空闲/全灭”状态四个“当前点亮第几盏灯”的状态。很多人只写四个状态把复位后 LED 全灭这件事交给复位信号本身漏掉空闲状态。这会导致一个很尴尬的问题一旦使能信号拉低LED 停在当前灯上而不是回到全灭的初始状态。如果你希望“使能无效时停止闪烁并全灭”那么空闲状态就是必须的。状态含义LED 输出IDLE空闲全灭4b0000S_LED0点亮第 0 盏灯4b0001S_LED1点亮第 1 盏灯4b0010S_LED2点亮第 2 盏灯4b0100S_LED3点亮第 3 盏灯4b1000如果再加方向控制状态数量不变变化的是每个状态离开时的目标正向时S_LED0 - S_LED1反向时S_LED0 - S_LED3。这个观察很重要很多人一加“方向可调”就想把状态数量翻倍实际上控制逻辑变了状态并没有变多。1.2 把需求翻译成状态表的具体步骤写状态机之前我习惯先做一张状态转移表。这张表不急着写case而是用自然语言把每个状态的出口条件列清楚。拿上面带方向控制的四灯跑马灯为例现态转移条件次态IDLEen 为低IDLEIDLEen 为高S_LED0S_LED0未到计时结束S_LED0S_LED0计时结束且 dir1S_LED1S_LED0计时结束且 dir0S_LED3S_LED1未到计时结束S_LED1S_LED1计时结束且 dir1S_LED2S_LED1计时结束且 dir0S_LED0S_LED2未到计时结束S_LED2S_LED2计时结束且 dir1S_LED3S_LED2计时结束且 dir0S_LED1S_LED3未到计时结束S_LED3S_LED3计时结束且 dir1S_LED0S_LED3计时结束且 dir0S_LED2这张表写完之后case语句只是把它机械地翻译成 Verilog。很多人的状态机写得乱不是因为 Verilog 水平差而是跳过了表格这一步直接在代码里“边写边想”状态之间的关系全靠脑子硬记状态一多就必出 bug。1.3 为什么“一句移位”解决不了复杂需求网上最常见的流水灯写法是那句led {led[2:0], led[3]}。这个写法对“固定方向、固定速度、一直跑”的演示确实够用代码还短。但它把“灯的当前状态”和“下一次转移到哪里”揉在了一条赋值语句里任何需求变化都会让你很难受。比如要加方向控制移位那句要么改成led dir ? {led[2:0], led[3]} : {led[0], led[3:1]}表面看也能写但要继续加“使能暂停”“速度可调”“跑两圈后反转”“遇到某个按键亮灯方式改变”这串移位就会膨胀成一大堆互相纠缠的 if 条件。状态机的好处是把“我现在在哪个状态”和“什么条件下我要去哪里”显式地拆开每个状态独立看都很好理解整体修改也只是增删几个分支不会牵一发动全身。2. Moore/Mealy 选型与状态编码跑马灯该选哪种写法状态图画完下一步不是写代码而是决定状态机的类型和状态编码。这两个选择会影响代码的复杂度和最终电路面积尤其在状态多的时候差别非常明显。2.1 Moore 和 Mealy 到底怎么选状态机分 Moore 和 Mealy 两类。Moore 的输出只由当前状态决定Mealy 的输出由当前状态和当前输入共同决定。区别可以用一句话概括Moore 是“到了某个状态才做某件事”Mealy 是“输入一变就立刻做某件事”。跑马灯的 LED 输出只取决于“当前亮哪一盏灯”跟使能、方向这些输入没有直接关系所以应该用 Moore 结构。输出逻辑里只需要case (state)不需要把en和dir塞进输出表达式。这样输出非常干净也不容易出现组合逻辑毛刺把灯闪得乱七八糟。那什么时候用 Mealy举个例子如果要求“使能拉低的瞬间LED 立刻全灭”而不是等到下一个时钟沿状态切换过去才灭Mealy 会更直接因为输出可以直接写成led en ? led_by_state : 4b0000。但跑马灯这种低速电路里晚一个时钟周期灭灯肉眼完全看不出来没必要为了省一个周期引入额外复杂度。原则很简单默认选 Moore只有输出必须对输入即时响应时才考虑 Mealy。2.2 二进制、格雷码、独热码怎么选状态编码方式常见三种二进制码、格雷码、独热码。它们各自的代价不同。编码方式触发器数量组合逻辑复杂度典型场景二进制码少中等状态少、追求资源最小的 ASIC格雷码少中等相邻状态频繁切换、希望减少翻转功耗独热码多低FPGA、状态多、希望逻辑简单FPGA 的寄存器资源相对富裕组合逻辑资源更宝贵所以独热码是 FPGA 状态机的常见选择。独热码每个状态用一位触发器表示状态判断变成“某一位是否为 1”不需要像二进制那样编译出一大堆比较逻辑。四个有效状态加一个空闲状态一共五个独热位即使多花几个触发器也完全无所谓。我在这篇文章的例子里会用手动定义的localparam独热码而不是依赖综合器的fsm_encoding属性。不同 EDA 工具对fsm_encoding的写法不完全一样与其记各家语法不如直接自己在代码里把状态常量定义成独热码再让所有判断都基于state变量。这样写出来的代码换工具也不会变味综合器也无从“优化”你的状态结构。2.3 复位策略、默认分支和非法状态状态机必须有一个复位可到达的初始状态。我用低电平有效的异步复位rst_n复位时state S_IDLE。异步复位的好处是复位信号一拉低状态立刻回到初始态不依赖时钟是否存在这在调试时非常实用。同时case语句里必须写default分支。FPGA 上电后内部寄存器可能进入任意状态如果代码只覆盖了合法状态非法状态会把系统永久卡住。我习惯让非法状态一律回到S_IDLE也就是“宁可重新开始也不要死机”。另外在组合逻辑块里面赋初值也是一个必须养成的习惯next_state state; led 4b0000;这种“先给默认值再写 case”的写法可以从根源上避免综合出锁存器。3. 三段式 Verilog 完整实现代码逐段拆解状态图、状态表、编码方式都定了接下来的代码就顺理成章了。下面这段代码是一个带使能、方向控制、可参数化延时的四灯跑马灯模块。我用的是三段式状态机写法这也是我建议你在工程里固定下来的风格。3.1 三段式到底把状态机切成哪三段三段式不是某种高深理论而是把状态机的职责拆成三个always块第一段时序逻辑负责state next_state也就是状态寄存器的更新。第二段组合逻辑根据当前状态和输入条件计算next_state。第三段输出逻辑根据当前状态生成输出信号。输出逻辑可以写成时序的也可以写成组合的。流水灯的 LED 直接由当前状态决定我用组合逻辑输出这样state一更新LED 立刻跟随变化不额外延迟一拍。如果要输出的信号必须非常干净、不能有毛刺可以把输出也放到时序块里寄存一拍代价就是输出比状态变化晚一个时钟周期实际工程里要根据需求取舍。3.2 完整的可综合跑马灯模块module led_runner #( parameter CLK_HZ 12_000_000, parameter MS_PER_STEP 100 )( input wire clk, input wire rst_n, input wire en, input wire dir, output reg [3:0] led ); function integer clog2; input integer n; integer i; begin clog2 0; for (i 0; (1 i) n; i i 1) begin clog2 i 1; end end endfunction localparam integer CNT_MAX CLK_HZ * MS_PER_STEP / 1000 - 1; localparam integer CNT_W clog2(CNT_MAX 1); localparam S_IDLE 5b00001; localparam S_LED0 5b00010; localparam S_LED1 5b00100; localparam S_LED2 5b01000; localparam S_LED3 5b10000; reg [4:0] state; reg [4:0] next_state; reg [CNT_W-1:0] cnt; wire tick; // 第一段状态寄存器 always (posedge clk or negedge rst_n) begin if (!rst_n) begin state S_IDLE; end else begin state next_state; end end // 计时器使能有效且不在空闲态时计数 always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt {CNT_W{1b0}}; end else if (!en) begin cnt {CNT_W{1b0}}; end else if (state S_IDLE) begin cnt {CNT_W{1b0}}; end else if (cnt CNT_MAX) begin cnt {CNT_W{1b0}}; end else begin cnt cnt 1b1; end end // 单周期节拍信号只有计时满且使能有效时才拉高 assign tick en (state ! S_IDLE) (cnt CNT_MAX); // 第二段次态组合逻辑 always (*) begin next_state state; case (state) S_IDLE: begin if (en) next_state S_LED0; end S_LED0: begin if (tick) next_state dir ? S_LED1 : S_LED3; end S_LED1: begin if (tick) next_state dir ? S_LED2 : S_LED0; end S_LED2: begin if (tick) next_state dir ? S_LED3 : S_LED1; end S_LED3: begin if (tick) next_state dir ? S_LED0 : S_LED2; end default: next_state S_IDLE; endcase end // 第三段Moore 组合输出 always (*) begin led 4b0000; case (state) S_IDLE: led 4b0000; S_LED0: led 4b0001; S_LED1: led 4b0010; S_LED2: led 4b0100; S_LED3: led 4b1000; default: led 4b0000; endcase end endmodule如果你的综合器不支持函数做常量计算直接把cnt定义成固定位宽也没问题。比如 50MHz 时钟下想让跑马灯最长停在 1 秒计数器上限大约 5000 万用reg [25:0] cnt就能覆盖。用clog2函数只是为了把位宽算得更精确避免“看起来够用结果差一位”的边界问题。3.3 代码里几个容易被忽略的设计点tick是我故意抽出来的一个单周期脉冲信号。状态机转移条件里直接写tick而不是把cnt CNT_MAX散落在每个分支里。这样有两个好处一是以后想改时长只需要改CNT_MAX二是如果将来想在同一个状态里同时判断“计时满了”和“是否暂停”逻辑会更集中。cnt的清零逻辑单独放在计时器块里不是放在状态转移块里。很多初学会把“计时满”当成一个条件在状态机里顺手把cnt清零结果tick的宽度和状态切换的时序纠缠在一起特别容易出“一个灯亮一下就跳过去”的诡异现象。独立处理计数器状态机只关心“收到 tick 没有”职责更清晰。输出逻辑里那行led 4b0000;是防锁存器的关键。如果不给默认值只在各个状态分支里给led赋值综合器读到某些位没有被覆盖就会推断出锁存器。仿真时锁存器还能跑综合到 FPGA 上就会出现各种奇怪问题。先给默认值再写case是最简单的规避手段。4. 怎么验证状态机没跑飞仿真波形与上板排错代码写完不代表状态机是对的。我见过太多人仿真都不跑直接上板看到灯乱跳就不知道从哪里下手。验证一个状态机仿真阶段能解决 80% 的问题。4.1 写一个能“骗过自己”的 testbench下面这个 testbench 用比较低的CLK_HZ和比较小的MS_PER_STEP让仿真的计时周期变短波形里能很快看到几个完整循环。实际工程中参数可能要跑到十几万周期才能看到一次状态切换仿真等不起所以要学会用小参数做定向验证。timescale 1ns/1ps module led_runner_tb; reg clk 1b0; reg rst_n 1b0; reg en 1b0; reg dir 1b0; wire [3:0] led; led_runner #( .CLK_HZ (2000), .MS_PER_STEP(5) ) u_led_runner ( .clk (clk), .rst_n (rst_n), .en (en), .dir (dir), .led (led) ); always #5 clk ~clk; initial begin rst_n 1b0; #30; rst_n 1b1; #20; en 1b1; #2000; dir 1b1; #4000; en 1b0; #500; $finish; end initial begin $monitor(%0t | state%b led%b en%b dir%b, $time, u_led_runner.state, led, en, dir); end endmodule$monitor会打印内部state和顶层led的变化。这样你能直接看到state是否按照S_IDLE - S_LED0 - S_LED1 - S_LED2 - S_LED3 - S_LED0...的顺序变化方向切换后是否倒序跑。4.2 波形里要重点看哪几个信号仿真跑完先别急着感叹“灯亮了”要对着波形逐项确认state是否出现非法值。独热码一共只有 5 个合法值波形里如果出现00101这类状态说明代码有问题或者复位没复位干净。tick是否真的是单周期脉冲。好的tick应该是拉高一拍就落下去如果连续多拍为高状态机很可能一个条件触发多次转移。cnt是否在到达CNT_MAX的那一拍被清零。如果计数上限是 9那么波形里cnt最高就是 9不会出现 10。led是否和当前状态一一对应。state是00010时led必须是0001如果对应关系错位优先检查输出块而不是状态转移块。使能拉低后cnt是否马上归零、led是否保持当前值不再变化。如果不是检查tick里有没有把en和状态条件一起放进去。4.3 上板出现异常时的排查顺序上板和仿真表现不一致大多是外部信号处理或者时序约束的问题而不是状态机逻辑问题。我通常按下面这个顺序排查先确认复位信号是不是一直有效或者一直无效。用逻辑分析仪或者开发板上的 LED 指示复位状态这一步能排除一半问题。再确认按键或者拨码开关有没有做同步和消抖。外部开关直接接到en、dir上金属触点的抖动会造成状态机在几个状态之间来回跳肉眼看到的就是灯乱闪。检查计数器位宽。如果CNT_MAX计算出来超过了计数器最大值cnt CNT_MAX永远不成立灯就永远不会动。拿笔算一下2^N - 1是否大于等于CNT_MAX。对比仿真和上板的时钟频率。仿真用了低CLK_HZ上板如果没改参数跑马灯速度会完全不对这是参数化设计最常见的疏忽。最后看综合报告里有没有意外生成的锁存器。如果有回到代码里检查是不是某个组合逻辑输出忘了赋默认值。5. 状态机工程化扩展速度可调、方向可调与通用节拍跑马灯能跑起来只是第一步。实际开发中你大概率会遇到“速度要能调”“方向要能变”“多组灯要一起跑”这类需求。状态机设计得好不好这时候才真正见分晓。5.1 把“延时计数器”从状态机里抽出来很多状态机都带一个计数器但计数器最好独立成一个节拍发生器而不是和状态转移耦合在一起。状态机的职责是“什么时候做什么事”计数器的职责是“每隔多少个时钟产生一次 tick”。两者解耦之后状态机里所有跟延时相关的判断都浓缩成一个tick信号代码一眼能看到转移条件。节拍发生器也很容易参数化。如果追求更灵活的定时可以改成比较器加装载值reg [CNT_W-1:0] limit; wire tick en (state ! S_IDLE) (cnt limit); always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt {CNT_W{1b0}}; end else if (!en || state S_IDLE || cnt limit) begin cnt {CNT_W{1b0}}; end else begin cnt cnt 1b1; end end这样状态机完全不需要知道某个速度档对应多少毫秒它只关心tick来了没有。5.2 速度可调和多组 LED 的扩展思路速度可调的做法是给模块加一个speed输入组合逻辑根据speed算出limitlocalparam LIMIT_FAST 500; localparam LIMIT_MID 1000; localparam LIMIT_SLOW 2000; always (*) begin case (speed) 2b00: limit LIMIT_FAST; 2b01: limit LIMIT_MID; 2b10: limit LIMIT_SLOW; default: limit LIMIT_MID; endcase end如果你的板子时钟是 50MHz500 个时钟对应 10 微秒LED 会闪得非常快。扩展时的关键点不是怎么选LIMIT而是保证三个档位都不会把limit设成 0 或 1否则tick会变得过于密集状态机根本停不下来。多组 LED 的扩展也遵循同样的思路每组的“当前亮灯状态”可以复用一个状态机结构但状态是独立的。不要在一个状态机里强行塞进两组灯的转移逻辑那会让状态组合爆炸。宁可例化两个跑马灯模块各管各的灯需要同步时再统一控制它们的en这样可读性和可维护性都好很多。5.3 状态机代码的维护清单我在评审别人的状态机代码时会按照下面这张清单快速过一遍你也可以这么检查自己写的代码检查项具体要求默认状态case必须有default非法状态回到复位态输出默认值组合输出块先赋默认值防止锁存器转移条件状态转移只用单周期脉冲信号不直接用电平条件复位状态和计数器都复位复位源保持一致编码独热码常量定义完整不重复不遗漏计数器计数上限不要越界清零时机要明确这张清单的价值不在于逐条打勾而在于逼你提前想清楚每个状态有没有出口、每个输出有没有兜底、每个条件有没有歧义。6. 实战复盘几个容易写废状态机的细节最后聊几个我在实际项目中经常遇到、也经常帮别人擦屁股的坑。这些问题仿真不一定立刻暴露但上板之后特别恶心。6.1 计数到上限后不能留下“持续高电平”有次我接手一个别人写的流水灯模块现象是灯会在两个状态之间高频抖动。查了半天发现他的tick是用cnt CNT_MAX写出来的而且计数器没有在到达上限时清零。于是tick持续保持高电平状态机在这个电平期间反复触发转移一个灯还没稳定状态就已经跳走了。正确做法是让tick成为单周期脉冲计数器到达CNT_MAX的同一拍把它清零tick自然只拉高一拍。状态机看到这个脉冲只执行一次状态转移走人。时刻记住状态机的转移条件应该“边沿化”“脉冲化”不是“电平化”。6.2 组合逻辑漏赋值导致锁存器另一个很常见的坑是输出逻辑漏掉default。比如有人在写 LED 输出时只在每个状态分支里给led赋值一旦状态因为某种原因进了非法值组合输出中某些位没有被赋值综合工具就会推断出锁存器。锁存器在仿真里可能表现正常到了 FPGA 上会因为时序问题出现毛刺。防这个坑不需要什么高级技巧就是两行代码的事块里面先写一句led 4b0000;然后写case。next_state也是同理先next_state state;再写条件覆盖。宁可多写两行“无用”的默认赋值也不要让工具替你补一个你根本不想看到的锁存器。6.3 外部按键直接进状态机跑马灯工程几乎都会加按键控制启动或方向。最容易犯的错误是直接把按键引脚接到en和dir上不做任何处理。机械按键按下和松开时会产生几毫秒到几十毫秒的抖动这个抖动在数字电路里就是一串随机高低电平。状态机跑在几十兆赫兹时钟下一抖就是成千上万个时钟周期状态机会在多个状态之间来回乱穿最后灯的表现完全不可控。正确的做法是给输入加两级同步器再加消抖计数器。同步器解决的是跨时钟域和亚稳态问题消抖计数器解决的是机械抖动问题。比如检测到按键电平稳定持续 20ms 再认为有效这就是最朴素也最好用的消抖方案。状态机本身不要承担消抖职责它只负责接收已经“洗干净”的使能脉冲。说到底状态机写得好不好不取决于你会不会用case而取决于你愿不愿意在写代码之前把状态画清楚、把条件列明白、把边界想完整。跑马灯只是起点这套思考方式用到任何控制器上都一样。

相关新闻

基于MP2642GR-Z与TM4C1294NCZAD的两串电芯被动均衡系统设计与实现

基于MP2642GR-Z与TM4C1294NCZAD的两串电芯被动均衡系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 5:58:32 阅读更多 →
gmapping地图重置实战:从杀进程到根治坐标系漂移与旧图残留

gmapping地图重置实战:从杀进程到根治坐标系漂移与旧图残留

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 5:58:32 阅读更多 →
Fragment Mono:源自 Helvetica 谱系的等宽编程字体,在 Fontsource 中的分发与使用

Fragment Mono:源自 Helvetica 谱系的等宽编程字体,在 Fontsource 中的分发与使用

前端CLI开发工具 【免费下载链接】fontsource Self-host Open Source fonts in neatly bundled NPM packages. 项目地址: https://gitcode.com/gh_mirrors/fo/fontsource 点击查看 免费下载 Fragment Mono 是一款以 Helvetica 为基因、面向代码阅读场景设计的等宽&…

2026/10/17 5:58:32 阅读更多 →

最新新闻

CANN深度解析:昇腾AI异构计算架构的核心原理与性能调优实践

CANN深度解析:昇腾AI异构计算架构的核心原理与性能调优实践

如果最近在昇腾AI处理器上跑过模型,那你大概率躲不开这个名字:CANN。我第一次接触它时,想当然地以为它和GPU上的CUDA一样——装个驱动、配好环境、调一下框架后端就能直接跑。真正上手才发现,CANN不是一个简单的驱动,也…

2026/10/17 7:06:04 阅读更多 →
Ollama+Go+词库+RAG:本地大模型应用实战拆解

Ollama+Go+词库+RAG:本地大模型应用实战拆解

本地大模型这两年已经卷到“开箱即用”了。去年我跑一个开源大模型,还得先折腾显卡驱动、CUDA、Python 环境、模型转换脚本,现在一把梭的方式是直接拉一个 Ollama 服务,命令一敲模型就跑起来了。更吸引人的是,Ollama 这边既能接入…

2026/10/17 7:06:04 阅读更多 →
微信企业转账到零钱Java对接实战:从签名验签到结果归档

微信企业转账到零钱Java对接实战:从签名验签到结果归档

简介:本资源是一套面向Java后端开发者的企业级微信支付实战代码,聚焦微信企业付款到零钱功能的完整后台实现,适用于工资发放、奖金结算、退款处理等真实业务场景。代码基于微信商户平台API规范,涵盖签名生成、HTTPS请求构造、敏感…

2026/10/17 7:06:04 阅读更多 →
PDMS-AVEVA-E3D二次开发教程(09):.NET Addin 开发——IAddin 接口、CAF 装载配置与最小可运行 Addin

PDMS-AVEVA-E3D二次开发教程(09):.NET Addin 开发——IAddin 接口、CAF 装载配置与最小可运行 Addin

版本声明:本篇基线为 AVEVA E3D Design 3.1(文档版本线存在 1.1 / 2.1 / 3.1,教程统一以 3.1 为准);前代产品 AVEVA PDMS 自 2024 年 4 月 1 日起不再销售、不再提供支持。历史文档(PDMS 12.0 时代&#xf…

2026/10/17 7:06:04 阅读更多 →
PDMS-AVEVA-E3D二次开发教程(10):Command 机制与 UIC——把定制命令挂到菜单与工具栏

PDMS-AVEVA-E3D二次开发教程(10):Command 机制与 UIC——把定制命令挂到菜单与工具栏

版本声明:本篇基线为 AVEVA E3D Design 3.1(文档版本线存在 1.1 / 2.1 / 3.1,教程统一以 3.1 为准);前代产品 AVEVA PDMS 自 2024 年 4 月 1 日起不再销售、不再提供支持。文中命令基类、状态枚举、事件名、UIC 机制与…

2026/10/17 7:06:04 阅读更多 →
降AI工具的本质是语义重构:从检测原理到实操指南

降AI工具的本质是语义重构:从检测原理到实操指南

在内容创作这个圈子里泡久了,你一定会遇到这样一个问题:拿AI写好的稿子,一检测就标红,于是到处找“降AI工具”。我也踩过这个坑,最初以为所谓降AI就是把“重要”换成“关键”、把“因为”换成“由于”,直到…

2026/10/17 7:05:03 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →