FPGA实验记录

发布于:2025-04-09 ⋅ 阅读:(34) ⋅ 点赞:(0)

FPGA实验记录

一、状态机思想重写 LED流水灯

(1)新建工程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2)添加流水灯实现代码

在这里插入图片描述
在这里插入图片描述
新建代码后跳转到VScode时会默认起一个名字最好另存为对应文件名否则在后面运行会报错。
新建保存完代码后将代码文件添加到工程中并将top.v设置为顶层模块
点击project然后点击Add/Remove Files in Project选项后点击上图箭头处将前面已经保存的文件添加进来然后点击Apply点击ok。
选中顶层文件右键选择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。