2021-08-22 16:45:23 索炜达电子 1096
项目编号:E434
文件大小:2.2M
源码说明:带中文注释
开发环境:Verilog
简要概述
项目名称:百分之秒精度的计时器的FPGA实现
课程名称:Verilog HDL硬件描述语言(三级项目)
2021年4月
摘要
使用1MHz的晶振实现百分之一秒精度的计时器。
本报告讲展示使用Questa Sim的仿真,以证实理论的可行性。
主要构成(需要用到的材料)
硬件(具体实现)
1MHz的晶振
FPGA开发板
软件
-Visual Studio Code
-Questa Sim-64 2020.1
-(Quartus II 在实际烧写时会用到)
工作原理
计时器主体
从后往前逐位进位,一共6位,第2,4,5,6位逢10进1,第1,3位逢6进1。
不需要进位的时候,直接在末尾加1。
reset按键
在具体实现reset按键的时候可以引入一个按键消抖功能。
reg key_inner[1:0];
在clk的上升沿触发,每次遇到reset==1时为key_inner[1:0]+1,当连续3次假发后key_inner[1]为高电平,进行复位操作。
00 => 01 => 10 => 11 => 00
key_inner[1]的电平状态:
低电平===>高电平 ==>低电平
代码解析(代码见附录1)
khmtimer.v
因为使用非阻塞赋值,则如果当前数值是x-1,比如最后一位是9,那么到这次时钟周期,该进位了,直接不进行加一,而是清零并且下一位+1。这样每一位最大就是9,也就是1001,因此4个二进制位代表1位,一共需要4×6=24个二进制位来表示当前时间。reg[23:0] nowtime;
khmtimer_tb.v
为了产生1MHz的信号,我们需要仿真最小的时间单元为500ns,因此,仿真精度应选择100ns。
电路接线图
各模块的注解:
#INITIAL#39 为 clk信号发生器,即1MHz的晶振
#INITIAL#67 为 reset信号发生器,即复位按键的状态
#INITIAL#29, 35 为 10000分频器用于生成100Hz的clk信号
#ALWAYS#71 为 主体计时模块,输入100Hz的clk信号,key_flag是reset的状态输入,计时满1小时carry在1个时钟周期内会产生高电平,nowtime为当前时间的实时输出
仿真图
10000分频器演示
可以看到,通过对1MHz的clk信号10000分频,产生了100Hz的clk_100hz信号。
(注:为了加速仿真,暂时在1ms的环境下生成的下列图片,即直接产生100Hz信号)
reset功能
可以看到,当reset信号为高电平时,nowtime会在下一个clk的上升沿置零。
可以看到计时满1小时时,carry会出现1个时钟周期的高电平,并且,nowtime会重置为0。
附录1 Verilog代码
1、程序代码(khmtimer.v)
//khmtimer.v
/*
* Author:Haomin Kong
* Tel:15933998367
* E-mail:a645162@qq.com
* Toolchain:
* Visual Studio Code
* Questa Sim-64 2020.1
* 2021/4/2 18:18:00 Created
* 2021/4/12 19:45:00 Finished
* Open source on Gitee:
* https://gitee.com/a645162/fpga_-timer_10ms
* */
//加速测试使用
//`timescale 1ms/1ms
`timescale 100ns/100ns
module khmtimer(
input wire clk,
input wire reset,
output reg[23:0] nowtime,
output reg carry
);
//定义分频器的计数寄存器
reg[13:0] count = 1'b0;
//工作信号,1MHz的时钟信号10000分频,得到100Hz的时钟信号
reg clk_100hz = 1'b1;
//reset
reg key_flag = 1'b1;
initial
begin
//count <= 1'b0;
//不需要这一行,直接在初始时刻给一个reset信号即可
//nowtime[23:0] <= 24'h0;
//clk_100hz <= 1'b1;
carry <= 1'b0;
end
//(1)reset按键
always@(posedge reset)
begin
key_flag = 1'b1;
end
///*
//(2)分频器,通过1MHz产生100HZ的时钟信号
always@(posedge clk)
begin
if(count == 4999)
begin
clk_100hz <= !clk_100hz;
count <= 0;
end
else
count <= count+1;
end
//*/
//(3)计时处理部分
//这行是为了加速仿真,直接产生所需的100Hz的clk信号
//always@(posedge clk)
//这行是正式使用的1MHz转100Hz信号
always@(posedge clk_100hz)
begin
carry <= 1'b0;
//判断是否复位键
if(key_flag)
begin
key_flag = 1'b0;
nowtime <= 24'h0;
end
else
begin
if(nowtime[3:0] == 4'h9)
begin
nowtime[3:0] <= 4'h0;
if(nowtime[7:4]==4'h9)
begin
nowtime[7:4] <= 4'h0;
if(nowtime[11:8] == 4'h9)
begin
nowtime[11:8] <= 4'h0;
if(nowtime[15:12] == 4'h5)
begin
nowtime[15:12] <= 4'h0;
if(nowtime[19:16] == 4'h9)
begin
nowtime[19:16] <= 4'h0;
if(nowtime[23:20] == 4'h5)
begin
nowtime[23:20] <= 4'h0;
carry <= 1'b1;
end
else
nowtime[23:20] <= nowtime[23:20] + 1;
end
else
nowtime[19:16] <= nowtime[19:16] + 1;
end
else
nowtime[15:12] <= nowtime[15:12] + 1;
end
else
nowtime[11:8] <= nowtime[11:8] + 1;
end
else
nowtime[7:4] <= nowtime[7:4] + 1;
end
else
nowtime[3:0] <= nowtime[3:0] + 1;
end
end
endmodule
2、Testbench代码(khmtimer_tb.v)
//khmtimer_tb.v
/*
* Author:Haomin Kong
* Tel:15933998367
* E-mail:a645162@qq.com
* Toolchain:
* Visual Studio Code
* Questa Sim-64 2020.1
* 2021/4/2 18:18:00 Created
* 2021/4/12 19:45:00 Finished
* Open source on Gitee:
* https://gitee.com/a645162/fpga_-timer_10ms
* */
//加速测试使用
//`timescale 1ms/1ms
`timescale 100ns/100ns
`include "khmtimer.v"
module khmtimer_tb();
//输入频率为1MHz的时钟
parameter clk_period = 10;
parameter clk_period_1s = clk_period * 1000 * 1000;
//这里是1小时10秒
parameter[63:0] c_period_1h = clk_period_1s * 60 * 60 * 1 + clk_period_1s * 10;
//这里是2小时10秒
//parameter[63:0] c_period_2h = clk_period_1s * 60 * 60 * 2 + clk_period_1s * 10;
//10ms也就是100Hz(即1/100s)
reg clk;
reg reset_key;
wire[23:0] nowtime;
wire carry;
//生成时钟信号
initial begin
clk = 1'b1;
forever #(clk_period/2) clk = !clk;
end
khmtimer khm1(
.clk(clk),
.reset(reset_key),
.nowtime(nowtime),
.carry(carry)
);
/*
initial begin
reset_key=1'b0;
//仿真reset复位信号
#(clk_period*10) reset_key <= 1'b1;
#(clk_period*10) reset_key <= 1'b0;
#(clk_period*10) reset_key <= 1'b1;
#(clk_period*10) reset_key <= 1'b0;
$display ("The current time is (%0d ps)", $time);
#(clk_period*100) $stop;
end
*/
///*
initial begin
reset_key=1'b0;
//仿真两小时零1秒
#(c_period_1h) $stop;
end
//*/
endmodule
目录│文件列表:
└ fpga_-timer_10ms-Verilog作业提交完毕
│ .gitignore
│ carry.png
│ clk_test.v
│ div.png
│ khmtimer.v
│ khmtimer_tb.v
│ khmworkok.v
│ khmworkok_tb.v
│ LICENSE
│ modelsim.ini
│ QQ图片20210412180552.png
│ QQ图片20210412180626.png
│ README.md
│ reset.png
│ tb_two.png
│ timer.mpf
│ timescale.png
│ vsim.wlf
│ wire.png
│ 孔昊旻Verilog HDL三级项目.docx
│ 孔昊旻报告封皮-pic.pdf
│ 孔昊旻报告封皮.docx
│ 孔昊旻报告封皮.pdf
│ 孔昊旻的HDL三级项目报告内容.md
│ 孔昊旻的HDL三级项目报告内容.pdf
│ 孔昊旻的HDL三级项目报告内容1.md
│ 孔昊旻的HDL三级项目报告内容_final.md
│ 孔昊旻的HDL三级项目报告内容_final.pdf
├ backup
│ │ clk_test.v
│ │ khmtimer.v
│ │ khmtimer_tb.v
│ │ khmwork.v
│ │ khmworkok.v
│ │ khmworkok_tb.v
│ └ khmwork_tb.v
└ 参考资料
│ h1.v
│ hdlbits.v
│ homework.v
│ module led_on.v
│ mpclock.v
│ 十进制计数器.v
│ 基于verilog数字秒表的设计实现.docx
└ 基于verilog数字秒表的设计实现.pdf