FPGA学习总结

本次主要总结在FPGA学习过程中我认为一些比较重要的工程

1、呼吸灯

呼吸灯如果采用PWM,那么实现就非常简单,这里我觉得呼吸灯设计思路比较重要
首先说一下设计思路
将一个大的时钟周期,分为三个时钟周期的乘积。

parameter TIME_US = 6'd49;
parameter TIME_MS = 10'd999;
parameter TIME_S  = 10'd999;

然后设置一个判断条件,帮助设置时间间隔里的高低电平的占比,这里用了一个flag信号来控制呼吸灯的转变,先由弱变强再由强变弱。这里是利用判断s与ms的大小来控制占比的大小的渐变。

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 1'b0;
    end
    else if(!flag)begin
        led <= (cnt_s > cnt_ms)?1'b1:1'b0;
    end
    else if(flag)begin
        led <= (cnt_s > cnt_ms)?1'b0:1'b1;
    end
    else
        led <=led;
end

flag信号控制

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 1'b0;
    end
    else if (end_cnt_s) begin
        flag <= ~flag;
    end
    else begin
        flag <= flag;
    end
end

总代码

module breathe_led(
    input clk,
    input rst_n,

    output reg led
);

parameter TIME_US = 6'd49;
parameter TIME_MS = 10'd999;
parameter TIME_S  = 10'd999;

reg [5:0] cnt_us;
reg [9:0] cnt_ms;
reg [9:0] cnt_s;
reg flag;

wire add_cnt_us;//us计数器开始的标志
wire end_cnt_us;//us计数器结束的标志

wire add_cnt_ms;//ms计数器开始的标志
wire end_cnt_ms;//ms计数器结束的标志

wire add_cnt_s;//s计数器开始的标志
wire end_cnt_s;//s计数器结束的标志
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_us <= 6'd0;
    end
    else if (add_cnt_us) begin
        if (end_cnt_us) begin
            cnt_us <= 6'd0;
        end
        else begin
            cnt_us <= cnt_us +1'd1;
        end
    end
    else begin
        cnt_us <= cnt_us;
    end
end

assign add_cnt_us = 1'b1;
assign end_cnt_us = add_cnt_us && (cnt_us ==TIME_US);

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_ms <= 10'd0;
    end
    else if (add_cnt_ms) begin
        if (end_cnt_ms) begin
            cnt_ms <=10'd0;
        end
        else begin
            cnt_ms <= cnt_ms + 1'd1;
        end
    end
    else begin
        cnt_ms <= cnt_ms; 
        end
end

assign add_cnt_ms = end_cnt_us;
assign end_cnt_ms = add_cnt_ms && (cnt_ms ==TIME_MS);

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_s <= 10'd0;
    end
    else if (add_cnt_s) begin
        if (end_cnt_s) begin
            cnt_s <=10'd0;
        end
        else begin
            cnt_s <= cnt_s + 1'd1;
        end
    end
    else begin
        cnt_s <= cnt_s; 
        end
end

assign add_cnt_s = end_cnt_ms;
assign end_cnt_s = add_cnt_s && (cnt_s ==TIME_S);

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 1'b0;
    end
    else if (end_cnt_s) begin
        flag <= ~flag;
    end
    else begin
        flag <= flag;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 1'b0;
    end
    else if(!flag)begin
        led <= (cnt_s > cnt_ms)?1'b1:1'b0;
    end
    else if(flag)begin
        led <= (cnt_s > cnt_ms)?1'b0:1'b1;
    end
    else
        led <=led;
end

endmodule

要观察仿真波形,使用ModelSim软件,编写仿真文件

