【FPGA】状态机思想回顾流水灯
一、LED流水灯实现
1. 基本要求
- 用状态机思想写一个 LED流水灯的FPGA代码
- 写出仿真测试代码,用Modelsim进行仿真分析
- DE2-115板上验证
2. 状态机思想
用状态机思想的话,流水灯通常可以用几个状态来表示不同的LED亮的位置。
比如,每个状态对应一个LED亮,然后通过状态转移来实现流动的效果。由于我们流水灯是8个灯亮,所以对应8个状态。
所以,状态机的状态定义可能如下:
状态S0: LED[0]亮
状态S1: LED[1]亮
…
状态S7: LED[7]亮
流水灯就是一个状态持续一段时间再进入下一个状态。
3. 关键代码
// File: led_flow.v
module led_flow(
input clk, // 50MHz时钟 (DE2-115 PIN_Y2)
input rst_n, // 复位信号 (低电平有效)
output reg [7:0] led// LED输出 (DE2-115 LEDG7-LEDG0)
);
// 状态定义
localparam S0 = 3'b000; // 初始状态:LED0亮
localparam S1 = 3'b001;
localparam S2 = 3'b010;
localparam S3 = 3'b011;
localparam S4 = 3'b100;
localparam S5 = 3'b101;
localparam S6 = 3'b110;
localparam S7 = 3'b111;
// 内部信号
reg [2:0] state; // 当前状态
reg [24:0] cnt; // 分频计数器
wire en; // 状态切换使能(0.5Hz)
// 0.5Hz分频(0.5秒切换)
assign en = (cnt == 25'd24_999_999); // 50MHz/(25M+1) ≈ 0.5Hz
// 分频计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 0;
else if(en) cnt <= 0;
else cnt <= cnt + 1;
end
// 状态机主逻辑
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= S0;
led <= 8'b0000_0001; // 初始状态
end
else if(en) begin
case(state)
S0: begin led <= 8'b0000_0010; state <= S1; end
S1: begin led <= 8'b0000_0100; state <= S2; end
S2: begin led <= 8'b0000_1000; state <= S3; end
S3: begin led <= 8'b0001_0000; state <= S4; end
S4: begin led <= 8'b0010_0000; state <= S5; end
S5: begin led <= 8'b0100_0000; state <= S6; end
S6: begin led <= 8'b1000_0000; state <= S7; end
S7: begin led <= 8'b0000_0001; state <= S0; end
default: state <= S0;
endcase
end
end
endmodule
4. 仿真测试
写完代码后,参考连接博客进行仿真。
Quartus使用步骤及联合Modelsim仿真教程-
知安的小白
操作步骤这篇博客讲的很清楚了,一同操作后的效果截图如下
仿真代码(tb_led_flow.v)
// File: tb_led_flow.v
`timescale 1ns/1ps
module tb_led_flow();
reg clk;
reg rst_n;
wire [7:0] led;
// 实例化被测模块
led_flow uut(
.clk(clk),
.rst_n(rst_n),
.led(led)
);
// 生成50MHz时钟
initial begin
clk = 0;
forever #10 clk = ~clk; // 20ns周期=50MHz
end
// 测试激励
initial begin
// 初始化
rst_n = 0;
#100;
rst_n = 1;
// 观察10个状态周期
#100000000; // 仿真10ms(实际应仿真更长时间)
$stop;
end
endmodule
下面是仿真波形:
5. 效果演示
[FPGA]状态机思想回顾流水灯演示效果
二、CPLD和FPGA
1. 技术区别
特性 | 特性 | FPGA |
---|---|---|
结构 | 乘积项逻辑 | 查找表(LUT)结构 |
逻辑容量 | 通常<10万门 | 可达数百万逻辑单元 |
布线结构 | 固定互联 | 可编程互联 |
时序特性 | 确定延迟 | 布线依赖延迟 |
存储资源 | 有限 | 包含专用Block RAM |
配置方式 | 非易失,上电即用 | 通常需要外部配置芯片 |
功耗 | 低静态功耗 | 高动态功耗 |
适用场景 | 胶合逻辑、状态机 | 复杂算法、并行处理 |
2. 应用场景
CPLD典型应用:
接口协议转换(UART、SPI)
简单状态机控制
地址译码电路
上电时序管理FPGA典型应用:
数字信号处理(FIR滤波器)
高速接口(PCIe、DDR)
图像处理流水线
协议加速(TCP/IP Offload)
三、HDLbits组合逻辑题目
HDLbits问题集(Verilog)精选题目及解答
题目1:Exams/m2014 q4g
module top_module (
input in1,
input in2,
input in3,
output out);
assign out = (~(in1^in2)^in3);
endmodule
题目2:Gates
Module Declaration
module top_module(
input a, b,
output out_and,
output out_or,
output out_xor,
output out_nand,
output out_nor,
output out_xnor,
output out_anotb
);
大概意思就是写个逻辑语句实现名称。
module top_module(
input a, b,
output out_and,
output out_or,
output out_xor,
output out_nand,
output out_nor,
output out_xnor,
output out_anotb
);
assign out_and=a&b;
assign out_or=a|b;
assign out_xor=a^b;
assign out_nand=~(a&b);
assign out_nor=~(a|b);
assign out_xnor=~(a^b);
assign out_anotb=a&(~b);
endmodule
题目3:Arithmetic Circuits–Adder(加法器设计)
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum);
assign sum = x + y;
endmodule
题目4:7420
74LS20芯片内部逻辑电路如下,由两个nand(与非门)组成。需要写个语句实现7420功能。
module top_module (
input p1a, p1b, p1c, p1d,
output p1y,
input p2a, p2b, p2c, p2d,
output p2y );
assign p1y=~(p1a&p1b&p1c&p1d);
assign p2y=~(p2a&p2b&p2c&p2d);
endmodule
题目5:Truthtable1
按真值表实现电路。
如果数电学的不好不知道怎么办的话,可以用logisim,点击Project->Analyze Circuit->Table:
再点击Build Circuit就生成电路图了。
module top_module(
input x3,
input x2,
input x1, // three inputs
output f // one output
);
assign f=((~x3)&x2)|(x1&x3);
endmodule
四、实验总结
本次实验掌握了状态机编程思想,事实上,状态机思想也更简易更容易想到。