0.0s至9.9s计时的秒表设计
文章目录
基础:时间基准电路
- 定时发出一个窄脉冲的电路
- 时序
- 每T时间,生成一个宽度为P时间的脉冲
- 电路的工作时钟的周期为P
- 使用一个计数器可以实现该时序
本质上是一个两级计数器级联的的电路结构,第一级计数器生成时间基准信号,第二级计数器用时间基准信号作为计数使能。
时间基准电路为基础的0至9计数器
内部结构
计数器cnt_sync RTL视图:
带使能的计数器cnt_en_0to9 RTL视图:
相比之下带使能的只是相比普通的用上了寄存器本来的ENA端口。
仿真
将时间基准模块的最大计数值参数改为5,方便仿真观察。
第二个计数器由第一个计数器使能驱动。
SignalTap观测、分段触发采集
时间基准计数器的最大值改回25000000,进行SignalTap观测。
在长长的数据中,一次只能截取一次计数值的跳变,不利于观察和调试:分段触发。
在右侧Signal Configuration设置中,首先勾选Segmented,再在右侧选择分段数目和每次采样点数。这里选择8段,每段16点。
编译,下载,运行,采样,观察采样结果。
如图,每次抓取触发事件附近的波形样点,抓取多次,省略了跳变中间大量的计数过程,结果清晰明了。
计时0.0至9.9秒表
顶层设计
第一部分是时间基准电路,第二部分是0.1秒和1秒分开计数,第三部分是输出的译码。
先做时间基准电路,然后输出作0.1计数的使能。
0.1秒的计数输出作1秒计数的使能。
两个计数的输出送到译码器然后输出。
原理图
带使能的计数器设计
对秒表添加功能主要是在计时间的这部分添加,主要是在代码里加入判断语句。
使能
这个和前面的设计一样,加一个if判断即可。
复位
复位功能也是加if判断。
由于是按键控制。不按时输入为0,所以在!RST时复位。
因为复位功能优先级最高,所以将复位放在最外面的if判断条件内。
暂停
暂停功能和使能类似,不过需要一个变量来存储是否需要暂停。
如果暂停就不再计数,所以暂停的判断也要放在EN外。
代码
module cnt_en_0to9( CLK , CNTVAL , EN , RST , HOLD , OV );
input CLK;
input EN;
input RST;
input HOLD;
output [4-1:0] CNTVAL;
output OV;
parameter MAX_VAL = 9;
reg ifHOLD;
reg [4-1:0] CNTVAL;
reg OV;
always @ (posedge HOLD) begin //if stop count or not
ifHOLD <= !ifHOLD;
end
always @ (posedge CLK) begin //cnt
if (!RST)
CNTVAL <= 0;
else if (!ifHOLD) begin
if (EN) begin
if (CNTVAL >= MAX_VAL)
CNTVAL <= 0;
else
CNTVAL <= CNTVAL + 1'b1;
end
else
CNTVAL <= CNTVAL;
end
end
always @ (CNTVAL) begin //ov
if(CNTVAL == MAX_VAL)
OV = 1'b1;
else
OV = 1'b0;
end
endmodule
管脚分配
这个实验相比之前的实验使用的管脚多了很多,一个个设置很麻烦,浪费生命。使用导入预设的方法来设置管脚。
先新建一个文本文档(.txt),位置无所谓。按照格式输入端口和管脚的分配关系。
文本格式:第一行为
to, location
之后罗列端口和对应的管脚,格式为
端口名 , 管脚
本工程中的管脚分配预设文件为:(芯片为EP3C16F484C)
to, location
CLK50 ,PIN_G21
RST ,PIN_F1
HOLD ,PIN_G3
sec_leds[0] ,PIN_A13
sec_leds[1] ,PIN_B13
sec_leds[2] ,PIN_C13
sec_leds[3] ,PIN_A14
sec_leds[4] ,PIN_B14
sec_leds[5] ,PIN_E14
sec_leds[6] ,PIN_A15
sec_leds7 ,PIN_B15
decimalsec_leds[0] ,PIN_E11
decimalsec_leds[1] ,PIN_F11
decimalsec_leds[2] ,PIN_H12
decimalsec_leds[3] ,PIN_H13
decimalsec_leds[4] ,PIN_G12
decimalsec_leds[5] ,PIN_F12
decimalsec_leds[6] ,PIN_F13
sec_ov ,PIN_J1
decimalsec_ov ,PIN_J2
保存之后在quartus中导入。
先选择上方Assignments,然后选择Import Assignments,最后找到预设的文件导入就可以了。
最后上板子就可以啦。
Verilog整体代码
module segment4to7( N , LEDS );
input [4-1:0] N;
output [7-1:0] LEDS;
reg [7-1:0] LEDS;
always @ (N) begin
case (N)
4'b0000: LEDS <= 7'b1000000;
4'b0001: LEDS <= 7'b1111001;
4'b0010: LEDS <= 7'b0100100;
4'b0011: LEDS <= 7'b0110000;
4'b0100: LEDS <= 7'b0011001;
4'b0101: LEDS <= 7'b0010010;
4'b0110: LEDS <= 7'b0000010;
4'b0111: LEDS <= 7'b1111000;
4'b1000: LEDS <= 7'b0000000;
4'b1001: LEDS <= 7'b0010000;
default: LEDS <= 7'b1111111;
endcase
end
endmodule
module cnt_sync( CLK , CNTVAL , OV );
input CLK;
output [32-1:0] CNTVAL;
output OV;
parameter MAX_VAL = 5_000_000;
reg [32-1:0] CNTVAL;
reg OV;
always @ (posedge CLK) begin
if(CNTVAL >= MAX_VAL)
CNTVAL <= 0;
else
CNTVAL <= CNTVAL + 1'b1;
end
always @ (CNTVAL) begin
if(CNTVAL == MAX_VAL)
OV = 1'b1;
else
OV = 1'b0;
end
endmodule
module cnt_en_0to9( CLK , CNTVAL , EN , RST , HOLD , OV );
input CLK;
input EN;
input RST;
input HOLD;
output [4-1:0] CNTVAL;
output OV;
parameter MAX_VAL = 9;
reg ifHOLD;
reg [4-1:0] CNTVAL;
reg OV;
always @ (posedge HOLD) begin //if stop count or not
ifHOLD <= !ifHOLD;
end
always @ (posedge CLK) begin //cnt
if (!RST)
CNTVAL <= 0;
else if (!ifHOLD) begin
if (EN) begin
if (CNTVAL >= MAX_VAL)
CNTVAL <= 0;
else
CNTVAL <= CNTVAL + 1'b1;
end
else
CNTVAL <= CNTVAL;
end
end
always @ (CNTVAL) begin //ov
if(CNTVAL == MAX_VAL)
OV = 1'b1;
else
OV = 1'b0;
end
endmodule