`timescale 1ns/1ns
module breathe_led_tb();

    reg clk;
    reg rst_n;

    wire led;

    parameter CYCLE = 20;
    parameter TIME_US = 5;
    parameter TIME_MS = 10;
    parameter TIME_S = 10;
	 
    always #(CYCLE/2) clk = ~clk;

    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        #(CYCLE);
        rst_n = 1'b1;
        #((TIME_US+1)*(TIME_MS+1)*(TIME_S+1)*CYCLE);
        $stop;
    end

    breathe_led #(
        .TIME_US (TIME_US),
        .TIME_MS (TIME_MS),
        .TIME_S (TIME_S)
    ) u_breathe_led(
        .clk (clk),
        .rst_n (rst_n),
        
        .ld (led)
    );


endmodule

二·数码管显示

数码管显示是后面经常要用到的模块,这里编写一个简单的数码管静态显示模块,并且观看仿真波形
先编写一个计时器

module time_count(//计时0.5秒,计满后输出高电平
    input clk,
    input rst_n,

    output reg flag

);

parameter MAX_NUM = 26'd24_999_999;

reg [25:0] cnt;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= 26'd0;
        flag <= 1'b0;
    end
    else if (cnt == MAX_NUM ) begin
        cnt <= 26'd0;
        flag <= 1'b1;
    end
    else begin
        cnt <= cnt + 1'd1;
        flag <= 1'b0;
    end
end

endmodule

然后编写数码管的开启模块,用于控制段选信号和位选信号还有显示的内容

module seg_led_static(
    input clk,
    input rst_n,
    input flag,

    output reg [6:0] sel,//六位的位选信号
    output reg [7:0] seg//八位的段选信号
);

reg [3:0] num;//保存当前数码管显示的数字


always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sel <= 6'b111_111;
    end
    else begin
        sel <= 6'b000_000;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        num <= 4'h0;
    end
    else if(flag)begin
        num <= num + 1'h1;
    end
    else begin
        num <= num;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        seg <= 8'b0;
    end
    else begin
        case (num)
            4'h0:    seg <= 8'b1100_0000;//匹配到后参考共阳极真值表
	        4'h1:    seg <= 8'b1111_1001;
	        4'h2:    seg <= 8'b1010_0100;
	        4'h3:    seg <= 8'b1011_0000;
	        4'h4:    seg <= 8'b1001_1001;
	        4'h5:    seg <= 8'b1001_0010;
	        4'h6:    seg <= 8'b1000_0010;
	        4'h7:    seg <= 8'b1111_1000;
	        4'h8:    seg <= 8'b1000_0000;
	        4'h9:    seg <= 8'b1001_0000;
	        4'ha:    seg <= 8'b1000_1000;
	        4'hb:    seg <= 8'b1000_0011;
	        4'hc:    seg <= 8'b1100_0110;
	        4'hd:    seg <= 8'b1010_0001;
	        4'he:    seg <= 8'b1000_0110;
	        4'hf:     seg <= 8'b1000_1110;
	      	default : seg <= 8'b1100_0000;
            endcase
    end
end

endmodule

编写顶层文件

module top_seg_led_static(
   input clk,
   input rst_n,

   output [5:0] sel,
   output [7:0] seg 
);

parameter MAX_NUM = 26'd24_999_999;
wire flag_reg;

time_count #(.MAX_NUM (MAX_NUM)) u_time_count(
    .clk (clk),
    .rst_n (rst_n),

    .flag (flag_reg)
);

seg_led_static u_seg_led_static(
    .clk (clk),
    .rst_n (rst_n),
    .flag (flag_reg),

    .sel (sel),
    .seg (seg)
);



endmodule

仿真文件编写

`timescale 1ns/1ns
module top_seg_led_static_tb();

reg clk;
reg rst_n;

wire [5:0] sel;//位选信号
wire [7:0] seg;//段选信号

parameter MAX_NUM = 9; //切换一次状态的周期数量
parameter CYCLE = 20 ;//周期

always #(CYCLE/2) clk = ~clk;

initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #(CYCLE);
    rst_n = 1'b1;
    #((MAX_NUM+1)*CYCLE*16);
    $stop;
end

top_seg_led_static #(.MAX_NUM (MAX_NUM)) u_top_seg_led_static(
    .clk (clk),
    .rst_n (rst_n),

    .sel (sel),
    .seg (seg)
);


endmodule

仿真结果
在这里插入图片描述
总结:
通过实践和练习,我逐渐熟悉了在FPGA中实现呼吸灯和数码管显示的技术,也更加了解了状态机的思想,以及对信号转换的理解。并能够理解和调整相应的设计参数,实现所需的效果。这对于深入理解数字系统设计和嵌入式系统开发具有重要意义。
在未来的学习中,我将继续拓展FPGA应用的领域,探索更多有趣和实用的设计,进一步提升我的FPGA设计能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_1482581259

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值