尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Quartus II FPGA交通灯工程:Verilog状态机、数码管扫描与引脚约束实战
简介「QuartusⅡ交通灯控制电路」是一份面向数字逻辑电路设计与芯片仿真的完整工程实践包围绕十字路口信号灯控制展开甲车道为主道单次通行75秒乙车道为辅道每次25秒两车道交替放行切换前黄灯先亮3秒并以每秒一次的频率闪亮同时支持按键切换模式。整套设计可直接用于课程设计、FPGA/CPLD实验与原理图设计练习。包内共167个文件以bdf原理图、bsf元件符号、vwf波形仿真文件为主体另含qsf工程配置、sof下载文件、rpt编译报告及大量cdb、hdb等编译中间数据库工程结构完整压缩包约2.42MB已有3293人学习。读者可据此理解分模块原理图的设计思路学习状态机与计时器配合工作的时序实现方式并借助波形文件验证黄灯闪烁与车道切换逻辑对照编译报告排查引脚分配和时序问题从而快速改动并复现自己的方案。1. 波形完美、板子不亮这个工程包解决的正是这个断点实验室里最常见的翻车现场不是代码写不出来而是 Quartus II 里芯片仿真波形跑得干干净净下载到板子上灯却不按剧本亮该红的绿灯、该倒计时的时候数码管在闪。这份 Quartus II 交通灯控制电路工程包就是冲这个断点去的——一个十字路口的东西向、南北向三色灯配两位倒计时数码管、黄灯过渡、手动复位从分频、状态机、显示扫描到引脚约束全放在一个可编译的工程里。它适合三类人正在做数字逻辑电路设计课设、需要一个能跑通的参考架构的刚接触 FPGA、想搞明白「行为级写法和可综合写法差在哪」的以及手上有块开发板、想拿个完整例子练全流程的。下面按「能干什么 → 怎么跑 → 怎么改」的顺序拆。2. 工程架构拆解一次红绿灯切换要经过几层拿到压缩包先别急着点全编译先把工程的骨架看明白。交通灯表面上是几个灯亮灭实质上是「时钟 → 计时 → 状态 → 译码 → 管脚」的链路任何一层错位波形和实物就对不上。这个工程按可综合的经典拆法分成四块时钟使能生成、主状态机、倒计时与显示、顶层连线互相之间只通过使能脉冲和状态编码通信不做跨模块的时钟传递。2.1 解压后先看文件清单工程、源码、约束、波形各在哪工程主干是一个 Quartus II 的工程文件加上一堆.v源文件和一份引脚约束。真正的「坑」几乎都集中在.qsf和顶层模块上因为这两处跟你的板卡强绑定别人机器上能跑你机器上不一定。解压后建议先按下面这张表过一遍知道哪个文件该动、哪个文件别碰。文件类型作用是否需要改动traffic_light.qpf工程文件记录工程名与版本双击即可打开不需要traffic_light.qsf设置文件器件型号、引脚分配、IO 电平标准必须改按你板子的原理图top.v顶层源码例化各子模块、连信号改端口对接时看它clk_en.v源码分频产生 1 Hz 单周期使能改分频系数traffic_fsm.v源码四相位状态机与倒计时装载改相位时长、加相位seg_scan.v源码数码管动态扫描改共阳/共阴、位数tb_traffic.v仿真测试激励缩短时间参数改激励再跑output_files/编译产物.sof下载文件、报告每次全编译后重新生成有一点要提前说清楚output_files里的东西是可以删的中间产物重新全编译就会再生成但.qsf里的引脚分配是手写进去的资产删了就找不回来这也是我建议第一次打开工程就另存一份备份的原因。但凡涉及数字逻辑电路设计的工程约束文件的价值往往比源码高源码能重写约束是照着板子一根线一根线对出来的。2.2 时钟链从板载晶振到 1 Hz 的三条路交通灯最核心的时间单位是「秒」。板载晶振常见是 50 MHz也就是每秒 5000 万个时钟沿直接拿来做状态机节拍那这个路口一秒内能切换几百万次肉眼只看得到一片糊。所以必须先建立一个 1 Hz 的时间基准。这件事有三种做法差别很大做法实现方式优点问题分频出新时钟计数到 2500 万后翻转clk_1hz用它当always (posedge clk_1hz)直观引入新的时钟域综合和时序分析都麻烦容易出跨时钟域告警单周期使能系统时钟不变每 2500 万个周期拉高一个周期的tick单时钟域、时序干净代码里所有逻辑都要判断if (tick)外部按键/晶振分频模块硬件上单独给低频源省逻辑多数开发板没有现成的 1 Hz 源这个工程走的是第二种也就是「使能脉冲」路线这也是我在实际项目里最推荐的做法。原因很实在整个设计只有clk一个时钟Quartus II 的 TimeQuest 时序分析只需要约束一根时钟报告里不会出现一堆「时钟未被约束」的告警。而分频出新时钟的写法在老教材里很常见但在真板子上跑起来经常莫名其妙——这就是玄学感的来源其实是时钟域没管好。2.3 状态机怎么划分相位四相位是最小可用的路口模型东西绿灯、东西黄灯、南北绿灯、南北黄灯循环一圈。这里的关键决策是「时长放在哪」。硬编码在case里最省事但改一次时长要动四处放在模块参数里改一个数字就生效。工程用的是参数化写法四个时长都是parameter// 四个相位的持续秒数改这里就能改配时 parameter EW_GREEN 15, // 东西直行绿灯 15 秒 parameter EW_YELLOW 3, // 东西黄灯过渡 3 秒 parameter NS_GREEN 20, // 南北直行绿灯 20 秒 parameter NS_YELLOW 3 // 南北黄灯过渡 3 秒为什么东西向给 15 秒、南北向给 20 秒这是主干道优先的常见配时思路实际路口会根据车流量调整我们做课设时不必较真但这个「不对称」是有意义的——它能暴露一个很隐蔽的 bug如果两个方向的绿灯时长写成同一个参数你测试的时候永远发现不了「倒计时装载错了方向」这种错误一旦写成两个不同的值波形上一眼就能看出来。状态编码建议用localparam起名字别在case里直接写3d0。综合工具并不会因为你写了名字就多花资源但人看得懂。这里还有个细节四个状态用两位二进制就够但工程里用三位是为了后面加左转相位和夜间黄闪留余量扩展时不用改位宽。2.4 从零复现新建工程到第一次全编译如果你想脱离这个工程自己搭一遍步骤大致如下每一步都对应一个容易漏的点打开 Quartus II新建工程工程名与顶层实体名保持一致都叫top。名字不一致会在综合时报「找不到顶层实体」这个错我第一次踩的时候找了半小时。在器件选择页选对器件族和具体型号型号必须和板子上的芯片丝印一致。选错了后面 Programmer 里根本认不到设备。把四个.v文件加进工程tb_traffic.v不要加进去当综合源文件仿真文件只在仿真时引用。打开top.v设为顶层执行一次 Analysis Elaboration不是全编译先看有没有语法和端口连接错误这一步比全编译快得多。按板子原理图在 Pin Planner 里分配引脚或者直接编辑.qsf。全编译检查 Compilation Report 里有没有 latch 推断、时钟未约束、多驱动这几类告警。第 6 步值得单独强调。全编译「成功」不等于「正确」Quartus II 只要语法过得去就会给你出.sof但里面可能藏着一个组合逻辑环路或者一个被推断成锁存器的always (*)。数字逻辑电路设计的老手看报告比看代码还仔细因为代码是你想写的报告是工具实际综合出来的二者经常不是一回事。3. 核心模块拆解三段 Verilog 撑起整个路口工程里真正干活的只有三个模块加起来一两百行。这一章逐段过一遍每段都说清楚「为什么这么写」和「哪些参数你会想改」。3.1 分频与使能生成clk_en.v这是整个工程的时间心脏。它的职责只有一个在 50 MHz 的时钟上每 5000 万个周期吐出一个宽度为单周期的tick脉冲。写法上用的是「计数到 N-1 归零并拉高」的经典结构。module clk_en #( parameter CLK_FREQ 50_000_000, // 板载晶振频率按实际板卡修改 parameter TICK_HZ 1 // 需要的节拍频率交通灯用 1 Hz )( input wire clk, input wire rst_n, output reg tick ); // 分频系数50M / 1 50_000_000 localparam integer DIV CLK_FREQ / TICK_HZ; reg [31:0] cnt; always (posedge clk or negedge rst_n) begin if (!rst_n) begin cnt 32d0; tick 1b0; end else if (cnt DIV - 1) begin cnt 32d0; tick 1b1; // 只拉高一个时钟周期不是 50% 占空比 end else begin cnt cnt 1b1; tick 1b0; end end endmodule逻辑说明cnt从 0 数到DIV-1正好是DIV个时钟周期此时把tick拉高一个周期并立即清零计数器。因为tick只在cnt满的那一拍为高所以它是「单周期脉冲」而不是方波下游模块必须写成if (tick)而不是always (posedge tick)。参数说明CLK_FREQ一定要改成你板子的真实频率。我见过有人板子是 24 MHz代码里留着 50 MHz 的默认值结果倒计时显示 15 秒实际走了 31 秒肉眼很难第一眼发现跑一次秒表才露馅。TICK_HZ保持 1 就行仿真时把它改成 10 或者把CLK_FREQ改成 100能让波形在几微秒内跑完一个完整循环。另外cnt的位宽是 32 位减 1 之后最大值约 42 亿够分到 0.01 Hz 级别。如果你只要 1 Hz理论上 26 位就够但 Quartus II 会把多余的高位优化掉不必手动抠这点资源。3.2 主状态机traffic_fsm.v状态机负责两件事决定当前哪个方向放行以及维护当前相位的剩余秒数。写法上刻意拆成「时序部分管状态和计数、组合部分管灯色输出」两段式避免把输出也塞进时序逻辑里导致灯色慢一拍。module traffic_fsm #( parameter EW_GREEN 15, parameter EW_YELLOW 3, parameter NS_GREEN 20, parameter NS_YELLOW 3 )( input wire clk, input wire rst_n, input wire tick, // 来自 clk_en 的 1 Hz 单周期使能 output reg [2:0] ew_light, // {红,黄,绿}高有效 output reg [2:0] ns_light, output reg [5:0] ew_cnt, // 东西向剩余秒数直接送数码管 output reg [5:0] ns_cnt ); // 四个相位用三位编码给后续扩展留余量 localparam S_EW_G 3d0, S_EW_Y 3d1, S_NS_G 3d2, S_NS_Y 3d3; reg [2:0] state; reg [5:0] cnt; // 当前相位剩余秒数 // 段一状态转移 计时只在 tick 到来时推进 always (posedge clk or negedge rst_n) begin if (!rst_n) begin state S_EW_G; cnt EW_GREEN - 1; end else if (tick) begin if (cnt 6d0) begin case (state) S_EW_G: begin state S_EW_Y; cnt EW_YELLOW - 1; end S_EW_Y: begin state S_NS_G; cnt NS_GREEN - 1; end S_NS_G: begin state S_NS_Y; cnt NS_YELLOW - 1; end S_NS_Y: begin state S_EW_G; cnt EW_GREEN - 1; end default:begin state S_EW_G; cnt EW_GREEN - 1; end endcase end else begin cnt cnt - 1b1; // 每秒减一 end end end // 段二灯色译码组合逻辑默认全红防止锁存器 always (*) begin ew_light 3b100; // 默认红灯亮 ns_light 3b100; case (state) S_EW_G: begin ew_light 3b001; ns_light 3b100; end S_EW_Y: begin ew_light 3b010; ns_light 3b100; end S_NS_G: begin ew_light 3b100; ns_light 3b001; end S_NS_Y: begin ew_light 3b100; ns_light 3b010; end endcase end // 剩余秒数送显示绿灯相位显示绿灯倒计时黄灯相位显示黄灯倒计时 assign ew_cnt cnt; assign ns_cnt cnt; endmodule逻辑说明状态机只在tick为高的那一拍做判断和递减其余时间保持不动所以cnt的递减速度严格等于 1 秒一次。当cnt归零时立刻切换到下一个相位并把新相位的时长减一装进去减一是因为当前这一秒已经被消耗掉了。参数说明四个parameter决定配时注意cnt是 6 位最大 63 秒如果你想设 90 秒的红灯位宽要跟着加到 7 位否则会被截断成 26 秒——这是个很典型、很难靠肉眼发现的错误。这里有个设计取舍值得说上面ew_cnt和ns_cnt都直接接了同一个cnt显示的是「当前相位剩余时间」。如果你要做「红灯等待时间」的显示那这两路就要分开算红灯方向的数码管应该显示对方绿灯还剩多久。工程里选简单版本是为了让波形好读二次开发时这里是最容易改出花样的地方。3.3 倒计时与数码管动态扫描seg_scan.v倒计时的数值要在两位数码管上显示出来多位数码管没法同时点亮只能靠扫描每次只点亮一位切换速度足够快人眼就看成同时亮。刷新率建议在 1 kHz 左右太高会增加动态功耗太低会肉眼可见地抖。module seg_scan #( parameter SCAN_DIV 50_000 // 50MHz / 50000 1kHz 刷新 )( input wire clk, input wire rst_n, input wire [3:0] tens, // 十位已由 BCD 转换得到 input wire [3:0] ones, // 个位 output reg [1:0] sel, // 位选低有效 output reg [7:0] seg // 段选 {dp,g,f,e,d,c,b,a}低有效 ); reg [15:0] scan_cnt; reg idx; // 0 显示十位1 显示个位 reg [3:0] cur; // 扫描节拍 always (posedge clk or negedge rst_n) begin if (!rst_n) begin scan_cnt 16d0; idx 1b0; end else if (scan_cnt SCAN_DIV - 1) begin scan_cnt 16d0; idx ~idx; // 两位轮流 end else begin scan_cnt scan_cnt 1b1; end end // 位选与当前数字 always (*) begin case (idx) 1b0: begin sel 2b10; cur tens; end // 低电平选通左位 default: begin sel 2b01; cur ones; end endcase end // 七段译码共阳写法0 表示点亮 always (*) begin case (cur) 4d0: seg 8hC0; 4d1: seg 8hF9; 4d2: seg 8hA4; 4d3: seg 8hB0; 4d4: seg 8h99; 4d5: seg 8h92; 4d6: seg 8h82; 4d7: seg 8hF8; 4d8: seg 8h80; 4d9: seg 8h90; default: seg 8hFF; // 熄灭同时避免推断出锁存器 endcase end endmodule逻辑说明idx每 50000 个时钟翻转一次两位数码管各占 1 ms整屏刷新 500 Hz看着不闪。sel低有效seg用的是共阳编码0 亮 1 灭如果你的板子是共阴把整张表取反即可。参数说明SCAN_DIV直接决定刷新率公式是CLK_FREQ / (SCAN_DIV * 位数)。改成 5000 会刷到 5 kHz看着更亮但功耗上去改成 500000 就会明显看到跳动。tens和ones这两个输入怎么来的需要把 6 位二进制秒数转成两位 BCD。常见做法是双 dabble 算法每次左移一位并加 3 修正或者干脆用/10和%10让小综合工具去推断除法器。秒数只有 0 到 63用除法器资源不心疼但要注意综合报告里是否出现「inferred divider」这类提示出现了就说明它在用资源换便利。3.4 顶层与引脚约束top.v 加 .qsf顶层模块只做三件事例化、连线、引出。它本身不含逻辑但它是 Quartus II 找端口的入口端口名一旦改了.qsf里的引脚分配会全部失配。module top ( input wire clk, // 板载晶振 input wire rst_n, // 复位按键低有效 output wire [2:0] ew_light, // 东西向 {红,黄,绿} output wire [2:0] ns_light, // 南北向 {红,黄,绿} output wire [1:0] seg_sel, // 数码管位选 output wire [7:0] seg_data // 数码管段选 ); wire tick; wire [5:0] ew_cnt, ns_cnt; clk_en #( .CLK_FREQ (50_000_000), // 换成你板子的晶振频率 .TICK_HZ (1) ) u_clk_en ( .clk (clk), .rst_n(rst_n), .tick (tick) ); traffic_fsm #( .EW_GREEN (15), .EW_YELLOW(3), .NS_GREEN (20), .NS_YELLOW(3) ) u_fsm ( .clk (clk), .rst_n (rst_n), .tick (tick), .ew_light(ew_light), .ns_light(ns_light), .ew_cnt (ew_cnt), .ns_cnt (ns_cnt) ); // 显示部分把秒数拆成十位个位后送扫描模块BCD 转换略 seg_scan u_seg ( .clk (clk), .rst_n(rst_n), .tens (4d0), .ones (ew_cnt[3:0]), .sel (seg_sel), .seg (seg_data) ); endmodule引脚约束写在.qsf里长这样编号是示例务必对着自己板子的原理图改# 时钟与复位 set_location_assignment PIN_23 -to clk set_location_assignment PIN_25 -to rst_n # 灯组先确认板子是共阳还是共阴再决定高有效还是低有效 set_location_assignment PIN_40 -to ew_light[0] set_location_assignment PIN_41 -to ew_light[1] set_location_assignment PIN_42 -to ew_light[2] # IO 电平标准必须和板子一致否则编译报错或驱动不了 set_instance_assignment -name IO_STANDARD 3.3-V LVTTL -to clk逻辑说明top把tick从分频模块传给状态机把状态机的秒数传给扫描模块数据流是单向的没有任何回环。这种单向结构让调试变得非常容易定位——灯不对就查状态机数码管不对就查扫描。参数说明IO_STANDARD不是随便填的。填错了轻则编译告警重则下载后引脚被拉坏。不同板子的 bank 电压不同原理图上通常标了3.3V或2.5V照着填就行。4. 芯片仿真testbench 怎么写才看得懂波形代码写完不代表能用。数字逻辑电路设计里芯片仿真是最便宜的一次验证改一行参数、跑几微秒仿真就能看到完整的四相位循环。上板之后才发现问题代价就是一遍遍插拔下载线。4.1 缩短时间参数跑仿真真实参数下一个完整循环要 41 秒仿真器得跑 20 多亿个时钟周期等不起。做法是例化时把分频系数改小让 1 Hz 在新的时间尺度上对应几微秒。timescale 1ns / 1ps module tb_traffic; reg clk 1b0; reg rst_n 1b0; wire tick; wire [2:0] ew_light, ns_light; wire [5:0] ew_cnt, ns_cnt; // 仿真专用把 50MHz 缩成 100Hz 计数上限加快循环 clk_en #(.CLK_FREQ(100), .TICK_HZ(1)) u_clk_en ( .clk(clk), .rst_n(rst_n), .tick(tick) ); traffic_fsm #( .EW_GREEN(4), .EW_YELLOW(2), .NS_GREEN(5), .NS_YELLOW(2) ) u_fsm ( .clk(clk), .rst_n(rst_n), .tick(tick), .ew_light(ew_light), .ns_light(ns_light), .ew_cnt(ew_cnt), .ns_cnt(ns_cnt) ); always #5 clk ~clk; // 100MHz 仿真时钟周期 10ns initial begin #100 rst_n 1b1; // 释放复位 #20000 $stop; // 跑够两个完整循环后停下 end endmodule逻辑说明CLK_FREQ改成 100意味着每 100 个仿真时钟产生一个tick状态机参数也同步缩成 4/2/5/2。这样几百纳秒就能看到一个完整相位波形窗口里一屏放得下两三个循环。参数说明#20000是仿真时长按你缩短后的总周期估算宁长勿短。$stop和$finish的区别是前者暂停、后者结束调波形时用$stop方便回头看。4.2 波形上该盯哪几个信号打开波形窗口别一股脑把所有信号都拖进去先盯这五个state、cnt、tick、ew_light、ns_light。看三件事第一tick是不是严格等间隔的单周期脉冲。如果它连着好几个周期都是高说明分频逻辑写成了电平输出状态机会连跳好几个相位。第二cnt在每个tick到来时只减一归零的下一拍state变化且cnt重新装载。如果看到cnt跳变或停在某个值不动多半是tick没接对或者位宽被截断。第三相位切换时灯色有没有重叠期。正常情况下ew_light从绿灯切黄灯切红灯任意时刻只有一位为高。如果出现两位同时为高那就是组合逻辑的case漏了分支被综合成了别的东西。4.3 上板前的一致性核对仿真通过之后还有三件事要对照着核查一遍它们不会在波形里体现但会决定下载后能不能亮引脚分配是否和原理图一一对应尤其是灯的三根线顺序红黄绿搞反了现象是「灯会亮但顺序离谱」。极性是否匹配。板子若是共阳接法seg编码要整体取反否则数码管显示的是反码看着像乱码。复位键是低有效还是高有效。工程按低有效写negedge rst_n如果板子按键按下是高电平就得改成posedge否则一上电就一直在复位状态灯全灭。5. 避坑与排查这五类问题占了九成下面这五条都是我在不同板子上反复撞见的按「现象 → 原因 → 解决」记比看手册快。5.1 编译与综合阶段现象全编译报 0 error但 Programmer 里找不到设备Start 按钮是灰的。原因器件型号没选对或者只跑了 Analysis Elaboration 没跑全编译没有生成.sof。Quartus II 的工程器件设置和实际芯片对不上时软件不会报错只会安静地不认设备。 解决Assignments Device里核对器件族和具体型号与芯片丝印逐字对上然后执行全编译确认output_files下生成了.sof最后检查下载线驱动是否装好。现象报告里出现「Warning: inferred latch for signal xxx」。原因always (*)里某条分支没给所有输出赋值综合工具只能给你补一个锁存器保持原值。 解决在每个组合always块开头先给默认值像 3.1、3.3 里那样先写ew_light 3b100;再把case的所有分支补全最后加default。5.2 仿真与上板不一致现象功能仿真波形完全正确下载到板子上灯乱跳或干脆不亮。原因测试平台里用的是缩短后的参数状态机跑得飞快掩盖了「秒数位宽不够」或者「计数器溢出」这类问题也可能仿真里没有真实的上电时序而板子上复位释放的时刻比时钟稳定还早。 解决仿真里保留一组接近真实参数的长跑至少跑完一个完整循环同时把复位逻辑改成「上电后延时若干周期再释放」别让状态机在时钟没稳的时候就开始跑。现象数码管显示的数字是对的但亮度忽明忽暗边缘有拖影。原因扫描频率太低或者位选切换和段选更新不是同一拍出现「旧数字配上新位选」的瞬间。 解决把SCAN_DIV调小到刷新率 1 kHz 以上在切换位选的那一拍先输出全灭seg 8hFF下一拍再给新数字牺牲一点亮度换干净画面。5.3 硬件与引脚现象灯全亮或者该亮的灯不亮但用万用表量引脚有电压变化。原因共阳共阴接反或者高有效/低有效写反。代码里3b001表示绿灯物理上可能是低电平点亮。 解决先查原理图上灯的接法共阳则输出低有效把译码表整体取反不确定就写一个只点亮一灯的极简工程试一下比反复改状态机快。现象按下复位键有时能复位有时不能灯的状态偶尔卡住。原因机械按键抖动一次按下产生多个边沿状态机被连续复位多次如果复位信号直接进异步复位端抖动会让电路反复进出复位态。 解决加一个简单的按键消抖模块20 ms 计数稳定后才输出或者把复位同步化处理工程里如果没带消抖模块这是二次开发第一个要补的东西。提示这五条里前三类器件选错、锁存器、参数缩短掩盖问题占了新手卡住时间的绝大部分遇到「明明代码没问题」的情况先回头查这三处。6. 二次开发把两相位改成四相位顺手把配时抽成表这个工程最容易上手的第一刀是把四相位扩成六相位加上左转。做法不复杂在localparam里补两个状态S_EW_L、S_NS_L在case里插入跳转灯色输出多一位左转箭头。麻烦的是时长参数会从四个变成六个如果继续用零散parameter改一次配时要在例化处对六个数字很容易错位。我一般的做法是把配时收进一张表// 用常量数组描述每个相位的时长索引与状态编码对应 localparam integer DUR [0:5] {15, 3, 12, 20, 3, 12}; // 东西绿 东西黄 东西左 南北绿 南北黄 南北左综合工具对常量数组的支持没问题取用时DUR[state]即可。这样加相位就是加一个数不用动跳转逻辑的结构改错概率直线下降。第二个改造点是紧急按钮插入一个最高优先级的状态任何相位下按下都立刻切到全红松开后回到初始相位重新计时。注意这个判断要放在状态转移的if最前面优先级靠代码顺序保证。第三个是夜间黄闪模式用一个拨码开关选择开启时跳过状态机、直接让黄灯按 1 Hz 翻转。实现上不需要动traffic_fsm在顶层用一个二选一选择器切换两路灯色输出就行这样原状态机完全不用改回退也简单。改完之后怎么验证我的顺序是先跑短参数仿真看相位跳转和灯色不重叠再把TICK_HZ临时设成 10 跑一遍长仿真确认倒计时数值跟着变最后上板用手机秒表掐一次完整循环看实际秒数和参数是否吻合。这套流程走下来改配时、加相位这类需求基本不会翻车。注意改完状态编码后如果.qsf里用了基于寄存器名的分配编译可能报引脚找不到。养成用端口名而不是内部信号名做引脚分配的习惯能省掉大量这种血泪经验。从那以后我每次改状态机都强制先把tick频率调高跑一遍短仿真确认跳转表没有死循环再回到真实参数——这个习惯是从一次「上板后灯卡死在黄灯」的教训里换来的当时查了两小时才发现是新加的相位没有出口。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

