状态机实现LED流水灯
本次实验,我们将利用状态机的思想来进行Verilog编程实现一个LED流水灯,并通过Modelsim来进行模拟仿真,再到DE2-115开发板上进行验证。 首先进行主要代码的编写。
module led (input sys_clk,input sys_rst_n,output reg [7:0] led);// 状态定义(8个状态)parameter S0 = 3'd0,S1 = 3'd1,S2 = 3'd2,S3 = 3'd3,S4 = 3'd4,S5 = 3'd5,S6 = 3'd6,S7 = 3'd7;parameter MAX_COUNT = 25_000_000; // 0.5秒@50MHzreg [2:0] current_state; // 当前状态寄存器reg [2:0] next_state; // 下一状态寄存器reg [25:0] counter; // 26位定时计数器// 状态寄存器always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n)current_state <= S0; // 异步复位else current_state <= next_state; // 正常状态转移end// 计数器逻辑always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n)counter <= 0; // 复位清零else if (current_state != next_state)counter <= 0; // 状态切换时清零elsecounter <= counter + 1;end// 状态转移逻辑always @(*) begincase (current_state)S0: next_state = (counter == MAX_COUNT-1) ? S1 : S0;S1: next_state = (counter == MAX_COUNT-1) ? S2 : S1;S2: next_state = (counter == MAX_COUNT-1) ? S3 : S2;S3: next_state = (counter == MAX_COUNT-1) ? S4 : S3;S4: next_state = (counter == MAX_COUNT-1) ? S5 : S4;S5: next_state = (counter == MAX_COUNT-1) ? S6 : S5;S6: next_state = (counter == MAX_COUNT-1) ? S7 : S6;S7: next_state = (counter == MAX_COUNT-1) ? S0 : S7;default: next_state = S0;endcaseend// 输出逻辑(循环右移模式)always @(*) begincase (current_state)S0: led = 8'b00000001;S1: led = 8'b00000010;S2: led = 8'b00000100;S3: led = 8'b00001000;S4: led = 8'b00010000;S5: led = 8'b00100000;S6: led = 8'b01000000;S7: led = 8'b10000000;default: led = 8'b00000001;endcaseendendmodule
然后为了能在Modelsim中进行模拟仿真,我们还需要编写一个测试模块代码。
`timescale 1ns/1psmodule tb_led();reg sys_clk;reg sys_rst_n;wire [7:0] led;// 实例化被测试模块(缩小计数器值便于仿真)led_fsm_8bit #(.MAX_COUNT(3)) uut (.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.led(led));// 生成50MHz时钟initial beginsys_clk = 0;forever #10 sys_clk = ~sys_clk; // 20ns周期=50MHzend// 测试流程控制initial begin// 初始化sys_rst_n = 0;#20; // 等待一个时钟上升沿sys_rst_n = 1;// 运行2000ns(观察完整状态周期)#2000;$finish;end// 监控输出initial begin$monitor("Time = %tns | State = %d | LED = %08b",$time, uut.current_state, led);endendmodule
编写完测试代码并成功编译后,就可以准备进行模拟仿真了,首先对仿真文件进行绑定,选择Setting-->EDA Tool Settings-->Simulation。
然后就可以进行模拟仿真了。
仿真完成后,进行DE2-115开发板的实物验证。首先对管脚进行配置。
把程序烧录到开发板,就可以看到效果。
CPLD和FPGA
对比维度 | CPLD | FPGA |
---|---|---|
核心架构 | 基于乘积项(Product-Term)和宏单元(Macrocell),结构简单,逻辑资源有限 | 基于查找表(LUT)和寄存器,逻辑单元(LE)灵活组合,资源丰富 |
存储技术 | 采用EEPROM或Flash工艺,非易失性,无需外部配置芯片 | 基于SRAM工艺,掉电丢失配置数据,需外部存储器 |
资源规模 | 逻辑单元较少(几十至几百宏单元),适合小规模逻辑设计 | 逻辑单元可达数百万级,支持大规模复杂设计 |
时序特性 | 连续式布线,延迟均匀且可预测 | 分段式布线,延迟不可预测 |
功耗 | 静态功耗较高,适合低复杂度场景 | 动态功耗优化更好,适合高性能计算 |
编程灵活性 | 编程次数有限(约1万次),逻辑固化后不可重构 | 支持无限次动态重构,灵活适配不同算法 |
启动时间 | 上电即用,无需配置时间 | 需从外部加载配置数据,存在启动延迟 |
CPLD的典型应用场景:简单逻辑控制比如状态机、地址译码、总线控制等组合逻辑密集型任务;某些接口的转换,比如电平转换(TTL与LVDS)、I/O扩展、协议适配(SPI转UART);胶合逻辑,这在复杂系统中作为“粘合剂”,可以连接不同功能模块(DSP与存储器间的控制逻辑);低功耗需求场景比如工业控制、仪器仪表中的简单逻辑处理。
FPGA的典型应用场景:复杂时序逻辑比如如高速数据处理(通信协议处理、雷达信号处理)、实时控制(自动驾驶传感器融合);并行计算加速:数字信号处理(DSP)、AI推理、图像处理(ISP算法加速);动态重构系统,常用于需要硬件功能随需求变化的场景(软件定义无线电);高性能计算如数据中心加速、加密解密、科学仿真等对算力要求高的领域。
从设计复杂度上看,CPLD适用于门数小于1万的设计,FPGA更适合大规模设计(>10万门)。从时序要求上看,CPLD延迟可预测,适合实时性强的控制逻辑;FPGA虽延迟不可预测,但通过时序约束优化可实现高频运行(如500MHz以上)。从功耗与成本上看,CPLD成本低但功耗较高,FPGA能效比更优但需要额外配置芯片。从技术融合趋势上看,现代CPLD(如Altera MAX系列)逐渐采用FPGA的LUT架构,界限模糊,但核心差异仍存在。
hdlbitsFPGA组合逻辑练习
D触发器
D锁存器
Two gates
计数器1-12
简单电路A
总结
本次实验通过状态机设计方法,成功实现了LED流水灯的Verilog编程,并在Modelsim中进行了仿真验证,最终在DE2-115开发板上进行了实物验证。此外,通过对CPLD和FPGA的对比分析,进一步加深了对这两种器件的理解,为今后的设计提供了参考。