数字电子技术课程设计——反应计时器

通过用户接收刺激开始计时到按下按钮停止计时,测试用户的反应时间。

题目要求:

(1)电路有三个输入按键:clear,start 和 stop,使用一个 LED 作为视觉刺激指示灯, 在七段数码管上显示相应的信息。

(2)当按下 clear 键时,电路回到初始状态,七段数码管给出一个初始显示,同时 LED 指示灯熄灭。

(3)当按下 start 键,七段数码管熄灭,产生一段 2s 到 6s(包括 2s 和 6s)之间的随机时间之后,LED 指示灯点亮,计数器开始加计数。计数器每 1ms 加 1,它的值以 XXX 的格式显示在数码管上。

(4)被测试者看到 LED 指示灯点亮后,立即按下 stop 键,此时计数器暂停计数,数码管显示的就是被测试者的反应时间。大多数人的反应时间在 0.1-0.3s 之间。

(5)如果不按下 stop 键,计时器达到 999 之后停止计数。

(6)如果 LED 指示灯点亮前,按下 stop 键,被视为犯规,数码管上应给出犯规指示。

(7)连续进行多次测试后,可按下按键 Min,Max 和 Ave 查阅所有测试结果中的最短时间、最长时间和平均时间。按键 restart 可清除记录的信息。

一、分析与设计

由题意可得,用户有输入:

start(开始计时)  stop(停止计时)  clear(清零) restart(重置所有数据)

Min(显示最短时间) Max(显示最长时间) Ave(显示平均时间)

另有50MHz时钟clk。为迎合ms计数,分频出一1kHz(1ms)的时钟w1。

1、基础功能状态机实现

正常一次操作为:start(开始)->等待2~6s->计时1~999ms中按下暂停->结束。有四个状态。

此处使用状态机来实现操作间的转换。

状态控制变量:reg [1:0]control;

状态1:control = 2'b00 初始化:可start(开始计时)  clear(清零) restart(重置所有数据)。

状态2:control = 2'b01 等待:可stop(停止计时)——对应题目要求(6)犯规。

状态3:control = 2'b10 正式计时:可stop(停止计时)。

状态4:control = 2'b11 处理:可clear(清零) restart(重置所有数据)。

状态转换图如下:

其中:count为计数器,用于2~6s计数和1~999ms计数。Random为随机数。

随机数Random生成:令一计数器值k在clk信号下循环计数1~4001;当按下start按钮时,取Random = k % 4001 + 2000 可获得随机时间2~6s。

2、显示实现(实时值,最大值等)

显示有:LED(LED显示)   (Data3\Data2\Data1)(数码管显示三位)。

数码管显示状态控制reg [1:0]Judge;

熄灭 Judge = 2'b01 ->  等待2~6s时,数码管熄灭。

全亮 Judge = 2'b10 ->  在等待时间按下stop,给出违规显示数码管全亮,显示数字8。

显示三位数字 Judge = 2'b00 或 2'b11 -> 正常显示三位数字。

三位值确定:

1、实时值Now:在1~999ms中,通过计数器count求得实时显示值。

Now3 = count/100;        Now2 = (count/10)%10;         Now1 =count%10;

2、最大最小值Max\Min:按下暂停stop后,比较当前值Now与保存的最大最小值,进行更新。

3、平均值Ave:按下暂停stop后,更新总时长AllTime与总次数N,利用 AllTime / N 得到平均值。

显示三位值:

按照输入的 Min 、Max 、Ave 将实时值 或 最大值 或 最小值 或 平均值 赋值给显示的Data。

利用数码管动态扫描将三位Data值显示在数码管上。

二、程序代码

顶层文件

module Test(clk,clear,start,stop,restart,Min,Max,Ave,LED,codeout,SEG,w1,Data3,Data2,Data1,Data,Judge);
	input clk;	//50MHz时钟
	input clear,start,stop,restart;	//清零、开始、结束、重置
	input Min,Max,Ave;	//显示最小,最大、平均值
	
	output LED;	//LED显示
	output [6:0]codeout;	//数码管7段
	output [7:0]SEG;	//数码管8位
	
	output w1;	//分频后1kHz(1ms)
	output [3:0]Data3;	//第三位
	output [3:0]Data2;	//第二位
	output [3:0]Data1;	//第一位
	output [3:0]Data;	//显示位
	output [1:0]Judge;	//数码管显示模式控制
	
	//主模块:按输入,将最大值(3位)等存入Data3~Data1中,控制LED显示和数码管显示模式
	Test_1 t1(clk,w1,clear,start,stop,restart,Min,Max,Ave,LED,Data3,Data2,Data1,Judge);
 	//将三位数字Data3~Data1依次赋值给Data,同时控制数码管显示位数(SEG),使得显示出三位数字。Judge控制显示模式
	Test_2 t2(w1,Judge,Data3,Data2,Data1,Data,SEG);
	//将Data译码到七段数码管上
	Test_3 t3(Data,codeout);
	//将50MHz分频为1kHz(1ms),用于Test_1,Test_2
	Test_4 t4(clk,w1);
	
