2021-08-22 16:45:23 索煒達電子 1092
項目編號:E434
文件大?。?.2M
源碼說明:帶中文注釋
開發(fā)環(huán)境:Verilog
簡要概述
項目名稱:百分之秒精度的計時器的FPGA實現(xiàn)
課程名稱:Verilog HDL硬件描述語言(三級項目)
2021年4月
摘要
使用1MHz的晶振實現(xiàn)百分之一秒精度的計時器。
本報告講展示使用Questa Sim的仿真,以證實理論的可行性。
主要構(gòu)成(需要用到的材料)
硬件(具體實現(xiàn))
1MHz的晶振
FPGA開發(fā)板
軟件
-Visual Studio Code
-Questa Sim-64 2020.1
-(Quartus II 在實際燒寫時會用到)
工作原理
計時器主體
從后往前逐位進位,一共6位,第2,4,5,6位逢10進1,第1,3位逢6進1。
不需要進位的時候,直接在末尾加1。
reset按鍵
在具體實現(xiàn)reset按鍵的時候可以引入一個按鍵消抖功能。
reg key_inner[1:0];
在clk的上升沿觸發(fā),每次遇到reset==1時為key_inner[1:0]+1,當(dāng)連續(xù)3次假發(fā)后key_inner[1]為高電平,進行復(fù)位操作。
00 => 01 => 10 => 11 => 00
key_inner[1]的電平狀態(tài):
低電平===>高電平 ==>低電平
代碼解析(代碼見附錄1)
khmtimer.v
因為使用非阻塞賦值,則如果當(dāng)前數(shù)值是x-1,比如最后一位是9,那么到這次時鐘周期,該進位了,直接不進行加一,而是清零并且下一位+1。這樣每一位最大就是9,也就是1001,因此4個二進制位代表1位,一共需要4×6=24個二進制位來表示當(dāng)前時間。reg[23:0] nowtime;
khmtimer_tb.v
為了產(chǎn)生1MHz的信號,我們需要仿真最小的時間單元為500ns,因此,仿真精度應(yīng)選擇100ns。
電路接線圖
各模塊的注解:
#INITIAL#39 為 clk信號發(fā)生器,即1MHz的晶振
#INITIAL#67 為 reset信號發(fā)生器,即復(fù)位按鍵的狀態(tài)
#INITIAL#29, 35 為 10000分頻器用于生成100Hz的clk信號
#ALWAYS#71 為 主體計時模塊,輸入100Hz的clk信號,key_flag是reset的狀態(tài)輸入,計時滿1小時carry在1個時鐘周期內(nèi)會產(chǎn)生高電平,nowtime為當(dāng)前時間的實時輸出
仿真圖
10000分頻器演示
可以看到,通過對1MHz的clk信號10000分頻,產(chǎn)生了100Hz的clk_100hz信號。
(注:為了加速仿真,暫時在1ms的環(huán)境下生成的下列圖片,即直接產(chǎn)生100Hz信號)
reset功能
可以看到,當(dāng)reset信號為高電平時,nowtime會在下一個clk的上升沿置零。
可以看到計時滿1小時時,carry會出現(xiàn)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
);
//定義分頻器的計數(shù)寄存器
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產(chǎn)生100HZ的時鐘信號
always@(posedge clk)
begin
if(count == 4999)
begin
clk_100hz <= !clk_100hz;
count <= 0;
end
else
count <= count+1;
end
//*/
//(3)計時處理部分
//這行是為了加速仿真,直接產(chǎn)生所需的100Hz的clk信號
//always@(posedge clk)
//這行是正式使用的1MHz轉(zhuǎn)100Hz信號
always@(posedge clk_100hz)
begin
carry <= 1'b0;
//判斷是否復(fù)位鍵
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復(fù)位信號
#(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作業(yè)提交完畢
│ .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三級項目報告內(nèi)容.md
│ 孔昊旻的HDL三級項目報告內(nèi)容.pdf
│ 孔昊旻的HDL三級項目報告內(nèi)容1.md
│ 孔昊旻的HDL三級項目報告內(nèi)容_final.md
│ 孔昊旻的HDL三級項目報告內(nèi)容_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
│ 十進制計數(shù)器.v
│ 基于verilog數(shù)字秒表的設(shè)計實現(xiàn).docx
└ 基于verilog數(shù)字秒表的設(shè)計實現(xiàn).pdf