恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

FPGA交通灯控制电路设计:Verilog状态机与Quartus II仿真实战

  • 首页
  • 资讯中心
  • /
  • FPGA交通灯控制电路设计:Verilog状态机与Quartus II仿真实战

相关资讯

酒吧点餐小程序系统开发实战:从需求分析到上线部署指南 2026/9/9 1:08:01
智能体工作流工具深度对比:11款AI Agent编排平台选型指南 2026/9/9 1:08:01
蚊子目标检测数据集详解:YOLO与VOC格式训练全流程 2026/9/9 1:08:01

最新资讯

PHP转Java实战指南:从架构设计到性能调优的迁移方法论
NumPy高效指南:从安装、广播机制到性能优化实战
给DeepSeek Harness接入Elastic APM:Agent成本、失败与行为可观测实践
长江经济带GIS矢量图制作全流程:从数据获取到拓扑检查与实战应用
量子计算机真能在2029年破解比特币吗?技术解析与应对策略
新手怎么弄文件压缩打包?三步生成zip压缩包,格式密码分卷一次讲清

今日推荐

基于MongoDB的图书管理系统:数据建模与Spring Boot+Vue实战
Claude Code安装配置全攻略:从零开始用上终端AI编程助手
tmux 会话管理与终端复用:AI 编程工作流的调度中枢实战

本周热门

超人会飞不算本事:系统稳定依赖清晰规则与边界设计
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论
基于CNN的调制信号识别:MATLAB实现时频图分类实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

FPGA交通灯控制电路设计:Verilog状态机与Quartus II仿真实战

