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

一、3-8译码器

1.简介

3-8译码器,就是把3种输入状态翻译成8种输出状态,译码器是将输入的具有特定含义的二进制代码翻译成输出信号的不同组合,实现电路控制功能的逻辑电路。译码器在数字系统中应用广泛,可用于代码的转换、终端数字的显示、数据的分配等等。

2.实验目的

本次实验主要是为了理解verilog基础语法,掌握组合逻辑的设计方法。

3.设计原理

3-8 译码器有 3 个输入和 8 个输出,所以可以指定当输入为 111 时,译码后为指定的状态,即输出00000001,紧接着依次类推,当输入为 110 时,输出 01111111,当输入为 101 时,输出 11011111,当输入为 100 时,输出 11101111,输入 011 时,输出为 11110111,输入为 010 时,输出 11111011,输入为 001 时,输出 11111101,输入为 000 时,输出为 11111110。
如下图所示:
在这里插入图片描述

4.项目代码

module decoder(
	input wire [2:0] a,//输入信号,3位
	
	output reg [7:0] b//输出信号,8位
);

	//译码器组合逻辑
	always@(*)begin
		case(a)
			3'b000: b=8'b11111110;
			3'b001:	b=8'b11111101;
			3'b010: b=8'b11111011;
			3'b011:	b=8'b11110111;
			3'b100: b=8'b11101111;
			3'b101:	b=8'b11011111;
			3'b110:	b=8'b01111111;
			3'b111:	b=8'b10000000;
			default: b=8'b00000000;
		endcase 
	end 
endmodule 

5.项目仿真

仿真代码

`timescale 1ns/1ns //单位/精度
module decoder_tb();

reg [2:0]  a;//输入信号
wire [7:0] b;//输出信号

initial begin
	a = 3'b000;
	#1        ;//延迟1ns
	a = 3'b001;
	#1        ;//延迟1ns
	a = 3'b010;
	#1        ;//延迟1ns
	a = 3'b011;
	#1        ;//延迟1ns
	a = 3'b101;
	#1        ;//延迟1ns
	a = 3'b110;
	#1        ;//延迟1ns
	a = 3'b111;
	#1        ;//延迟1ns
	a = 3'bxxx;
	#1        ;//延迟1ns
end 

decoder	u_decoder(
.a	(a),//输入信号,3位
	
.b	(b)//输出信号,8位
);
endmodule 

仿真结果
在这里插入图片描述

二、点亮LED灯

1.实验任务

每间隔1S实现led灯的亮灭。

2.实验代码

//每间隔1S实现LED的亮灭
module led(
    input           clk     ,
    input           rst_n   ,

    output  reg   [3:0]  led   
);

//计时1S
//parameter CNT0_2S = 24'd9;//如果要进行仿真的话就使用这个计数器
parameter CNT0_2S = 24'd9_999_999;
reg [23:0]  cnt     ;//保存时钟上升沿的个数
reg [1:0]   state   ;

always @(posedge clk or negedge rst_n) begin//对寄存器赋值要使用always
    if(!rst_n)begin
        cnt <= 24'd0;
    end
    else if(cnt == CNT0_2S)begin
        cnt <= 24'd0;
    end
    else begin
        cnt <= cnt + 1'd1;
    end
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        state <= 2'd0;
    end
    else if(state == 2'd3 && cnt == CNT0_2S)begin
        state <= 2'd0;
    end
    else if(cnt == CNT0_2S)begin
        state <= state + 1'd1;
    end
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        led <= 4'b0000;
    end
    else 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
end

//0001,0010,0100,1000,0001
// always @(posedge clk or negedge rst_n) begin
//     if(!rst_n)begin
//         led <= 4'b0001;
//     end
//     else if(cnt == CNT0_2S)begin
//         led <= {led[2:0],led[3]};//使用位拼接可以更简单的实现流水灯
//     end
//     else begin
//         led <= led;
//     end
// end
endmodule

3.引脚配置

在这里插入图片描述

4.仿真测试

代码

`timescale 1ns/1ns
module led_tb();
    reg     clk;
    reg     rst_n;

    wire    [3:0]   led;