SK-VQA:知识增强的多模态大模型训练与应用

SK-VQA:知识增强的多模态大模型训练与应用

1. SK-VQA项目概述:当多模态大模型遇上知识增强训练 在知识驱动的视觉问答(KB-VQA)领域,现有模型常面临"知识盲区"困境——当问题涉及训练数据之外的领域知识时,性能会断崖式下跌。这正是我们团队开发SK-VQA…

📅 2026/10/30 11:47:52
动态规则引擎设计:分层架构与商业决策优化

动态规则引擎设计:分层架构与商业决策优化

1. 项目背景与核心价值在数字化运营与商业决策领域,规则模型正成为企业精细化管理的核心工具。这个系列聚焦运营、销售、产品、舆论及利益链条治理五大场景,通过数据科学方法构建可量化的决策框架。作为该系列的第七部分,我们重点探讨动态环境…

📅 2026/10/30 11:47:52
TranslationTools v3.1511.01 安装配置与取词排错指南

TranslationTools v3.1511.01 安装配置与取词排错指南

简介:围绕 Android 项目与框架中字符串资源分散、难以快速筛选和统一翻译的问题,这份 MediaTek 字符串翻译工具(STT)面向应用开发者和本地化工程师,用于简化多语言本地化流程,便于在项目内集中处理字符串资…

