毕业实习-实践项目学习记录

1、三段译码器

1.1、实现目标

顾名思义,三段译码器就是有三段输入,然后有8位的输出。
比如:输入为0,那么输出就应该是8’b1111_1110;同理,如果输入为1,那么输出应该为8’b1111_1101;以此类推,输入7,输出应该为8’b0111_1111。
因此,我们在这里可以得到输入和输出的关系:

输入输出
08’b1111_1110
18’b1111_1101
28’b1111_1011
38’b1111_0111
48’b1110_1111
58’b1011_1111
68’b0111_1111
78’b0000_0000

1.2、创建项目:

创建项目之前,我们有必要先了解一下项目的结构:
在这里插入图片描述

打开Quartus之后会进入到这个界面中,点击“New Project Wizard”——创建向导,进行项目的创建
在这里插入图片描述
进入创建向导之后点击next
在这里插入图片描述
之后是选择项目的保存路径和项目的名称,项目路径和名称当中最好不要包含中文
在这里插入图片描述

这里的第一个选项的意思是创建一个空项目,第二个是使用项目模板。因为我们并没有项目模板,所以我们就选择第一个,创建一个空项目
在这里插入图片描述
这里是添加文件,目前我们还没有开始编写文件,不需要添加,直接next
在这里插入图片描述
我们在这里进行开发板的选择,这里使用的是EP4CE6F17C8的开发板,
在这里插入图片描述
上面的操作进行完成之后进入到工具的选择,我们将仿真工具选择为ModelSim-Altera
在这里插入图片描述
上面的操作完成之后就进入到总览界面,到这里就代表项目创建完成了,我们点击Finish就可以了
在这里插入图片描述

1.2、模块代码:

1.2.1、创建verilog文件

点击菜单栏中的File,然后点击选择框中的New
在这里插入图片描述
然后选择
在这里插入图片描述
我们就创建好一个Verilog文件了。

1.2.2、编写代码

	module decoder(
	input 	wire 	[2:0]	data_in,  
	output 	reg 	[7:0]	data_out  
);

always @(*)
begin
	case (data_in)
		3'b000:  data_out <= 8'b1111_1110;
		3'b001:  data_out <= 8'b1111_1101;
		3'b010:  data_out <= 8'b1111_1011;
		3'b011:  data_out <= 8'b1111_0111;
		3'b100:  data_out <= 8'b1110_1111;
		3'b101:  data_out <= 8'b1101_1111;
		3'b110:  data_out <= 8'b1011_1111;
		3'b111:  data_out <= 8'b0111_1111;
		default: data_out <= 8'b0000_0000;
	endcase
end

endmodule

这样,我们就实现了一个简单的三段译码器。

1.2.3、保存文件

我们创建好了一个文件,但是我们还没有将这个文件保存在电脑中。
将代码编写好之后,我们只需要按下快捷键ctrl+s,会弹出来界面让我们选择保存的路径。我们将代码保存在项目的src文件夹下。同时,文件的名字和模块的名字必须相同。仿真文件也一样。

1.3、仿真

1.3.1、编写仿真文件

同时,为了能够更加直观地看到输出,我们可以进行仿真,在仿真查看结果。

