FPGA实验记录
文章目录
一、状态机思想重写 LED流水灯
(1)新建工程
(2)添加流水灯实现代码
新建代码后跳转到VScode时会默认起一个名字最好另存为对应文件名否则在后面运行会报错。
新建保存完代码后将代码文件添加到工程中并将top.v设置为顶层模块
选中顶层文件右键选择Set as Top…
相关代码:
状态机核心实现:
led_fsm.v
module led_fsm (
input clk,
input rst_n,
input en,
input pause,
output [5:0] led
);
parameter S_LED0 = 6'b000001;
parameter S_LED1 = 6'b000010;
parameter S_LED2 = 6'b000100;
parameter S_LED3 = 6'b001000;
parameter S_LED4 = 6'b010000;
parameter S_LED5 = 6'b100000;
reg [5:0] current_state, next_state;
// 状态寄存器(增加pause控制)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= S_LED0;
end else if (en && !pause) begin // 只有使能且未暂停时更新
current_state <= next_state;
end
end
// 下一状态逻辑保持不变
always @(*) begin
case (current_state)
S_LED0: next_state = S_LED1;
S_LED1: next_state = S_LED2;
S_LED2: next_state = S_LED3;
S_LED3: next_state = S_LED4;
S_LED4: next_state = S_LED5;
S_LED5: next_state = S_LED0;
default: next_state = S_LED0;
endcase
end
assign led = current_state;
endmodule
top .v(顶层模块:将按键输入(KEY0复位、KEY1暂停)转换为状态机控制信号;初始化状态机为运行状态(pause=0),确保上电后流水灯自动运行。)
module top (
input clk,
input rst_n, // 确保rst_n为低有效复位
input KEY0,
input KEY1,
output [5:0] led
);
wire en_1Hz;
wire key0_debounced, key1_debounced;
reg pause;
wire fsm_rst_n;
reg key1_debounced_prev;
// 修正按键极性(根据DE2-115按键电路)
key_debounce u_key0_deb (
.clk(clk),
.rst_n(rst_n),
.key_in(~KEY0), // KEY0低电平有效
.key_out(key0_debounced)
);
key_debounce u_key1_deb (
.clk(clk),
.rst_n(rst_n),
.key_in(~KEY1), // KEY1低电平有效
.key_out(key1_debounced)
);
assign fsm_rst_n = ~key0_debounced;
// 添加初始状态强制赋值
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
pause <= 1'b0; // 明确初始化暂停状态
key1_debounced_prev <= 1'b0;
end else begin
key1_debounced_prev <= key1_debounced;
// 仅当KEY1从释放到按下时触发
if (key1_debounced_prev && !key1_debounced) begin
pause <= ~pause;
end
end
end
clk_divider #(
.CLK_FREQ(50_000_000),
.OUT_FREQ(1)
) u_clk_div (
.clk(clk),
.rst_n(rst_n),
.en(en_1Hz)
);
led_fsm u_led_fsm (
.clk(clk),
.rst_n(fsm_rst_n),
.en(en_1Hz),
.pause(pause),
.led(led)
);
endmodule
key_debounce.v(实现按键消抖,提供稳定的输入信号,避免机械按键抖动干扰状态机逻辑。)
module key_debounce(
input clk,
input rst_n,
input key_in,
output reg key_out
);
parameter DEBOUNCE_TIME = 1_000_000; // 20ms@50MHz
reg [19:0] counter;
reg key_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
key_reg <= 1;
key_out <= 1'b0; // 修正复位初始值为0(匹配按键未按下状态)
end else begin
key_reg <= key_in;
if (key_reg != key_in) begin
counter <= 0;
end else if (counter < DEBOUNCE_TIME) begin
counter <= counter + 1;
end else begin
key_out <= key_in;
end
end
end
endmodule
clk_divider .v(生成1Hz的使能信号(en),控制状态机的更新节奏,确保LED每秒移动一次。)
module clk_divider #(
parameter CLK_FREQ = 50_000_000,
parameter OUT_FREQ = 1
) (
input clk,
input rst_n,
output reg en
);
localparam CNT_MAX = CLK_FREQ / OUT_FREQ - 1;
reg [25:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
en <= 0;
end else begin
if (cnt == CNT_MAX) begin
cnt <= 0;
en <= 1;
end else begin
cnt <= cnt + 1;
en <= 0;
end
end
end
endmodule
(3)配置引脚
(4)烧录
(5)实现效果
二、CPLD和FPGA芯片
(1)主要技术区别:
CPLD 的技术特性
CPLD(复杂可编程逻辑器件)基于乘积项(Product-Term)架构,由可编程的“与-或”逻辑阵列和固定数量的触发器构成,采用集中式布线资源,信号路径延迟固定且可预测。其逻辑密度较低(等效数百至数千逻辑门),适合中小规模组合逻辑设计。CPLD 集成非易失性存储器(如Flash或EEPROM),上电后无需配置即可立即运行,静态功耗极低(微瓦级),且开发工具简单,逻辑设计直接映射硬件,无需复杂时序优化。
FPGA 的技术特性
FPGA(现场可编程门阵列)基于查找表(LUT)架构,以多输入查找表为核心单元,结合分布式寄存器和可编程互连资源,支持高度灵活的分布式布线。其逻辑密度可达百万至十亿门级,集成专用硬件模块(如DSP Slice、高速收发器、Block RAM),可高效实现复杂时序逻辑和并行计算。FPGA 采用易失性SRAM存储配置,需外挂非易失性芯片加载程序,支持动态部分重配置(Partial Reconfiguration)。其延迟受布局布线影响较大,需通过时序约束工具优化,功耗较高(毫瓦至瓦级),开发流程复杂(综合、布局布线、时序收敛)。
(2) 适用场合:
CPLD 的典型应用与选型考量
CPLD 凭借其低功耗、固定时序及快速启动特性,广泛应用于逻辑复杂度较低的场景。例如,在简单控制逻辑(如状态机、接口协议转换)和胶合逻辑设计中,CPLD 可通过非易失性存储实现即用即启,替代传统分立芯片,显著降低系统成本和 PCB 复杂度。其确定性延迟特性使其成为工业控制、电机驱动等实时性要求严苛场景的理想选择;同时,极低的静态功耗和无需外部配置的特性,也契合便携设备、电源管理等对功耗敏感且需快速响应的需求。在选型时,若项目需求聚焦于中小规模逻辑、确定性时序或低成本嵌入式控制,CPLD 通常是更优解。
FPGA 的典型应用与选型考量
FPGA 则以其高逻辑密度和可重构灵活性,专注于处理复杂算法与高速数据流任务。例如,在数字信号处理(DSP)、AI 推理或 5G 通信基带等场景中,FPGA 可通过并行计算架构和分布式布线资源实现高效加速。其支持动态部分重配置的能力,使其在原型验证、ASIC 仿真等需功能动态调整的系统中极具优势。尽管 FPGA 的功耗和成本较高,但其在大规模并行计算(如密码学加速、实时大数据分析)及高速接口(PCIe、以太网)领域性能远超 CPLD。因此,若项目涉及复杂算法、高吞吐量数据处理或需要开发灵活性,FPGA 是必然选择,尤其在高性能需求优先于功耗控制的场景中表现突出。
三、 hdlbits-组合逻辑练习
(1)7420chip
对两组四输入端口进行与操作(AND),然后对结果取反(NOT),最后输出。
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
(2)电路B
分析波形图:
当 x 和 y 不同时(即一个为高电平,另一个为低电平),异或运算的结果为1,z 为0。
当 x 和 y 相同时(即都为高电平或都为低电平),异或运算的结果为0,z 为1。
总结:z的结果与x、y异或运算结果相反,所以可以异或运算之后取反得到z。
module top_module (
input x,
input y,
output z
);
assign z = ~(x ^ y);
endmodule
(3)ring or vibrate
对于振动电机(motor):
只有在“有来电”且“处于振动模式”时,才应开启。
逻辑表达式为:motor = ring AND vibratemode。
对于振铃器(ringer):
只有在“有来电”且“不处于振动模式”时,才应开启。
逻辑表达式为:ringer = ring AND NOT vibratemode。
module topmodule (
input ring,
input vibratemode,
output ringer, // 控制振铃器
output motor // 控制振动电机
);
assign motor = ring & vibratemode; // 当有来电且处于振动模式时,开启振动电机
assign ringer = ring & (!vibratemode); // 当有来电且不处于振动模式时,开启振铃器
endmodule
(4)4-bit加法器
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum
);
assign sum = x + y;
endmodule
(5)Kmap1
module top_module(
input a,
input b,
input c,
output out );
assign out = a | b | c;
endmodule
(6)Kmap2
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = (~a & ~d) | (~b & ~c) | (a & c & d) | (~a & c & b);
endmodule
四、总结
本次实验通过Verilog硬件描述语言用状态机思想实现了LED流水灯的设计与控制。在使用Quartus实现流水灯的过程中加强了对软件使用熟练度。此外,还练习了组合逻辑设计,包括7420芯片模拟、异或运算、振动模式控制及4-bit加法器设计等,巩固了数字电路设计的基础知识,提升了实际操作能力。
五、参考文献
HDLBits练习 Circuits;Karnaugh Map to Circuits
HDLBits练习 Circuits;Combinational Logic;Multiplexers
HDLBits练习 Circuits;Combinational Logic;Arithmetic Circuits
流水灯部分代码来自 deepseek。