FPGA预科实习项目总结

一.项目内容

我参加的实习培训一共有十天我们的学习内容有:按键控制led流水灯,led呼吸灯,按键消抖,数码管显示

1.led流水灯

1.流水灯模块设计

在这里插入图片描述

2.实验代码

module led(
        input                   clk,
        input                   rst_n,

        output  reg     [3:0]   led 

);

//计时1s
parameter   MAX1S = 26'd49_999_999 ;
parameter   MAX0_2S = 26'd9_999_999;

reg [25:0]  cnt_1s;//1s计数寄存器

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_1s <= 26'd0;
    end
    else if (cnt_1s == MAX0_2S) begin
        cnt_1s <= 26'd0;
    end
    else begin
        cnt_1s <= cnt_1s + 1'd1;
    end
end

//控制led
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 4'b0001;
    end
    else if (cnt_1s == MAX0_2S) begin
        led <= {led[0],led[3:1]};
    end
    else begin
        led <= led;
    end
end
endmodule

3.仿真文件

`timescale 1ns/1ns//单位精度
module led_tb();
    reg             clk;//52MHz时钟信号,每10ns翻转一次
    reg             rst_n;

    wire    [3:0]   led;
    
    parameter MAX0_2S = 26'd9 ;

initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #10  //延迟10ns
    rst_n = 1'b1;
    #1000;
    $stop;//停止仿真
end

always #10//延迟10ns
begin
    clk = ~clk;//时钟翻转
end

led #(.MAX0_2S(MAX0_2S))u_led(
    .clk    (clk),
    .rst_n  (rst_n), 
    .led    (led) 

);

endmodule

2.按键控制led

1.项目要求

在这里插入图片描述

2.系统框图

在这里插入图片描述

3.项目代码

//led灯控制
module key_led(
    input                   clk     ,
    input                   rst_n   ,
    input   wire     [3:0]   key     ,

    output  reg     [3:0]   led     
);

parameter TIME0_2S = 26'd9_999_999;

reg [25:0]  cnt ;
reg [1:0]   state;

//0.2s计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= 26'd0;
    end
    else if (cnt == TIME0_2S) begin
        cnt <= 26'd0;
    end
    else begin
        cnt <= cnt + 1'd1;
    end
end

//状态
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= 2'b0;
    end
    else if (cnt == TIME0_2S) begin
        state <= state + 1'b1;
    end
    else begin
        state <= state;
    end
end

//控制led
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 4'b0000;
    end
    else if (!key[0]) begin
        case (state)
            2'd0 :  led <= 4'b0001;
            2'd1 :  led <= 4'b0010;
            2'd2 :  led <= 4'b0100;
            2'd3 :  led <= 4'b1000;
            default: led <= 4'b0000; 
        endcase 
    end
    else if (!key[1]) begin
        case (state)
            2'd3 :  led <= 4'b0001;
            2'd2 :  led <= 4'b0010;
            2'd1 :  led <= 4'b0100;
            2'd0 :  led <= 4'b1000;
            default: led <= 4'b0000; 
        endcase 
    end
    else if (!key[2]) begin
        case (state)
            2'd0 :  led <= 4'b1111;
            2'd1 :  led <= 4'b0000;
            2'd2 :  led <= 4'b1111;
            2'd3 :  led <= 4'b0000;
            default: led <= 4'b0000;
        endcase
    end
    else if (!key[3]) begin
        led <= 4'b1111;
    end
    else begin
        led <= led ;
    end
end
endmodule

4.测试文件

`timescale 1ns/1ns //单位/精度
module key_led_tb();
    reg clk     ;
    reg rst_n   ;
    reg [3:0]   key;

    wire [3:0]  led ;

    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;//结束复位
        key = 4'b1111;
        #((MAX_NUM)*CYCLE*4);
        key = 4'b1110;
        #((MAX_NUM)*CYCLE*4);
        key = 4'b1101;
        #((MAX_NUM)*CYCLE*4);
        key = 4'b1011;
        #((MAX_NUM)*CYCLE*4);
        key = 4'b0111;
        #((MAX_NUM)*CYCLE*4);
        $stop;  
    end

   key_led #(.TIME0_2S(MAX_NUM))  u_key_led(
        .clk     (clk),
        .rst_n   (rst_n),
        .key     (key),
        .led     (led)
);





endmodule

3.按键消抖

1.消抖原理

在这里插入图片描述

2.系统框图

在这里插入图片描述

3.项目代码

//按键消抖
module key_debounce(
    input                   clk     ,
    input                   rst_n   ,
    input   wire    [3:0]   key_in,

    output  wire    [3:0]   key_out
);

parameter   MAX20 = 20'd999_999;
wire        nedge;      //下降沿检测
reg [19:0]  cnt_20ms;   //20ms计数寄存器
reg         start;      //倒计时开始标志
reg [3:0]   key_r0;     //按键消抖寄存器0   
reg [3:0]   key_r1;     //按键消抖寄存器1
reg [3:0]   flag;       //检测按钮
reg [3:0]   key_on;     //中间按键寄存器







