[FPGA]Verilog 60s秒表计时器

1.引述

这次的实验来自于本人本科课程数电结课时的自选题目。由于这次上传是后知后觉,学校已将小脚丫板子回收,所以在这篇文章中没法贴出代码结果的效果图了,但最终效果已经过测试,可放心食用。那么下面就贴上代码并略加讲解供大家参考。

2.分频模块

我们要实现一个秒表,自然要将实验板中的时钟脉冲clk分频为一个周期为1s的脉冲,已知小脚丫板子的晶振为12MHz。下面贴上分频模块的代码。

module divide #
( //parameter是verilog里参数定义
parameter WIDTH = , //计数器的位数,计数的最大值为 2**(WIDTH-1)
parameter N = 12_000_000 //分频系数,请确保 N<2**(WIDTH-1),否则计数会溢出
)
(
input clk, //clk频率为12MHz
input rst_n, //复位信号,低有效,
output clkout //输出信号,可以连接到LED观察分频的时钟
);
reg [WIDTH-:] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟
//上升沿触发时计数器的控制
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_p <= 'b0;
else if(cnt_p == (N-))
cnt_p <= 'b0;
else
cnt_p <= cnt_p + 'b1; //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器
end
//上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_p <= 'b0;
else if(cnt_p < (N>>)) //N>>1表示右移一位,相当于除以2取商
clk_p <= 'b0;
else
clk_p <= 'b1; //得到的分频时钟正周期比负周期多一个clk时钟
end
//下降沿触发时计数器的控制
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_n <= 'b0;
else if(cnt_n == (N-))
cnt_n <= 'b0;
else
cnt_n <= cnt_n + 'b1;
end
//下降沿触发的分频时钟输出,和clk_p相差半个clk时钟
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
clk_n <= 'b0;
else if(cnt_n < (N>>))
clk_n <= 'b0;
else
clk_n <= 'b1; //得到的分频时钟正周期比负周期多一个clk时钟
end
wire clk1 = clk; //当N=1时,直接输出clk
wire clk2 = clk_p; //当N为偶数也就是N的最低位为0,N[0]=0,输出clk_p
wire clk3 = clk_p & clk_n; //当N为奇数也就是N最低位为1,N[0]=1,输出clk_p&clk_n。正周期多所以是相与
assign clkout = (N==)? clk1:(N[]? clk3:clk2); //条件判断表达式
endmodule

3.八位数码管显示模块

小脚丫板子上有两个八位数码管显示,本实验中用来显示从00s到59s的显示。下面贴上数码管显示模块的代码。

module segment
(
input wire [:] seg_data_1, //四位输入数据信号
input wire [:] seg_data_2, //四位输入数据信号
output wire [:] segment_led_1, //数码管1,MSB~LSB = SEG,DP,G,F,E,D,C,B,A
output wire [:] segment_led_2 //数码管2,MSB~LSB = SEG,DP,G,F,E,D,C,B,A
);
reg[:] seg [:]; //存储7段数码管译码数据
initial
begin
seg[] = 'h3f; // 0
seg[] = 'h06; // 1
seg[] = 'h5b; // 2
seg[] = 'h4f; // 3
seg[] = 'h66; // 4
seg[] = 'h6d; // 5
seg[] = 'h7d; // 6
seg[] = 'h07; // 7
seg[] = 'h7f; // 8
seg[] = 'h6f; // 9
seg[]= 'h77; // A
seg[]= 'h7C; // b
seg[]= 'h39; // C
seg[]= 'h5e; // d
seg[]= 'h79; // E
seg[]= 'h71; // F
end
assign segment_led_1 = seg[seg_data_1];
assign segment_led_2 = seg[seg_data_2];
endmodule

4.功能讲解

在主模块中除了要例化上述的两个模块之外,还需给这个秒表添砖加瓦一下!标题中提到这是一个60s秒表,而我们数码管显示只从00到59,但最大计时量程却达到了9min,这是怎么办到的呢?这里我们就用到了小脚丫上的一排八位LED灯,每当计到59s时,下一秒数码管显示回到00,点亮八位LED灯中的一个,达到表示已计过了1min的作用。一共有八位LED灯,当八个灯都被点亮后,数码管还有一次从00到59的显示机会,这样我们就的得到了一个最大计时量程为9min的秒表啦!下面贴上八位LED灯显示部分的代码。