发布时间:2026/9/9 1:13:01
FPGA交通灯控制电路设计:Verilog状态机与Quartus II仿真实战 简介这是一份基于QuartusⅡ平台设计的十字路口交通灯控制电路工程文件面向数字逻辑电路设计学习者、课程设计学生及EDA仿真入门者。方案实现甲车道主道通行75秒、乙车道辅道通行25秒的交替运行并支持按键模式切换黄灯先亮3秒且每秒闪亮一次完整覆盖状态转换、定时与闪烁逻辑。压缩包共167个文件约2.42MB包含原理图文件bdf、仿真波形vwf、BSF符号、RPT报告以及cdb、hdb、qmsg等各类Quartus工程中间文件涵盖从设计输入、编译综合到仿真验证的完整流程。已有3291人学习浏览适合用于理解状态机设计、分频计数及交通灯控制逻辑的实战参考。 又到了数字电路课设集中交付的季度后台问得最多的就是“QuartusⅡ交通灯控制电路”这套东西。我手上这个名为QuartusⅡ交通灯控制电路.rar的工程是当年做课设时从零到一攒出来的完整项目里面有Verilog源码、分频和状态机设计、ModelSim仿真脚本、引脚约束说明还有最终的课设报告。这个项目说难不难说简单也不简单——它本质是一个标准的有限状态机加计数器应用恰好把FPGA开发里最核心的几个概念全串起来了非常适合拿来练手。交通灯控制电路能做什么一句话用一片FPGA芯片模拟十字路口的红绿灯调度主干道和支干道按照固定时序轮流放行倒计时在数码管上实时显示黄灯作为状态切换的过渡信号。适合谁看正在准备数字电路课程设计的学生、刚接触Quartus II的FPGA新手还有那些想找一份能真正跑通、能讲清楚原理的课设方案的兄弟。这篇我就把整个设计思路、代码结构、仿真验证、上板调试全部摊开讲保证你能复现也能在答辩时讲明白。1. 交通灯控制电路需求拆解与方案选型1.1 十字路口的控制需求到底有哪些别急着写代码先想清楚一个十字路口需要哪些信号。典型的课设场景是主干道和支干道交叉每个方向的灯组都包含红、黄、绿三色。放行逻辑严格按时间片轮转主干道绿灯放行一段时间变成黄灯作为过渡然后主干道红灯亮起支干道绿灯放行再经过黄灯过渡回到主干道绿灯如此循环。倒计时数字要从设定值逐秒递减到0这个递减过程必须显示在数码管上。我当年用的时序配置是这样的主干道绿灯25秒、黄灯5秒支干道绿灯20秒、黄灯5秒一个周期总时长55秒。你也可以按课设任务书的参数调整关键是理解状态转移的规则。如果有余力还可以扩展夜间模式——黄灯全闪烁或者紧急模式——两个方向都亮红灯这个后面单独说。需求分析的结果直接决定状态机的状态数量。基础版只需要四个状态主干道绿灯/支干道红灯、主干道黄灯/支干道红灯、主干道红灯/支干道绿灯、主干道红灯/支干道黄灯。别想复杂了大部分课设只要把这四个状态的跳转时间和输出逻辑写对分数就不会低。1.2 为什么选FPGA而不是单片机这是我被问得最多的问题。一个十字路口控制用51单片机、STM32也能做为什么课设偏偏要用FPGA原因有两个。第一教学目的决定方案。数字电路课设考察的核心是时序逻辑、状态机设计、组合逻辑译码这些硬件描述层面的能力而不是写C语言跑while循环。FPGA天然是并行硬件架构每个always块对应一段独立的逻辑电路状态和输出之间的关系看得见摸得着和课本上的状态转移图完美对应。单片机方案说白了是软件思维写起来反而体现不出“数字电路设计”这个主题。第二Quartus II这套EDA工具链本身就是为FPGA开发设计的。它有完整的编辑、综合、布局布线、仿真、下载流程工程管理、引脚分配、时序约束这些操作都是从业者必须掌握的基本功。在实验室里验证起来也方便——直接把编译生成的.sof文件下载到开发板就能看效果。1.3 整体架构三个模块各司其职交通灯控制电路在架构上拆成三个模块缺一不可分频模块开发板上的有源晶振通常是50MHz这个频率太快了必须分频得到1Hz的秒脉冲作为整个状态机的节拍输入。状态控制模块这是核心接收秒脉冲后驱动状态机依次跳转输出主干道和支干道红黄绿三色信号的控制电平。倒计时与译码显示模块根据当前状态实时计算倒计时数值并把二进制计数转成七段数码管能识别的段码。这三个模块用顶层文件连接起来。分频模块给状态机提供时钟状态机给倒计时模块提供状态信息和计数初值倒计时模块内部自己完成逐秒递减和译码输出。模块划分清晰之后每个文件单独调试都很方便这也是工程上推荐的“高内聚低耦合”思路。2. Quartus II环境搭建与工程创建实操2.1 版本选择13.1还是18.1 Lite很多新手第一件事就是去下载最新版Quartus结果发现新版本对老器件支持不友好甚至安装包大到离谱。我建议按你的开发板芯片来选版本。如果实验室的板子用的是Cyclone IV系列比如EP4CE6E22那直接装Quartus II 13.1这个版本最成熟稳定网上教程也最多对老器件支持非常完美。如果你手里是MAX 10系列的板子就需要用新版Quartus Prime Lite18.1或者20.1都可以。MAX 10在Quartus II 13.1里是不支持的这个坑我踩过当年拿到新板子用老版本建工程器件列表里怎么也找不到对应型号折腾了半天才发现是版本兼容性问题。安装的时候有几个经验一是关掉杀毒软件再解压安装包否则license生成工具容易被误删二是安装路径不要有中文和空格三是只装你需要的那几个组件比如Quartus软件本体加对应器件支持包别再勾选一大堆用不到的器件库能省好几个G空间。2.2 新建工程的七个步骤工程创建的流程我按实际操作的顺序列出来打开Quartus II进入File → New Project Wizard。指定工程路径和工程名工程名建议用英文如traffic_light路径不要有中文和空格。选择顶层实体名称这里必须和顶层模块名一致否则后期会报错。添加已有设计文件如果是全新项目直接跳过。选择目标器件。如果你用的是开发板按板子上的芯片具体型号选否则直接选Auto也可以。设置EDA工具选项仿真工具可以选ModelSim-Altera也可以暂时不管用Quartus自带的仿真。确认信息后点Finish完成创建。其中第3步是新手重灾区。顶层实体名在新建工程时写成了top_level结果Verilog文件里模块名写的是traffic_light编译必然报错。我的习惯是先想好模块名再建工程保证两者从头到尾一致。提示工程建立之后File → New → Verilog HDL File创建源码文件保存时文件名必须和模块名完全一致。traffic_light模块就存成traffic_light.v大小写都要对上。2.3 工程文件怎么组织这个项目文件不多但别把所有文件都堆在工程根目录。我的习惯是分三个文件夹rtl放所有Verilog源码sim放testbench仿真文件doc放设计报告和引脚说明。工程会自动生成.qpf工程文件、.qsf配置文件和.db数据库目录这些保持默认位置即可不要手动去改。3. 核心Verilog代码实现与仿真验证3.1 秒脉冲分频器怎么设计开发板的50MHz时钟意味着每秒有5000万个时钟周期。要得到1Hz的秒脉冲最简单的思路是计数到2500万次时翻转一次电平这样翻转周期就是2秒正好得到一个占空比50%的1Hz信号。这里有个位宽计算的细节2500万需要25位二进制数来表示2的24次方是1600多万不够用2的25次方是3300多万所以计数器位宽取25位或者26位都行。初学者常犯的错是把计数器位宽写小了仿真的时候没问题一上板发现分频完全不准确就是这个原因。代码实现如下module clk_div( input wire clk_50m, input wire rst_n, output reg clk_1s ); reg [25:0] cnt; always (posedge clk_50m or negedge rst_n) begin if (!rst_n) begin cnt 26d0; clk_1s 1b0; end else if (cnt 26d24_999_999) begin cnt 26d0; clk_1s ~clk_1s; end else begin cnt cnt 1b1; end end endmodule计数到24999999的时候清零并翻转输出这样clk_1s的周期正好是2秒不对等等——计数器从0数到24999999一共是2500万个50MHz周期也就是0.5秒翻转一次后高电平持续0.5秒、低电平持续0.5秒合起来正好1秒。这个逻辑没错。3.2 交通灯状态机这样写才清晰状态机是整个设计的灵魂推荐用三段式写法状态跳转时序逻辑、状态转移条件组合逻辑、输出逻辑。不过课设这种简单场景用一段式或两段式也完全够用关键是状态定义要一目了然。我用的四状态定义如下module traffic_light_ctrl( input wire clk_1s, input wire rst_n, output reg main_green, output reg main_yellow, output reg main_red, output reg branch_green, output reg branch_yellow, output reg branch_red ); localparam S0 2d0; // 主干道绿灯, 支干道红灯, 持续25秒 localparam S1 2d1; // 主干道黄灯, 支干道红灯, 持续5秒 localparam S2 2d2; // 主干道红灯, 支干道绿灯, 持续20秒 localparam S3 2d3; // 主干道红灯, 支干道黄灯, 持续5秒 reg [1:0] state; reg [4:0] cnt; always (posedge clk_1s or negedge rst_n) begin if (!rst_n) begin state S0; cnt 5d0; end else begin case (state) S0: begin if (cnt 5d24) begin state S1; cnt 5d0; end else begin cnt cnt 1b1; end end S1: begin if (cnt 5d4) begin state S2; cnt 5d0; end else begin cnt cnt 1b1; end end S2: begin if (cnt 5d19) begin state S3; cnt 5d0; end else begin cnt cnt 1b1; end end S3: begin if (cnt 5d4) begin state S0; cnt 5d0; end else begin cnt cnt 1b1; end end endcase end end always (*) begin main_green 1b0; main_yellow 1b0; main_red 1b0; branch_green 1b0; branch_yellow 1b0; branch_red 1b0; case (state) S0: begin main_green 1b1; branch_red 1b1; end S1: begin main_yellow 1b1; branch_red 1b1; end S2: begin main_red 1b1; branch_green 1b1; end S3: begin main_red 1b1; branch_yellow 1b1; end endcase end endmodule组合逻辑输出前先给所有输出赋默认值再在case里覆盖这样能避免生成锁存器是必须养成的好习惯。状态编码直接用了2位二进制因为只有四个状态完全够用。独热码在这些低速应用中反而浪费触发器资源。3.3 倒计时和数码管译码倒计时模块需要根据当前状态确定初始值。主干道绿灯亮时从25开始倒数黄灯亮从5开始支干道绿灯从20开始、黄灯从5开始。状态机每过一秒让计数值减1减到0时下一拍就会跳转状态。数码管显示用的是共阴极或共阳极七段码课设通常用两位数码管分别显示十位和个位。十进制数拆成两位BCD码非常方便因为数码管是逐位动态扫描的。下面是七段译码的核心逻辑我用的是共阴极0到9的段码如下case (data) 4d0: seg 7b0111111; // 0 4d1: seg 7b0000110; // 1 4d2: seg 7b1011011; // 2 4d3: seg 7b1001111; // 3 4d4: seg 7b1100110; // 4 4d5: seg 7b1101101; // 5 4d6: seg 7b1111101; // 6 4d7: seg 7b0000111; // 7 4d8: seg 7b1111111; // 8 4d9: seg 7b1101111; // 9 endcase段码数值直接套用不需要背网上查表就行重点是要搞清楚共阴共阳的区别。共阳极数码管需要把这段码逐位取反接反了错误表现为某个数字的某个段一直不亮。3.4 仿真时怎么快速验证仿真这部分很多人偷懒直接上板测实测下来效率特别低。我建议至少在ModelSim里跑一遍功能仿真确认状态跳转和倒计时都正确再下载到板子。仿真有两个加速技巧。一是testbench里把时钟周期设成真实值比如50MHz对应20ns的period但把分频器的目标计数值临时改小比如改成5计数就翻转这样仿真波形里每秒都能看到状态变化不然要等虚拟时间跑完2500万个周期仿真器会卡得怀疑人生。二是直接在testbench里给clk_1s一个周期为1秒的时钟信号绕过内部的分频模块单独测状态机和倒计时逻辑是否正常。initial begin rst_n 1b0; #10 rst_n 1b1; // 直接测状态机, clk由testbench提供 repeat (30) begin #(1 second / 2) clk_1s ~clk_1s; // 这类写法需要在testbench里定义real类型或换算成整数纳秒 end end注意Verilog里不能直接写1 second这样的时间单位需要换算成纳秒。我的做法是定义localparam PERIOD 1_000_000_000然后#(PERIOD/2)翻转时钟。仿真通过之后再把真实的50MHz时钟和分频模块接回来做全系统验证。4. 引脚分配、在线调试与常见报错排查4.1 引脚分配的正确姿势代码编译通过只是第一步要让开发板上的灯真正亮起来必须把FPGA引脚的逻辑信号映射到物理引脚上。打开Assignments → Pin Planner根据开发板原理图把每个信号分配到对应引脚。比如板子上时钟接在PIN_E1复位按键接在PIN_B1主干道绿灯接在PIN_A1等。引脚分配有三个坑要提。第一分配完引脚后必须重新编译直接下载旧生成的.sof文件不会生效。第二有些开发板LED是高电平点亮有些是低电平点亮需要根据原理图改代码里的输出极性不然逻辑对的上但灯就是不亮。第三引脚不要乱分配要避开VCC和GND引脚Pin Planner里灰色的引脚就别选了。注意SignalTap II和ISSP也都是通过JTAG接口调试的下载器和FPGA的JTAG链路必须正常。如果Programmer界面识别不到设备优先检查USB-Blaster驱动有没有装好。4.2 编译报错119013等典型问题怎么破网上搜“quartus运行提示119013”能搜到大量帖子说明这错误出镜率很高。这个错误代码本质上是Fitter阶段报出的错误它前面总会跟着一行具体描述最常见的诱因是I/O引脚分配和相关约束冲突。我遇到过的情况是工程器件的封装类型和引脚约束文件里的引脚编号不匹配导致布局布线无法进行。排查顺序建议按这三步来检查器件型号Project → Settings里确认选择的封装和速度等级和板子实际芯片完全一致尤其是EP4CE6E22C8N这种完整型号中间E22和C8都不能错。检查引脚分配Pin Planner里有没有重复分配引脚或者把同一个信号分配到了两个引脚。检查文件和约束冲突如果工程是从别人那里拷来的注意.qsf文件里的引脚约束是否和你当前工程匹配特别是换了板子或者换了芯片型号之后老工程的约束可能直接导致119013。4.3 板上信号怎么抓数值SignalTap II入门调试FPGA最头疼的是内部信号看不见这时候SignalTap II逻辑分析仪就派上用场了。它就是Quartus自带的在线逻辑分析仪相当于Vivado里的ILA可以实时抓取FPGA内部信号的波形。操作步骤Tools → SignalTap II Logic Analyzer打开界面新建.stp文件选择采样时钟通常选系统时钟50MHz然后从信号列表里添加要观察的节点比如state、cnt、main_green这些内部信号。设置采样深度1024即可触发条件可以设为state变化。保存后重新编译下载到板子里点击运行触发就能在Logic Analyzer窗口看到真实运行时的波形。踩过一个坑有些内部信号在综合时被优化掉了在SignalTap信号列表里找不到。解决办法是在Verilog代码里给信号加(* keep)属性比如(keep *) reg [1:0] state;综合工具就会保留这个信号。调试完可以去掉这个属性重新编译。4.4 类似Vivado VIO功能的在线调试IP核Vivado用多了的人会怀念VIO那种可以在线读写内部寄存器变量的功能。Quartus对应的方案是In-System Sources and Probes简称ISSP在MegaWizard Plug-In Manager里可以生成。这个IP核实例化之后JTAG上位机界面可以实时给FPGA内部信号赋值或者读取内部状态。比如你可以用ISSP在板子运行时强制把状态机拉到某个状态模拟紧急情况的输入不需要重新编译工程极大提高了调试效率。ISSP和SignalTap的定位不一样SignalTap负责抓波形看时序ISSP负责在线读写信号两者搭配使用基本就能覆盖课设阶段的所有调试需求。5. 课设避坑清单与个人体会5.1 我从这个项目里踩过的几个坑第一个坑是分频计数器位宽不够。仿真的时候功能正常下载到板上发现倒计时不准确检查了很久才发现计数器溢出导致分频频率不对。所以写代码前用计算器估算位宽别偷懒。第二个坑是组合逻辑输出没有给默认值。写完状态机第一次编译Quartus生成了锁存器警告当时没在意结果仿真发现输出有莫名其妙的毛刺。解决方式就是3.2节里写的case前先把所有输出信号赋上默认值。第三个坑是引脚分配用了一个被占用的引脚编译时报了冲突错误。Pin Planner里灰色或者带锁标记的引脚不要碰。第四个坑是仿真时没有设置测试平台顶层。Quartus做仿真时需要把testbench设为顶层否则ModelSim会默认用设计顶层跑结果看不到任何输入激励。第五个坑是下载器驱动。Windows系统下USB-Blaster驱动经常失效现象是Programmer界面显示No Hardware。解决方案是手动指定驱动路径到Quartus安装目录下的drivers文件夹不用去官网单下载。5.2 关于扩展功能的一些思路如果你的课设要求不只是基础红绿灯可以考虑加夜间模式——用一个拨码开关控制黄灯全部闪烁这个只需要在状态机前面加一个判断当模式信号有效时跳过正常状态跳转逻辑让所有黄灯以1Hz频率闪烁。还可以做紧急车辆优先模式按下按键后强制所有方向红灯让某个方向的绿灯提前亮起。这个方案需要引入按键消抖在FPGA里做20ms左右的延时计数消抖顺便把异步复位、按键输入这些知识点都涵盖了答辩时能多讲不少内容。交通灯这个题材之所以在课设里经久不衰就是因为它的复杂度刚好卡在一个非常合适的位置——再简单就体现不了状态机和时序逻辑的核心思想再复杂就容易让初学者陷进去。我个人做完这个项目最大的体会是FPGA开发里“先仿真、再上板”这个流程真的不能省很多看起来玄学的硬件问题在仿真阶段提前发现能省下大把调板时间。最后再分享一个小经验代码里多用localparam给状态和参数命名不要写裸的数字一个月后你自己回来看代码也能一眼看懂。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号