endmodule

主要功能模块

module Test_1(clk,w1,clear,start,stop,restart,Min,Max,Ave,LED,Data3,Data2,Data1,Judge);
	input clk;	//50MHz
	input w1;	//1kHz
	input clear,start,stop,restart;
	input Min,Max,Ave;
	
	output reg LED = 0;
	output reg [3:0]Data3 = 4'b0000;
	output reg [3:0]Data2 = 4'b0000;
	output reg [3:0]Data1 = 4'b0000;
	output reg [1:0]Judge = 2'b00;
	//实时值
	reg [3:0]Now3 = 4'b0000;
	reg [3:0]Now2 = 4'b0000;
	reg [3:0]Now1 = 4'b0000;
	//最小值
	reg [3:0]Min3 = 4'b0000;
	reg [3:0]Min2 = 4'b0000;
	reg [3:0]Min1 = 4'b0000;
	//最大值
	reg [3:0]Max3 = 4'b0000;
	reg [3:0]Max2 = 4'b0000;
	reg [3:0]Max1 = 4'b0000;
	//平均值
	reg [3:0]Ave3 = 4'b0000;
	reg [3:0]Ave2 = 4'b0000;
	reg [3:0]Ave1 = 4'b0000;
	
	//总时长和使用次数
	integer AllTime = 0;
	reg [4:0]N = 1;
	
	//随机数部分,通过计数器取余数获取随机值
	integer Random = 0;	//随机数
	integer k = 1;	//计数1~4001
	always@(posedge clk)
	begin
		if(k <= 4000) k <= k + 1;
		else k <= 1;
	end
	
	//主部分
	integer count = 0;	//计数器值1~999ms
	reg [1:0]control = 2'b00;	//状态转换机
	
	always@(posedge w1)
	begin
	case(control)
		2'b00:	//初始化;可重置、清零、开始计时;可进入等待01
			begin
				if(restart)	//重置restart
					begin
						count <= 1;	//计数重置
						LED <= 0;	//LED显示关闭
						Judge <= 2'b00;//数码管正常显示三位
						//当前值清零
						Now3 <= 0;	
						Now2 <= 0;
						Now1 <= 0;
						//最小值清零
						Min3 <= 0;	
						Min2 <= 0;
						Min1 <= 0;
						//最大值清零
						Max3 <= 0;	
						Max2 <= 0;
						Max1 <= 0;
						//平均值清零
						Ave3 <= 0;	
						Ave2 <= 0;
						Ave1 <= 0;
						//总时长清零
						AllTime <= 0;
						//使用次数清零
						N <= 1;
					end
			
				if(clear)	//清零clear
					begin
						count <= 1;	//计数重置
						LED <= 0;	//LED指示灯熄灭
						Judge <= 2'b00;	//数码管正常显示三位
						//当前值清零
						Now3 <= 0;	
						Now2 <= 0;
						Now1 <= 0;
					end
					
				if(start)	//开始计时start
					begin
						count <= 1;	//计数器重置为1
						Judge <= 2'b01;	//数码管全熄灭
						Random <= k % 4001 + 2000;	//随机时间2~6s
						
						control <= 2'b01; //进入等待部分
					end
			end
		2'b01:	//等待;可进入计时10,或者初始化00
			begin
				count <= count + 1;
				if(count >= Random)	//到达时间
					begin
						LED <= 1;	//LED灯提示
						count <= 1;	//计数器重置为1
						Judge <= 2'b00;	//数码管正常显示三位
								
						control <= 2'b10; //正式计时
					end
				if(stop)	//犯规
					begin
						count <= 1;	//计数器重置
						Judge <= 2'b10;	//数码管全亮给出提示
							
						control <= 2'b00;	//返回初始化
					end
			end
		2'b10:	//正式计时;可停止;可进入处理11(清零或重置)
			begin
				count <= count + 1;
				if(count > 999) //大于999ms错误
					begin
						count <= 1;	//计数器重置
						
						control <= 2'b11;	//进入处理11
					end
				if(stop)	//停止
					begin
						AllTime <= AllTime + count;	//总时间加上当前时间
						N <= N + 1;	//次数加一
						//计算平均值(总时长除以次数)
						Ave3 <= ((AllTime+count-N)/N)/100;
						Ave2 <= (((AllTime+count-N)/N)/10)%10;
						Ave1 <= ((AllTime+count-N)/N)%10;
						//计算最大值(如果当前值更大,则替换最大值)
						if((Max3<Now3)||(Max3==Now3&&Max2<Now2)||(Max3==Now3&&Max2==Now2&&Max1<Now1))
							begin
								Max3 <= Now3;
								Max2 <= Now2;
								Max1 <= Now1;
							end
						//计算最小值(如果当前值更小,则替换最小值,最小值为0也需替换)
						if((Min3==0&&Min2==0&&Min1==0)||(Min3>Now3)||(Min3==Now3&&Min2>Now2)||(Min3==Now3&&Min2==Now2&&Min1>Now1))
							begin
								Min3 <= Now3;
								Min2 <= Now2;
								Min1 <= Now1;
							end
							
						control <= 2'b11;	//进入处理11
					end
				//通过计数次数,给当前值赋值
				Now3 <= count/100;
				Now2 <= (count/10)%10;
				Now1 <= count%10;
			end
		2'b11://处理;可进行重置和清零;可进入初始化
			begin
				if(restart)	//重置restart
					begin
						count <= 1;	//计数重置
						LED <= 0;
						Judge <= 2'b00;
						//当前值清零
						Now3 <= 0;	
						Now2 <= 0;
						Now1 <= 0;
						//最小值清零
						Min3 <= 0;	
						Min2 <= 0;
						Min1 <= 0;
						//最大值清零
						Max3 <= 0;	
						Max2 <= 0;
						Max1 <= 0;
						//平均值清零
						Ave3 <= 0;	
						Ave2 <= 0;
						Ave1 <= 0;
						//总时长清零
						AllTime <= 0;
						//使用次数清零
						N <= 1;
					
						control <= 2'b00;	//进入初始化
					end
			
				if(clear)	//清零clear
					begin
						LED <= 0;	//LED指示灯熄灭
						count <= 1;	//计数重置
						Judge <= 2'b00;	//正常显示
						Now3 <= 0;	//当前值清零
						Now2 <= 0;
						Now1 <= 0;
						
						control <= 2'b00;	//进入初始化
					end
			end
		default:
			begin
			end
	endcase
		
	end
	
	//输出
	always@(posedge w1)
	begin
		if(control == 2'b10 || control == 2'b00)	//在计时状态和初始化状态输出实时值
			begin
				Data3 <= Now3;
				Data2 <= Now2;
				Data1 <= Now1;
			end
		if(Min)	//输出最小值
			begin
				Data3 <= Min3;
				Data2 <= Min2;
				Data1 <= Min1;
			end
		if(Max)	//输出最大值
			begin
				Data3 <= Max3;
				Data2 <= Max2;
				Data1 <= Max1;
			end
		if(Ave)	//输出平均值
			begin
				Data3 <= Ave3;
				Data2 <= Ave2;
				Data1 <= Ave1;
			end
	end
	