always #10 clk = ~clk;

initial begin
    clk         =   1'b0;
    rst_n       =   1'b0;
    #10 rst_n   =   1'b1;
    #1000 $stop ;
end

led     u_led(
    .clk     (clk),
    .rst_n   (rst_n),
    .led     (led)   
);

endmodule

结果
在这里插入图片描述

三、按键控制LED灯

1.实验任务

使用开发板上的四个按键控制四个LED灯。按下不同的按键时,四个LED灯显示不同效果。
在这里插入图片描述

2.系统设计

四个按键外加时钟和复位信号作为输入,两个计数器模块分别用于0.2s时间的计数和状态的计数。led模式选择模块根据状态计数器的改变,来改变四个led的状态,形成不同的样式。
在这里插入图片描述

3.实验代码

module key_led(
	input 				clk  ,//时钟50MHz
	input 				rst_n,//复位信号,下降沿有效negtive
	input 	[3:0]		key  ,//四个按键
	
	output 	reg [3:0]	led   //四个led灯
	
);

parameter TIME = 24'd10_000_000;//0.2S
reg [23:0]	cnt ;//计数器0.2S
reg [1:0]	state;//记录四个led状态

//0.2s计数器模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//复位
		cnt <= 24'd0;//计数器清0
	end 
	else if(cnt == TIME - 1)begin//记满10_000_000,0~9_999_999
		cnt <= 24'd0;//计数器清0
	end 
	else begin
		cnt <= cnt + 1'd1;//其他情况下计数器加1
	end 
end 

//状态计数模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//复位信号
		state <= 2'd0;//状态清0
	end 
	else if(cnt == TIME - 1)begin//记满10_000_000,0~9_999_999 0.2s
		state <= state + 2'd1;//状态加1
	end 
	else begin
	state <= state;//其他情况状态保持不变
	end 
end 

//状态控制led模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//复位信号
		led <= 4'b0000;//led全灭
	end 
	else if(key[0] == 0)begin//右边第1个按键按下,按键低电平0有效
		case(state)//判断状态的值
			2'd0: led <= 4'b0001;//右边第1个led灯亮
			2'd1: led <= 4'b0010;//右边第2个led灯亮
			2'd2: led <= 4'b0100;//右边第3个led灯亮
			2'd3: led <= 4'b1000;//右边第4个led灯亮
			default:;//默认情况不能忘,可以不写,但是要把stat情况考虑完
		endcase 
	end 
	else if(key[1] == 0)begin//右边第2个按键按下,按键低电平0有效
		case(state)//判断状态的值
			2'd0: led <= 4'b1000;//左边第1个led灯亮
			2'd1: led <= 4'b0100;//左边第2个led灯亮
			2'd2: led <= 4'b0010;//左边第3个led灯亮
			2'd3: led <= 4'b0001;//左边第4个led灯亮
		default:;
		endcase 
	end 
	else if(key[2] == 0)begin//右边第3个按键按下,按键低电平0有效
		case(state)
			2'd0: led <= 4'b1111;//全亮
			2'd1: led <= 4'b0000;//全灭
			2'd2: led <= 4'b1111;//全亮
			2'd3: led <= 4'b0000;//全灭
		default:;
		endcase 
	end
	else if(key[3] == 0)begin//右边第4个按键按下,按键低电平0有效
		case(state)
			2'd0: led <= 4'b1111;//全亮
			2'd1: led <= 4'b1111;//全亮
			2'd2: led <= 4'b1111;//全亮
			2'd3: led <= 4'b1111;//全亮
		default:;
		endcase 
	end
	else begin
		led <= 4'b0000;//其他情况默认4个led灯全灭
	end 
end 
endmodule 

4.引脚配置

在这里插入图片描述

5.仿真测试

代码

