【E434】FPGA精确到100分之1秒的计时器

2021-08-22 16:45:23      索炜达电子      722     

项目编号: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。

【E434】FPGA精确到100分之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。

电路接线图

【E434】FPGA精确到100分之1秒的计时器

各模块的注解:

  • #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分频器演示

【E434】FPGA精确到100分之1秒的计时器

可以看到,通过对1MHz的clk信号10000分频,产生了100Hz的clk_100hz信号。


(注:为了加速仿真,暂时在1ms的环境下生成的下列图片,即直接产生100Hz信号)


reset功能

【E434】FPGA精确到100分之1秒的计时器

可以看到,当reset信号为高电平时,nowtime会在下一个clk的上升沿置零。

【E434】FPGA精确到100分之1秒的计时器

可以看到计时满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

TAG计时器
  • 7 次
  • 1 分