`timescale 1ns/1ns  // 延时时间的单位和精度
module decoder_tb();
	reg   [2:0] data_in ;
	wire  [7:0] data_out;
	
	initial
	begin
		#100; data_in = 3'b000;  // #100表示延时100ns
		#100; data_in = 3'b001;
		#100; data_in = 3'b010;
		#100; data_in = 3'b011;
		#100; data_in = 3'b100;
		#100; data_in = 3'b101;
		#100; data_in = 3'b110;
		#100; data_in = 3'b111;
	end
	
	decoder decoder_inst (
		.data_in (data_in ),  // 输入,wire一般用来保存已经定义过的变量
		.data_out(data_out)   // 输出,reg用来初始化某个变量
	);
endmodule 

1.3.2、保存文件

将文件编写完成之后保存到项目下的sim文件夹下

1.4、添加模块文件和仿真文件到项目中

在上面菜单栏中选择Assignments->Setting->Files,进入到添加文件的界面。然后点击这个有三个点的按钮进行文件的选择。
在这里插入图片描述
然后找到刚才写的两个文件的路径,选择文件,并打开,
在这里插入图片描述
将两个文件选择好之后点击OK就完成添加了。

1.5、添加仿真

留在Settings界面,找到Simulation,点击
在这里插入图片描述
将仿真参数按照图中所示进行配置,然后是添加仿真文件到仿真项目中。点击Test Benches…
在这里插入图片描述
创建仿真项目
在这里插入图片描述
在这里插入图片描述
这里创建完成之后就一直OK,回到编写代码的界面中,然后点击全编译按钮(记得将模块文件设置为顶层文件)
在这里插入图片描述
编译完成之后点击菜单栏中的Tools->Run Simulation Tool-> RTL Simulation,会自动打开ModelSim,
,然后我们重启波形,并将运行时间设置为1微秒,然后再运行波形。波形大概是这样的。
在这里插入图片描述

2、led流水灯

2.1、创建项目

2.2、编写模块文件

/*
    模块描述:流水灯
*/
module led_2(
    input   wire            clk  ,
    input   wire            rst_n,

    output  reg     [3:0]   led  
);

// parameter MAX_1S = 26'd49_999_999;
parameter MAX_0_2S = 26'd9_999_999;
// parameter MAX_0_2S = 26'd99;

// 计时1s
reg [25:0] cnt_1s;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)  // 初始化计时器
    begin
        cnt_1s <= 26'd0;
    end
    else if (cnt_1s == MAX_0_2S)  // 当到达MAX_1S个周期后就表示计时到1s了
    begin
        cnt_1s <= 26'd0;
    end
    else  
    begin
        cnt_1s <= cnt_1s + 26'd1;  // 其他时候都+1
    end
end

// led控制
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        led <= 4'b0001;
    end
    else if (cnt_1s == MAX_0_2S)  // 计数器到0.2s时,改变状态
    begin
        led <= {led[2:0], led[3]};
    end
    else  // 其他时候保持不变
    begin
        led <= led;
    end
end

endmodule

2.3、保存文件

2.4、烧录文件到开发板中

点击这个按钮
在这里插入图片描述
在这里插入图片描述
烧录完成
在这里插入图片描述

2.5、结果

VID_20230715_163818

3、呼吸灯

3.1、创建项目

3.2、编写模块文件

module breath_led (
    input   wire        clk     ,
    input   wire        rst_n   ,

    output  reg  [3:0]  led
);
parameter TIME_US = 6'd49;
parameter TIME_MS = 10'd999;
parameter TIME_S  = 10'd999;

reg [9:0] cnt_s;  // 1000
reg [9:0] cnt_ms;
reg [5:0] cnt_us;  // 50

wire      add_cnt_us;
wire      end_cnt_us;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    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 + 6'd1;
        end
    end
    else
    begin
        cnt_us <= 6'd0;
    end
end
assign add_cnt_us = 1;
assign end_cnt_us = add_cnt_us && cnt_us == TIME_US;


wire      add_cnt_ms;
wire      end_cnt_ms;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        cnt_ms <= 10'd0;
    end
    else if (add_cnt_ms)
    begin
        if (end_cnt_ms)
        begin
            cnt_ms <= 10'd0;
        end
        else if (cnt_us == TIME_US)
        begin
            cnt_ms <= cnt_ms + 10'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);


wire      add_cnt_s;
wire      end_cnt_s;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    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 + 10'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);


// 控制led灯亮灭
reg flag;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        flag <= 1'b0;
    end
    else if (end_cnt_s)
    begin
        flag <= ~flag;
    end
    else
    begin
        flag <= flag;
    end
end

// 根据计数器的数值来控制led灯
always @(*)
begin
    if (flag)
    begin
        led[0] = cnt_s > cnt_ms ? 1 : 0;
        led[1] = cnt_s > cnt_ms ? 1 : 0;
        led[2] = cnt_s > cnt_ms ? 1 : 0;
        led[3] = cnt_s > cnt_ms ? 1 : 0;
    end
    else
    begin
        led[0] = cnt_s > cnt_ms ? 0 : 1;
        led[1] = cnt_s > cnt_ms ? 0 : 1;
        led[2] = cnt_s > cnt_ms ? 0 : 1;
        led[3] = cnt_s > cnt_ms ? 0 : 1;
    end
end
endmodule

3.3、保存文件

3.4、烧录

3.5、结果

VID_20230715_174420

4、呼吸流水灯

4.0、目标

第一个灯开始闪烁之后第二个灯延时250ms亮,然后第三个灯延时第二个灯250ms亮,同理,第四个灯延时250ms第三个灯亮。

4.1、创建项目

4.2、编写模块文件

延时函数

module delay_ms (
    input   wire        clk     ,
    input   wire        rst_n   ,
    input   wire [9:0]  delay   ,  // 加入延时控制,单位ms

    output  reg         flag     
);
parameter TIME_US = 6'd49;
parameter TIME_MS = 10'd999;
parameter TIME_S  = 10'd999;

reg [5:0] cnt_delay_us;  // 延时计时器
reg [9:0] cnt_delay_ms;
reg [9:0] cnt_delay_s;

/*
    延时
*/
wire      add_cnt_delay_us;
wire      end_cnt_delay_us;
always @(posedge clk or negedge rst_n) 
begin
    if (rst_n == 1'b0)
    begin
        cnt_delay_us <= 6'd0;
    end    
    else if (add_cnt_delay_us)
    begin
        if (end_cnt_delay_us)
        begin
            cnt_delay_us <= 6'd0;
        end
        else
        begin
            cnt_delay_us <= cnt_delay_us + 6'd1;
        end
    end
    else
    begin
        cnt_delay_us <= cnt_delay_us;
    end
end
assign add_cnt_delay_us = !flag;  // 延时计时中
assign end_cnt_delay_us = add_cnt_delay_us && cnt_delay_us == TIME_US;  // 延时终止

wire      add_cnt_delay_ms;
wire      end_cnt_delay_ms;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        cnt_delay_ms <= 10'd0;
    end
    else if (add_cnt_delay_ms)
    begin
        if (end_cnt_delay_ms)
        begin
            cnt_delay_ms <= 10'd0;
        end
        else
        begin
            cnt_delay_ms <= cnt_delay_ms + 10'd1;
        end
    end
    else
    begin
        cnt_delay_ms <= cnt_delay_ms;
    end
end
assign add_cnt_delay_ms = end_cnt_delay_us;
assign end_cnt_delay_ms = add_cnt_delay_ms && (cnt_delay_ms == TIME_MS);


wire      add_cnt_delay_s;
wire      end_cnt_delay_s;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        cnt_delay_s <= 10'd0;
    end
    else if (add_cnt_delay_s)
    begin
        if (end_cnt_delay_s)
        begin
            cnt_delay_s <= 10'd0;
        end
        else
        begin
            cnt_delay_s <= cnt_delay_s + 10'd1;
        end
    end
    else
    begin
        cnt_delay_s <= cnt_delay_s;
    end
end
assign add_cnt_delay_s = end_cnt_delay_ms;
assign end_cnt_delay_s = add_cnt_delay_s && (cnt_delay_s == delay);

always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        flag <= 1'b0;
    end
    else if (end_cnt_delay_s)
    begin
        flag <= 1'b1;
    end
    else
    begin
        flag <= flag;
    end
end
endmodule

控制每个led的延时

module breath_led_new (
    input   wire        clk     ,
    input   wire        rst_n   ,
    input   wire [9:0]  delay   ,  // 加入延时控制,单位ms
    output  reg         led     
);
/*
    实现一个呼吸流水灯
*/
parameter TIME_US = 6'd49;
parameter TIME_MS = 10'd999;
parameter TIME_S  = 10'd999;

reg [9:0] cnt_s;  // 1000
reg [9:0] cnt_ms;
reg [5:0] cnt_us;  // 50
wire      flag_run;  // 判断延时是否结束,如果结束,则正式开始计时

wire      add_cnt_us;
wire      end_cnt_us;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    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 + 6'd1;
        end
    end
    else
    begin
        cnt_us <= 6'd0;
    end
end
assign add_cnt_us = flag_run;
assign end_cnt_us = add_cnt_us && cnt_us == TIME_US;


wire      add_cnt_ms;
wire      end_cnt_ms;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    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 + 10'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);


wire      add_cnt_s;
wire      end_cnt_s;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    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 + 10'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);


// 控制led灯亮灭
reg flag;
always @(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
    begin
        flag <= 1'b0;
    end
    else if (end_cnt_s)
    begin
        flag <= ~flag;
    end
    else
    begin
        flag <= flag;
    end
end

always @(*)
begin
    if (flag)
    begin
        led = (cnt_s) > cnt_ms ? 0 : 1;
    end
    else
    begin
        led = (cnt_s) > cnt_ms ? 1 : 0;
    end
end

delay_ms delay_ms_inst (
    .clk     (clk      ),
    .rst_n   (rst_n    ),
    .delay   (delay    ),  // 加入延时控制,单位ms
    .flag    (flag_run ) 
);
endmodule

顶层文件

module breath_led_top (
    input   wire        clk     ,
    input   wire        rst_n   ,

    output  wire [3:0]  led
);

wire [3:0] led_temp;
breath_led_new breath_led_new_inst0 (
    .clk     (clk    ),
    .rst_n   (rst_n  ),
    .delay   (10'd1  ),  // 加入延时,控制
    .led     (led_temp[0] )
);

breath_led_new breath_led_new_inst1 (
    .clk     (clk    ),
    .rst_n   (rst_n  ),
    .delay   (10'd250),  // 加入延时,控制
    .led     (led_temp[1] )
);

breath_led_new breath_led_new_inst2 (
    .clk     (clk    ),
    .rst_n   (rst_n  ),
    .delay   (10'd500),  // 加入延时,控制
    .led     (led_temp[2] )
);

breath_led_new breath_led_new_inst3 (
    .clk     (clk    ),
    .rst_n   (rst_n  ),
    .delay   (10'd750),  // 加入延时,控制
    .led     (led_temp[3] )
);
assign led = led_temp;
endmodule

4.3、保存文件

4.4、烧录

4.5、结果

VID_20230715_165402

5、按键消抖

5.1、为什么要进行按键消抖

按键抖动:按键抖动通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动。当按下一次按键,可能在A点检测到一次低电平,在B点检测到一次高电平,在C点又检测到一次低电平。同时抖动是随机,不可测的。那么按下一次按键,抖动可能会误以为按下多次按键。
在这里插入图片描述
因此,为了消除按键抖动对程序的影响,我们需要对按键进行消抖处理。

5.2、思路

等信号平稳之后,再等待20ms进行采样。

/*
    按键消抖模块
*/
module key_debounce (
    input   wire        clk     ,
    input   wire        rst_n   ,
    input   wire [3:0]  key     ,  // 输入的不稳定信号
    output  wire [3:0]  key_out
);

localparam   MAX20 = 20'd1_000_000; 
reg [19:0] cnt_20ms;
reg        start; //稳定信号开始
reg [3:0]  key_r0;//按键抖动寄存器0
reg [3:0]  key_r1;//按键抖动寄存器1
wire       nedge;
reg [3:0]  key_r;//开启流水

//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'b1) begin
            cnt_20ms <= 20'd0;
        end
        else begin
            cnt_20ms <= cnt_20ms - 1'd1;
        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;//打一拍,同步时钟域
        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'b1)
    begin
        start <= 1'b0;
    end
    else begin
        start <= start;
    end
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        key_r <= 4'b0000;
    end
    else if (cnt_20ms == 1'b1) begin
        key_r <= ~key_r0;
    end
    else begin
        key_r <= key;
    end
end
assign key_out =  key_r;  // 将处理好的key信号赋值给key_out
endmodule

6、总结

本次的实习大概就是学习了这些知识,但是这些知识对于未来的找工作肯定是不够的,学无止境!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值