//20ms计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_20ms <= 20'd0;
    end
    else if (nedge) begin
        cnt_20ms <= MAX20;
    end
    else if (start) begin
        if (cnt_20ms == 1'd0) begin
            cnt_20ms <= 20'd0;
        end
        else begin
            cnt_20ms <= cnt_20ms - 1'b1;
        end
    end
    else begin
        cnt_20ms <= cnt_20ms ;
    end
end

//下降沿检测
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        key_r0 <= 4'b1111;
        key_r1 <= 4'b1111;
    end
    else begin
        key_r0 <= key_in;
        key_r1 <= key_r0;
    end
end
assign nedge = (~key_r0[0]&&key_r1[0])||(~key_r0[1]&&key_r1[1])||(~key_r0[2]&&key_r1[2])||(~key_r0[3]&&key_r1[3]);

//约束start
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        start <= 1'b0;
    end
    else if (nedge) begin
        start <= 1'b1;
    end
    else if (cnt_20ms == 1'd0) begin
        start <= 1'b0;
    end
    else begin
        start <= start;
    end
end

//记录flag
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 4'b0000;
    end
    else if (cnt_20ms == 1'd0) begin
        flag <= ~key_r0;
    end
    else begin
        flag <= 4'b0000;
    end
end

//设置key_out的值
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        key_on <= 4'b1111;
    end
    else if (flag[0]== 1'b1) begin
        key_on <= 4'b1110;
    end
    else if (flag[1]== 1'b1) begin
        key_on <= 4'b1101;
    end
    else if (flag[2]== 1'b1) begin
        key_on <= 4'b1011;
    end
    else if (flag[3]== 1'b1) begin
        key_on <= 4'b0111;
    end
    else begin
        key_on <= key_on;
    end
end

assign key_out = key_on ;
endmodule

4.数码管显示

1.显示原理

在这里插入图片描述

2.系统框图

在这里插入图片描述

3.源码显示

module time_count(//计时0.5s,计满后输出高电平
    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    ,//计满0.5秒后,标志

    output  reg [5: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'b111111;
    end
    else begin
        sel <= 6'b000000;
    end
end

//flag信号为1时,num+1
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 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'b1111_1111;
    endcase
end
endmodule
module top_seg_led_static(
    input                   clk     ,
    input                   rst_n   ,

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

wire     flag    ;
parameter    MAX_NUM = 26'd24_999_999;   
time_count #(.MAX_NUM(MAX_NUM))time_count_inst(//计时0.5s,计满后输出高电平
        .clk     (clk),
        .rst_n   (rst_n),
        .flag    (flag)
);

seg_led_static seg_led_static_inst(
        .clk     (clk),
        .rst_n   (rst_n),
        .flag    (flag),//计满0.5秒后,标志
        .sel     (sel),//六位位选信号
        .seg     (seg) //八位段选信号
);
endmodule

4.测试文件

`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;
    #(16*(MAX_NUM + 1)*CYCLE);
    $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

5.呼吸灯

1.项目源码

module breath_led(
    input               clk     ,
    input               rst_n   ,

    output  reg [3:0]   led
);

parameter CNT_US =  6'd49;//1us
parameter CNT_MS =  10'd999;//1ms
parameter CNT_S  =  10'd999;//1s

reg [5:0]   cnt_us;
wire        add_cnt_us;//us计数器开始标志
wire        end_cnt_us;//us计数器结束标志

reg [9:0]   cnt_ms;
wire        add_cnt_ms;
wire        end_cnt_ms;


reg [9:0]   cnt_s;
wire        add_cnt_s;
wire        end_cnt_s;

reg         flag ;//亮灭标志

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'b1;
            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 == CNT_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'b1;
        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 == CNT_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 == CNT_S ;

//约束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

//led控制
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 4'b0;
    end
    else if (flag) begin
        led <= {cnt_s>cnt_ms ,cnt_s>cnt_ms ,cnt_s>cnt_ms ,cnt_s>cnt_ms };
    end
    else begin
        led <= {cnt_s<cnt_ms ,cnt_s<cnt_ms ,cnt_s<cnt_ms ,cnt_s<cnt_ms };
    end
end
endmodule

2.测试文件

`timescale 1ns/1ns
module breath_led_tb();
reg clk         ;
reg rst_n       ;
wire    [3:0]   led ;

parameter   CYCLE   = 20;
parameter   CNT_US  = 4 ;
parameter   CNT_MS  = 9 ;
parameter   CNT_S   = 9 ;

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

initial begin
    clk = 1'b0;
    rst_n = 1'b0;//开始复位
    #(CYCLE);
    rst_n = 1'b1;//结束复位
    #1000;
    $stop;
end

breath_led #(.CNT_US(CNT_US),.CNT_MS(CNT_MS),.CNT_S(CNT_S)) u_breath_led(
        .clk     (clk),
        .rst_n   (rst_n),
        .led     (led)   
);
endmodule

二.实习总结

在最初的几天,我们学习了按键控制LED流水灯和LED呼吸灯的设计。通过使用Verilog语言编写代码,我们成功实现了按键来控制LED灯的亮灭和流动效果,以及利用PWM信号使LED灯呈现呼吸灯效果。这些实验帮助我熟悉了FPGA开发流程和Verilog语言的使用。
接着,我们学习了按键消抖的原理和方法。按键消抖是一个常见的问题,在实际应用中需要解决。我们通过verilog,设计了一个稳定的按键消抖模块,确保按键输入的准确性和稳定性。
在数码管显示的学习中,我们掌握了数码管的基本原理和控制方法。通过将FPGA与数码管连接,我们成功实现了数码管显示当前时间的功能。这个实验让我更加了解了FPGA如何通过逻辑门和时钟信号来控制外部设备。
通过这次FPGA培训实习,我不仅学到了专业知识和技能,还锻炼了自己的团队合作和问题解决能力。在与同组成员一起完成各项实验和任务的过程中,我们相互交流、互相帮助,共同解决问题。这种合作经验对于我未来的工作和学习都具有重要意义。
在未来的学习和实践中,我将继续努力提升自己在FPGA设计和物联网应用方面的专业能力。我相信通过海云捷讯的培训实习,我将成为一名优秀的物联网工程师,并为推动物联网技术的发展贡献自己的力量。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值