📅 2026/10/30 11:47:52
MORE NEWS

更多资讯

📰

4G信令全流程深度解析:从开机附着到上网的完整链路与排查指南

简介:这份资料围绕LTE信令全流程展开,面向通信工程专业学生、无线网络优化与核心网运维人员,以及准备相关认证或面试的从业者,帮助系统梳理4G网络中控制面与用户面的交互逻辑。内容从协议层与概念切入,覆盖NAS、RRC、P…

📰

obj文件解析源码:从文本到三维渲染顶点缓冲的完整指南

简介:三维模型obj格式解析源码适用于计算机图形学入门者与C开发者,帮助理解obj文件结构并掌握从文本读取到内存数据组织的完整流程。资源以Visual Studio 2013工程形式提供,核心包括ObjLoader.cpp/h源文件、Timer.h以及cube.obj、woman22.obj…

📰

Windows 免安装 JDK 17 配置指南:解压即用与多版本切换

简介:这是一份面向Java开发者的Windows平台JDK 17.0.8免安装压缩包,解压即可使用,省去繁琐的安装流程,适合初学者搭建开发环境,也方便有经验的程序员在多个项目或机器间快速切换版本。包内共416个文件,以dl…

📰

JAVA图书馆书库管理系统课程设计:Spring Boot+MyBatis完整实现与论文避坑指南

简介:这份资源是面向高校计算机相关专业毕业生的JAVA图书馆书库管理系统完整设计资料,包含论文文档与可运行源代码,适合正在准备毕业设计或需要JAVA Web项目实战参考的学生。压缩包共61个文件,约606KB,以class编译文件…

📰

论文阅读五:YOLOV11-RGBT: TOWARDS A COMPREHENSIVE SINGLE-STAGE MULTISPECTRAL OBJECT DETECTION FRAMEWORK

论文阅读笔记(五):YOLOV11-RGBT: TOWARDS A COMPREHENSIVE SINGLE-STAGE MULTISPECTRAL OBJECT DETECTION FRAMEWORK 现在可见光-红外(RGBT)多光谱检测有一堆融合方案,但大多是零散的、针对特定模型&#x…

📰

Kotlin Multiplatform for OpenHarmony 实战:OkHttp 的 ArkTS 语义复刻——拦截器链的回调世界

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

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