欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的秒表计时系统设计–第一版–郝旭帅电子设计团队。
功能说明:
-
利用六个数码管显示。
-
以10ms为精度显示
-
以秒为单位进行显示
-
记录最大为999.99
-
第一个数码管在运行时不显示
-
在翻看记录时,第一个数码管显示记录的次数
-
最多可以记录9次
-
使用说明:先按下启动,再按下记录(可以多次记录,此时秒依然运行),按下停止,按翻看即可。重复以上步骤
使用平台:本次设计应用Altera的平台设计(芯片:EP4CE10F17C8N)。
仿真平台:Modelsim。
作者QQ:746833924
说明:本篇设计中不涉及到IP和原语,代码在其他平台依然可以适用;当其他板卡电路不同时,会导致不同的现象出现,如有需要修改代码请联系作者;如需作者使用的板卡,请联系作者;
设计思想如下:
key_ctrl模块负责将外部的按键信号进行消抖,并且产生对应边沿变化时的脉冲;sec_timer_ctrl模块负责根据脉冲信号和设计逻辑产生对应数字逻辑;seven_tube_drive(七段数码管驱动)模块负责将sec_timer_ctrl模块产生的数字逻辑显示到数码管上。
key_ctrl模块设计思想为:按键信号是由外部机械式按键产生,每次按下或者抬起时,会产生一定的抖动。如果直接对其进行边沿检测就会导致多次触发。故而需要设计按键消抖,进而对消抖之后的波形进行边沿检测。消抖原理为:外部按键信号发生改变后,如果能够持续20ms,没有新的改变,就认为此次改变不是抖动,而是真正的按下,然后进行采样即可。
// 记录任意边沿之后没有遇到新的边沿的时间长度是否达到20Ms
//---------------------------------------------------------------------------------------
always@(posedgeclk)begin
if(rst_n ==1'b0)
cnt_20ms <=20'd0;
else
if(pulse_key_negedge ==1'b1||pulse_key_posedge ==1'b1)
cnt_20ms <=20'd1;
else
if(cnt_20ms >20'd0&&cnt_20ms <T_20ms)
cnt_20ms <=cnt_20ms +1'b1;
else
cnt_20ms <=20'd0;
end
// ---------------------------------------------------------------------------------------
// 任意边沿之后没有遇到新的边沿的时间长度达到20Ms,认为按键稳定,此时采样
//--------------------------------------------------------------------------------------
always@(posedgeclk)begin
if(rst_n ==1'b0)
key_wave <=1'b1;
else
if(cnt_20ms ==T_20ms)
key_wave <=key_rr;
else
key_wave <=key_wave;
end
//--------------------------------------------------------------------------------------
// 对消抖之后的按键信号进行边沿检测
//---------------------------------------------------------------------------------------------
initialkey_wave_r =1'b1;
always@(posedgeclk)key_wave_r <=key_wave;
assignflag_neg =(key_wave_r ==1'b1&&key_wave ==1'b0)?1'b1:1'b0;
assignflag_pos =(key_wave_r ==1'b0&&key_wave ==1'b1)?1'b1:1'b0;
//--------------------------------------------------------------------------------------------
sec_timer_ctrl模块的设计思想:首先根据外部的启动停止脉冲,确定运行的模式。
always @ (posedge clk) begin
if (rst_n == 1'b0)
state_run <= 1'b0;
else
if (flag_start_stop == 1'b1)
state_run <= ~state_run;
else
state_run <= state_run;
end
在运行模式下,启动10ms计时器。
always @ (posedge clk) begin
if (rst_n == 1'b0)
cnt_10ms <= 19'd0;
else
if (state_run == 1'b1)
if (cnt_10ms < T_10ms - 1'b1)
cnt_10ms <= cnt_10ms + 1'b1;
else
cnt_10ms <= 19'd0;
else
cnt_10ms <= 19'd0;
end
在运行模式下,记录经过了多少个10ms。记录的信息要在下一次启动的时刻才可以清除,并不能停止就清除;因为还需要查看信息呢。
下一次的启动时刻:非运行状态下,启动停止按键被按下。
always @ (posedge clk) begin
if (rst_n == 1'b0)
counter <= 32'd0;
else
if (state_run == 1'b0 && flag_start_stop == 1'b1)
counter <= 32'd0;
else
if (state_run == 1'b1 && cnt_10ms == T_10ms - 1'b1)
if (counter < 99999)
counter <= counter + 1'b1;
else
counter <= counter;
else
counter <= counter;
end
利用移位寄存器的思想记录每一次数值(最多只能记录九次)。
always @ (posedge clk) begin
if (rst_n == 1'b0)
counter_buf <= 320'd0;
else
if (state_run == 1'b1 && flag_record == 1'b1 && record_num < 4'd9)
counter_buf <= {counter_buf[287:32], counter, counter};
else
counter_buf <= counter_buf;
end
统计记录的次数,同样也得需要下一次启动的时刻才可以清除。
always @ (posedge clk) begin
if (rst_n == 1'b0)
record_num <= 4'd0;
else
if (state_run == 1'b0 && flag_start_stop == 1'b1)
record_num <= 4'd0;
else
if (state_run == 1'b1 && flag_record == 1'b1)
if (record_num < 4'd9)
record_num <= record_num + 1'b1;
else
record_num <= record_num;
else
record_num <= record_num;
end
在停止状态下,根据外部按键,确认需要翻看的是那一次的记录。当然,如果下一次启动开始了,翻看的记录也需要归零。
always @ (posedge clk) begin
if (rst_n == 1'b0)
show_num <= 4'd0;
else
if (state_run == 1'b0 && flag_start_stop == 1'b1)
show_num <= 4'd0;
else
if (state_run == 1'b0 && flag_show == 1'b1)
if (show_num < record_num)
show_num <= show_num + 1'b1;
else
show_num <= 4'd1;
else
show_num <= show_num;
end
在运行状态下,数码管显示正在跑的描述;在非运行状态中,如果没有记录或者翻看,一直显示停止记录的秒数,如果开始翻看,则开始显示记录的数值。
always @ (posedge clk) begin
if (rst_n == 1'b0)
show_data <= 32'd0;
else
if (state_run == 1'b1)
show_data <= counter;
else
if (record_num == 4'd0 || show_num == 4'd0)
show_data <= counter;
else
show_data <= (counter_buf >> {show_num, 5'd0});
end
根据显示的方式,计算出每个位应该显示的内容。
initial data[23:0] = 4'hf;
always @ (posedge clk) begin
if (rst_n == 1'b0)
data[23:20] <= 4'hf;
else
if (state_run == 1'b1)
data[23:20] <= 4'hf;
else
if (record_num == 4'd0 || show_num == 4'd0)
data[23:20] <= 4'hf;
else
data[23:20] <= record_num + 1 - show_num;
end
always @ (posedge clk) begin
if (rst_n == 1'b0)
data[19:0] <= 20'd0;
else begin
data[3:0] <= show_data%10;
data[7:4] <= show_data/10%10;
data[11:8] <= show_data/100%10;
data[15:12] <= show_data/1000%10;
data[19:16] <= show_data/10000%10;
end
end
以上即为sec_timer_ctrl模块的设计思想;
七段数码管为普通六位一体的共阳极数码,采用动态驱动的方式,在此不再赘述。
下板后,我们就可以看到秒表计时的运行情况。
当然我们也可以使用按键进行启动、记录、翻看等运行情况。
下板后,演示视频(链接)如下:
https://www.bilibili.com/video/BV15z421B7iC/?spm_id_from=333.999.0.0&vd_source=b5405faeab8632f02533bcbfc5e52e55
本设计所有内容(设计代码、设计工程)链接为:
链接:https://pan.baidu.com/s/19-14DaRzg_H0OLbZ77GWUg
提取码:vr1x
本篇内容中有部分资源来源于网络,如有侵权,请联系作者。
如果您觉得本公众号还不错的话,可以推给身边的朋友们,感谢并祝好!