always@(posedge clk)
if(cnt1=='b0)
LED[:]<='b11111111;
else if(cnt1=='b0001)
LED[:]<='b11111110;
else if(cnt1=='b0010)
LED[:]<='b11111100;
else if(cnt1=='b0011)
LED[:]<='b11111000;
else if(cnt1=='b0100)
LED[:]<='b11110000;
else if(cnt1=='b0101)
LED[:]<='b11100000;
else if(cnt1=='b0110)
LED[:]<='b11000000;
else if(cnt1<='b0111)
LED[:]<='b10000000;
else if(cnt1<='b1000)
LED[:]<='b00000000;

此外作为一个秒表自然就要有暂停和开始计时的功能(当然清零功能也是有哒!主模块中就用rst复位键来实现,这里不多赘述。)暂停和开始计时这里我就用同一个按键实现。小脚丫板子上还有两个RGB三色灯,既然有这么好的资源存在,我们就要物尽其用!按下开始计时键时,秒表开始计时,数码管显示开始变化,此处我们让RGB三色灯中的一个等亮绿灯,表示处于正常计时状态中;当再次按键开启键时,秒表暂停,我们让另一个RGB三色灯亮红色,表示处于暂停状态。下面贴上包含三色灯点亮的部分代码。

always @(posedge clk1h or negedge rst) //产生60进制计数器
begin //数码管显示要按照十进制的方式显示
if(!rst)
begin
cnt <= 'h00; //复位初值显示00
cnt1<='b0;
end
else if(flag)
begin
G_LED2<='b0;
R_LED1<='b1;
if(cnt[:] == 'd9) //个位满九?
begin
cnt[:] <= 'd0; //个位清零
if(cnt[:] == 'd5 ) //十位满五?
begin
cnt[:] <= 'd0; //十位清零
cnt1<=cnt1+;
end
else
begin
cnt[:] <= cnt[:] + 'b1; //十位加一
cnt1<=cnt1;
end
end
else cnt[:] <= cnt[:] + 'b1; //个位加一
end
else
begin
cnt <= cnt;
G_LED2<='b1;
R_LED1<='b0;
end
end

5.主模块

最后贴上主模块的代码,完成整个秒表的实现。

module counter60
(
input clk,rst, //时钟和复位输入
input key, //启动暂停按键
output wire [:] segment_led_1,segment_led_2, //数码管输出
output reg [:] LED, //八位LED灯
output reg R_LED1,G_LED2 //RGB三色灯,此处用红色表示处于暂停状态中,绿色表示处于正常计时中
);
wire clk1h; //1秒时钟
reg [:] cnt; //计时计数器
reg [:] cnt1; //分钟计数器
reg flag; //启动暂停标志 divide # //例化分频器产生1秒时钟信号
(
.WIDTH(),
.N(12_000_000)
) u1
(
.clk(clk),
.rst_n(rst),
.clkout(clk1h)
);
segment u2 //例化数码管显示模块
(
.seg_data_1 (cnt[:]), //seg_data input
.seg_data_2 (cnt[:]), //seg_data input
.segment_led_1 (segment_led_1), //MSB~LSB = SEG,DP,G,F,E,D,C,B,A
.segment_led_2 (segment_led_2) //MSB~LSB = SEG,DP,G,F,E,D,C,B,A
);
always @(posedge clk or negedge rst) //产生标志信号
begin
if(!rst)
flag = 'b0;
else if(!key)
begin
flag = ~flag;
end
else
begin
flag = flag;
end
end
always @(posedge clk1h or negedge rst) //产生60进制计数器
begin //数码管显示要按照十进制的方式显示
if(!rst)
begin
cnt <= 'h00; //复位初值显示00
cnt1<='b0;
end
else if(flag)
begin
G_LED2<='b0;
R_LED1<='b1;
if(cnt[:] == 'd9) //个位满九?
begin
cnt[:] <= 'd0; //个位清零
if(cnt[:] == 'd5 ) //十位满五?
begin
cnt[:] <= 'd0; //十位清零
cnt1<=cnt1+;
end
else
begin
cnt[:] <= cnt[:] + 'b1; //十位加一
cnt1<=cnt1;
end
end
else cnt[:] <= cnt[:] + 'b1; //个位加一
end
else
begin
cnt <= cnt;
G_LED2<='b1;
R_LED1<='b0;
end
end
always@(posedge clk)
if(cnt1=='b0)
LED[:]<='b11111111;
else if(cnt1=='b0001)
LED[:]<='b11111110;
else if(cnt1=='b0010)
LED[:]<='b11111100;
else if(cnt1=='b0011)
LED[:]<='b11111000;
else if(cnt1=='b0100)
LED[:]<='b11110000;
else if(cnt1=='b0101)
LED[:]<='b11100000;
else if(cnt1=='b0110)
LED[:]<='b11000000;
else if(cnt1<='b0111)
LED[:]<='b10000000;
else if(cnt1<='b1000)
LED[:]<='b00000000;
endmodule module divide #
( //parameter是verilog里参数定义
parameter WIDTH = , //计数器的位数,计数的最大值为 2**(WIDTH-1)
parameter N = 12_000_000 //分频系数,请确保 N<2**(WIDTH-1),否则计数会溢出
)
(
input clk, //clk频率为12MHz
input rst_n, //复位信号,低有效,
output clkout //输出信号,可以连接到LED观察分频的时钟
);
reg [WIDTH-:] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟
//上升沿触发时计数器的控制
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_p <= 'b0;
else if(cnt_p == (N-))
cnt_p <= 'b0;
else
cnt_p <= cnt_p + 'b1; //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器
end
//上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_p <= 'b0;
else if(cnt_p < (N>>)) //N>>1表示右移一位,相当于除以2取商
clk_p <= 'b0;
else
clk_p <= 'b1; //得到的分频时钟正周期比负周期多一个clk时钟
end
//下降沿触发时计数器的控制
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_n <= 'b0;
else if(cnt_n == (N-))
cnt_n <= 'b0;
else
cnt_n <= cnt_n + 'b1;
end
//下降沿触发的分频时钟输出,和clk_p相差半个clk时钟
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
clk_n <= 'b0;
else if(cnt_n < (N>>))
clk_n <= 'b0;
else
clk_n <= 'b1; //得到的分频时钟正周期比负周期多一个clk时钟
end
wire clk1 = clk; //当N=1时,直接输出clk
wire clk2 = clk_p; //当N为偶数也就是N的最低位为0,N[0]=0,输出clk_p
wire clk3 = clk_p & clk_n; //当N为奇数也就是N最低位为1,N[0]=1,输出clk_p&clk_n。正周期多所以是相与
assign clkout = (N==)? clk1:(N[]? clk3:clk2); //条件判断表达式
endmodule module segment
(
input wire [:] seg_data_1, //四位输入数据信号
input wire [:] seg_data_2, //四位输入数据信号
output wire [:] segment_led_1, //数码管1,MSB~LSB = SEG,DP,G,F,E,D,C,B,A
output wire [:] segment_led_2 //数码管2,MSB~LSB = SEG,DP,G,F,E,D,C,B,A
);
reg[:] seg [:]; //存储7段数码管译码数据
initial
begin
seg[] = 'h3f; // 0
seg[] = 'h06; // 1
seg[] = 'h5b; // 2
seg[] = 'h4f; // 3
seg[] = 'h66; // 4
seg[] = 'h6d; // 5
seg[] = 'h7d; // 6
seg[] = 'h07; // 7
seg[] = 'h7f; // 8
seg[] = 'h6f; // 9
seg[]= 'h77; // A
seg[]= 'h7C; // b
seg[]= 'h39; // C
seg[]= 'h5e; // d
seg[]= 'h79; // E
seg[]= 'h71; // F
end
assign segment_led_1 = seg[seg_data_1];
assign segment_led_2 = seg[seg_data_2];
endmodule

6.总结

到这里整个秒表就完成啦。最后再次向读者们道歉,不能贴上实验效果图了。身边有实验板的读者们可以将代码烧录进板子观察现象。本人编程水平、时间有限,这篇文章到这里就要结束啦,欢迎广大读者评论留言,更欢迎大家指出本人的不足,希望能通过交流自身得到提高。最后感谢大家的耐心阅读!

[FPGA]Verilog 60s秒表计时器(最大可计时间长达9min)的更多相关文章

  1. [FPGA]Verilog实现可自定义的倒计时器(24秒为例)

    目录 想说的话... 样例_边沿检测计数器 代码讲解 仿真演示 拓展_自定义倒计时数和倒计时间隔 代码讲解 仿真演示 总结 实例_24秒倒计时器 想说的话... 本次实现的是一个24秒倒计时器,功能顾 ...

  2. verilog实现毫秒计时器

    verilog实现毫秒计时器 整体电路图 实验状态图 Stop代表没有计时,Start代表开始计时,Inc代表计时器加1,Trap代表inc按钮按下去时候的消抖状态. 状态编码表 实验设计思路 时钟分 ...

  3. [FPGA] Verilog 燃气灶控制器的设计与实现

    燃气灶控制器的设计与实现 一.引述 本次实验所用可编程器件型号为MAXII EPM1270T144C5(其引脚表见本人另一博文:可编程实验板EPM1270T144C5使用说明),通过可编程实验板实现一 ...

  4. FPGA Verilog HDL 系列实例--------步进电机驱动控制

    [连载] FPGA Verilog HDL 系列实例 Verilog HDL 之 步进电机驱动控制 步进电机的用途还是非常广泛的,目前打印机,绘图仪,机器人等等设备都以步进电机为动力核心.那么,下面我 ...

  5. 秒表计时器以及Stopwatch

    Stopwatch:秒表计时器,用来记录程序的运行时间,通常用来测试代码在时间上的执行效率.(需要引用:System.Diagnostics.) Stopwatch sw=new Stopwatch( ...

  6. verilog实验2:基于FPGA的59秒计时器设计

    一.实验任务 利用四个数码管显示59秒计时器. 二.代码实现 将开发板的48M晶振分频出1M,然后计数器累加,将计数器结果显示在数码管上.低位逢十进一,第二位逢五进一,依次构成59秒计时器. 部分代码 ...

  7. 基于FPGA的数字秒表(数码管显示模块和按键消抖)实现

    本文主要是学习按键消抖和数码管动态显示,秒表显示什么的,个人认为,拿FPGA做秒表真是嫌钱多. 感谢 感谢学校和至芯科技,笔者专业最近去北京至芯科技培训交流了一周.老师的经验还是可以的,优化了自己的代 ...

  8. xilinx 赛灵思fpga verilog hdl 教程

    http://www.eefocus.com/article/08-03/37231s.html http://wenku.baidu.com/link?url=5mdkMmm4BGGi7gRdgSk ...

  9. [FPGA]Verilog实现JK触发器组成的8421BCD码十进制计数器

    目录 概述 电路分析 代码实现 参考文献 概述 本文以异步时序计数器为例,用Verilog实现以\(JK\)触发器组成的8421BCD码十进制异步计数器,并用ModelSim软件进行仿真验证. 电路分 ...

随机推荐

  1. 关于设备与canvas画不出来的解决办法

    连续四天解决一个在三星手机上面画canvas的倒计时饼图不出来的问题,困惑了很久,用了很多办法,甚至重写了那个方法,还是没有解决,大神给的思路是给父级加 "overflow: visible ...

  2. Java虚拟机-字节码指令

    目录 字节码指令 字节码与数据类型 加载和存储指令 运算指令 类型转换指令 对象创建与访问指令 操作数栈管理指令 控制转移指令 方法调用和返回指令 异常处理指令 同步指令 字节码指令 Java虚拟机的 ...

  3. pat 1116 Come on! Let's C(20 分)

    1116 Come on! Let's C(20 分) "Let's C" is a popular and fun programming contest hosted by t ...

  4. Easy 2048 Again(状压dp)

    题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3802 题意: 从数列A中, 删除若干个数(可以0个), 是删除 ...

  5. usaco training <1.2 Your Ride Is Here>

    题面 Your Ride Is Here It is a well-known fact that behind every good comet is a UFO. These UFOs often ...

  6. window系统下删除多余的引导

    window系统下删除多余的引导 1.首先第一步进入EFI分区删除多余系统引导,只留下需要的引导 如何进入EFI分区 a)win 搜索框输入cm, 右键以管理员运行命令行 b)输入命令 diskpar ...

  7. Obtaining the backtrace - libunwind

    Sometimes when working on a large project, I find it useful to figure out all the places from which ...

  8. vue 安装指令

    vue init webpack 项目名 创建项目cd 项目名 打开项目 npm install vuex --save 安装vuex在一个模块化的打包系统中,您必须显式地通过 Vue.use() 来 ...

  9. 使用scrapy-redis搭建分布式爬虫环境

    scrapy-redis简介 scrapy-redis是scrapy框架基于redis数据库的组件,用于scrapy项目的分布式开发和部署. 有如下特征:  分布式爬取 您可以启动多个spider工 ...

  10. Mac OS 终端利器 iTerm2(怕以后找不到,自存自用)

    之前一直使用 Mac OS 自带的终端,用起来虽然有些不太方便,但总体来说还是可以接受的,是有想换个终端的想法,然后今天偶然看到一个终端利器 iTerm2,发现真的很强大,也非常的好用,按照网上配置了 ...