`timescale 1ns/1ns//单位/精度
module key_led_tb();

reg 		clk  ;//时钟信号
reg 		rst_n;//复位信号
reg	 [3:0]	key  ;//按键信号

wire [3:0]	led  ;//led灯信号

parameter TIME  = 10;//间隔时间,由10_000_000变为10,便于仿真观察
parameter CYCLE = 20;//周期20ns
always #(CYCLE/2) clk = ~clk;//每10ns翻转一次,刚好模拟时钟周期50MHz

initial begin
	clk   = 1'b0;//初始时钟为低电平
	rst_n = 1'b0;//复位信号置0,下降沿有效,初始化
	#(CYCLE);//时钟20ns
	rst_n = 1'b1;//复位信号置1
	#(CYCLE * TIME * 4);//4个led灯,4个间隔,所以乘以4
	key   = 4'b1110;//按下右边第1个按键
	#(CYCLE * TIME * 4);
	key   = 4'b1101;//按下右边第2个按键
	#(CYCLE * TIME * 4);
	key   = 4'b1011;//按下右边第3个按键
	#(CYCLE * TIME * 4);
	key   = 4'b0111;//按下右边第4个按键
	#(CYCLE * TIME * 4);
	$stop;//停止
end 

//实例化模块
key_led	 #(.TIME (TIME)) u_key_led

(
.clk  		(clk)  ,//时钟50MHz
.rst_n		(rst_n),//复位信号,下降沿有效
.key  		(key)  ,//按键信号
             
.led		(led)//led灯
); 
endmodule 

结果
在这里插入图片描述

四、pwm呼吸灯

1.实验任务

呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化,感觉好像是人在呼吸。本次实验是使用开发板上的四个led灯实现1s间隔的呼吸灯。使4个led灯由暗到亮,再由亮到暗的过程。

2.实验代码

module pwm_led (
    input                   clk     ,
    input                   rst_n   ,

    output  reg     [3:0]   led     
);

parameter TIME_US = 6'd50;//50x20=1000ns=1us
parameter TIME_MS = 10'd999;//1usx1000=1ms
parameter TIME_S = 10'd999;//1msx1000=1s

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

wire  add_cnt_us;//开始计数的标志
wire  end_cnt_us;//结束计数的标志
wire  add_cnt_ms;
wire  end_cnt_ms;
wire  add_cnt_s;
wire  end_cnt_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 <= 4'b0000;
    end
    else if(!flag)begin//flag=0,led由灭到亮
        led <= {cnt_s > cnt_ms,cnt_s > cnt_ms,cnt_s > cnt_ms,cnt_s > cnt_ms};
    end
    else if(flag)begin//flag=1,led由亮到灭
        led <= {cnt_s < cnt_ms,cnt_s < cnt_ms,cnt_s < cnt_ms,cnt_s < cnt_ms};
    end
    else begin
        led <= led;
    end
end

endmodule

3.引脚配置

在这里插入图片描述

4.仿真测试

代码

`timescale 1ns/1ns
module pwm_led_tb();
    reg     clk;
    reg     rst_n;

    wire    [3:0]   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;
        #(2*(TIME_US+1)*(TIME_MS+1)*(TIME_S+1)*CYCLE);
        $stop;
    end

pwm_led #(
.TIME_US (TIME_US),
.TIME_MS (TIME_MS),
.TIME_S  (TIME_S)
) u_pwm_led(
.clk (clk),
.rst_n (rst_n),

.led (led)
);

endmodule

结果
在这里插入图片描述

五、静态数码管

1.实验原理

我们使用的数码管是8段数码管,每段是由led组成。通过控制每段led的亮灭,来控制数码管显示不同的数字和字母。
在这里插入图片描述
要显示不同的数字或者字母,就要选择点亮对应的led段。下图中、对应的是cyclone IV开发板上数码管的真值表,可以通过查找该表来显示我们想要的数字或者字母。
在这里插入图片描述
我们的开发板上的数码管分为了6位和8段,6位了控制6个数码管是否显示,8段来控制每个数码管显示的内容。本次实验是数码管的静态显示,因此只考虑段选信号。在不同的时刻,各个位选信号保持不变,并根据真值表,选择要显示的数字或者字母。并且Cyclone IV开发板中的数码管是共阳极,所以数码管中需要给低电平,对应的led段才会亮。