endmodule

显示功能模块

module Test_2(w1,Judge,Data3,Data2,Data1,Data,SEG);	
	input w1;
	input [1:0]Judge;
	input [3:0]Data1;
	input [3:0]Data2;
	input [3:0]Data3;
	output reg[3:0]Data = 4'b0000;
	
	output reg [7:0]SEG = 8'b00000000;	//位选信号
	reg [1:0]k = 2'b00;
	//通过Test_1模块控制Judge的值
	always@(posedge w1)
	begin
		if(Judge == 2'b01)	    //等待部分全熄灭
			begin
				SEG <= 8'b00000000;
			end
		else if(Judge == 2'b10)	//错误部分全亮,显示8
			begin
				SEG <= 8'b11111111;
				Data <= 4'b1000;
			end
		else	//正常循环显示三位数字
			begin
				if(k == 2'b00)		//第一位
					begin
						SEG <= 8'b00000001;
						Data <= Data1;
						k <= k + 2'b01;
					end
				else if(k == 2'b01)	//第二位
					begin
						SEG <= 8'b00000010;
						Data <= Data2;
						k <= k + 2'b01;
					end
				else				//第三位
					begin
						SEG <= 8'b00000100;
						Data <= Data3;
						k <= 2'b00;
					end
			end
	end
endmodule
module Test_3(Data,codeout);
	input[3:0] Data;//4位显示信号
	output reg[6:0] codeout = 7'b0000000;//7位输出信号
	
	always @(Data)//用always块语句描述逻辑
	begin
		case(Data)//case多分支条件语句,按输入显示对应输出
			4'd0 : codeout = 7'b1111110;
			4'd1 : codeout = 7'b0110000;
			4'd2 : codeout = 7'b1101101;
			4'd3 : codeout = 7'b1111001;
			4'd4 : codeout = 7'b0110011;
			4'd5 : codeout = 7'b1011011;
			4'd6 : codeout = 7'b1011111;
			4'd7 : codeout = 7'b1110000;
			4'd8 : codeout = 7'b1111111;
			4'd9 : codeout = 7'b1111011;
			default : codeout = 7'bx;//其他输入情况
		endcase
	end
endmodule//结束

分频器模块

module Test_4(clk,w1);
	input clk;
	output reg w1 = 0;
	
	integer k = 1;
	always@(posedge clk)
	begin
		if(k <= 25000)	//计数25000次
			k <= k + 1;
		else
			begin
				k <= 1;
				w1 <= ~w1;	//翻转一次
			end
	end
	
endmodule

三、ModelSim仿真

仿真包括三部分:

1、错误显示部分——在等待时间按下stop,数码管全亮显示数字8;

2、超时999ms部分——数码管显示三位数字999。

3、正常测试部分——此处测试三次,然后显示最大值、最小值、平均值;重置restart后,显示最大值、最小值、平均值。

注:需要计算好按下start和stop的时间,才能正常完成一次测试哟。

1、Test Bench文件

`timescale 10 ns/ 10 ns
module Test_vlg_tst();
reg Ave;
reg Max;
reg Min;
reg clear;
reg clk;
reg restart;
reg start;
reg stop;
// wires                                               
wire [3:0]  Data;
wire [3:0]  Data1;
wire [3:0]  Data2;
wire [3:0]  Data3;
wire [1:0]  Judge;
wire LED;
wire [7:0]  SEG;
wire [6:0]  codeout;
wire w1;
                         
Test i1 (  
	.Ave(Ave),
	.Data(Data),
	.Data1(Data1),
	.Data2(Data2),
	.Data3(Data3),
	.Judge(Judge),
	.LED(LED),
	.Max(Max),
	.Min(Min),
	.SEG(SEG),
	.clear(clear),
	.clk(clk),
	.codeout(codeout),
	.restart(restart),
	.start(start),
	.stop(stop),
	.w1(w1)
);
initial                                                
begin                                                  
    clk = 0;
    start = 0;
    stop = 0;
    clear = 0;
    restart = 0;
    Min = 0;
    Max = 0;
    Ave = 0;

    /*
    //错误显示,在等待时间按下stop
        //按下开始
    #100000
    start = 1;
    #100000
    start = 0;
    	//按下结束
    #200000
    stop = 1;
    #100000
    stop = 0;
	//按下清零
    #200000
    clear = 1;
    #100000
    clear = 0;
    */

    /*
    //超时999ms
        //按下开始
    start = 1;
    #10000000
    start = 0;
	//按下清零
    #500000000
    clear = 1;
    #10000000
    clear = 0;
    */

    /*
    //三次正常测试,求最大,最小,平均
    //第一次
	//按下开始
    start = 1;
    #10000000
    start = 0;
	//按下停止
    #350000000
    stop = 1;
    #10000000
    stop = 0;
	//按下清零
    #50000000
    clear = 1;
    #10000000
    clear = 0;
    //第二次
 	//按下开始
       #100000000
    start = 1;
    #10000000
    start = 0;
	//按下停止
    #380000000
    stop = 1;
    #10000000
    stop = 0;
	//按下清零
    #50000000
    clear = 1;
    #10000000
    clear = 0;
    //第三次
 	//按下开始
    #120000000
    start = 1;
    #10000000
    start = 0;
	//按下停止
    #270000000
    stop = 1;
    #10000000
    stop = 0;
	//按下清零
    #50000000
    clear = 1;
    #10000000
    clear = 0;

    //最小值
    #100000000
    Min = 1;
    #50000000
    Min = 0;

    //最大值
    #100000000
    Max = 1;
    #50000000
    Max = 0;

    //平均值
    #100000000
    Ave = 1;
    #50000000
    Ave = 0;

    //重置
    #100000000
    restart = 1;
    #10000000
    restart = 0;

    //最小值
    #50000000
    Min = 1;
    #30000000
    Min = 0;

    //最大值
    #50000000
    Max = 1;
    #30000000
    Max = 0;

    //平均值
    #50000000
    Ave = 1;
    #30000000
    Ave = 0;
    */

$display("Running testbench");                       
end                                                    
always#1 clk = ~clk;                                                                                              
endmodule

2、波形图

1、错误显示

2、超时

3、正常测试

注:具体操作可查看本专栏中其他文章。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值