2.实验任务

六个数码管同时间隔0.5s显示0-f。要求:使用一个顶层模块,调用计时器模块和数码管静态显示模块。

在这里插入图片描述

3.实验代码

time_count模块

module time_count(
	input	     clk  ,//50MHz时钟信号
	input		 rst_n,//复位信号
	output	reg  flag//一个时钟周期的脉冲信号
);
parameter	 MAX_NUM = 25'd25_000_000;//计数器最大计数值
reg  [24:0]	 cnt                     ; //时钟分频计数器

//计数器对时钟计数,每0.5s,输出一个时钟周期脉冲信号
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin//按复位时
		flag <= 1'b0;//信号为0
		cnt <= 25'd0;//计数器清零
	end
	else if(cnt < MAX_NUM - 1'b1)begin//如果没到时间
		flag <= 1'b0;//信号为0
		cnt <= cnt + 1'b1;//计数器正常累计+1
	end
	else	begin //否则到时间
		flag <= 1'b1;//信号变为1
		cnt <= 25'd0;
	end
end
endmodule 

seg_led_static模块

module	seg_led_static(
	input		      clk     ,
	input		      rst_n   ,
	input		      flag    ,
	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)//如果按复位键0
		sel <= 6'b111111;//则默认为高电平
	else 
		sel <= 6'b000000;//否则为低电平
end
//每次通知信号flag到达时,数码管计数加1
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		num <=	4'h0;
	else if(flag)begin
		if(num < 4'hf)
			num <= num + 1'h1;
		else 
			num <= 4'h0;
	end
	else begin
		num <= num;
	end
end
//根据数码管显示的数值,控制段选信号
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
		seg <= 8'b0;
	else begin
		case(num)//匹配16进制数
			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 


top_seg_led_static模块

module  top_seg_led_static(
	input	 	         clk  ,//50MHz系统时钟
	input		         rst_n,//系统复位信号(低有效)
	output		[5:0]	 sel  ,//数码管位选
	output	    [7:0]	 seg//数码管段选
);
 
parameter	MAX_NUM = 25'd25_000_000;// 数码管变化的时间间隔0.5s
wire		add_flag				;// 数码管变化的通知信号
//每隔0.5s产生一个时钟周期的脉冲信号
time_count #(.MAX_NUM(MAX_NUM)) u_time_count(
	.clk		(clk)  ,//50MHz时钟信号
	.rst_n		(rst_n),//复位信号
	.flag		(add_flag)//一个时钟周期的脉冲信号
);
//每当脉冲信号到达时,使数码管显示的数值加1
seg_led_static u_seg_led_static(
	.clk		(clk)	  ,
	.rst_n		(rst_n)	  ,
	.flag	    (add_flag),
	.sel		(sel)	  ,
	.seg		(seg)
);
endmodule 


4.引脚配置

在这里插入图片描述

5.仿真测试

代码

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

reg   		 	clk    ;
reg  		 	rst_n  ;
wire    [5:0]	sel	   ;
wire 	[7:0]  	seg    ;
parameter CYCLE = 5'd20;//周期20ns
parameter MAX_NUM = 8'd100;//调小间隔时间100*20ns
always #(CYCLE/2) clk = ~clk;//翻转时钟

initial begin
	clk   = 0		   ;//时钟初始为0
	rst_n = 0		   ;//复位初始为0
	#(CYCLE)		   ;//延迟20ns
	rst_n = 1		   ;//复位置1
	#(16*MAX_NUM*CYCLE);//显示0-f时间
	$stop			   ;//停止
	
	
end 
top_seg_led_static#(.MAX_NUM (MAX_NUM))	u_top_seg_led_static(
.clk  	(clk)  ,//50MHz系统时钟
.rst_n	(rst_n),//系统复位信号(低有效)
.sel  	(sel)  ,//数码管位选
.seg	(seg)	//数码管段选
);
endmodule 


结果

在这里插入图片描述

六、实验成果

流水灯

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值