[FPGA]Verilog 60s秒表计时器(最大可计时间长达9min)
[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)的更多相关文章
- [FPGA]Verilog实现可自定义的倒计时器(24秒为例)
目录 想说的话... 样例_边沿检测计数器 代码讲解 仿真演示 拓展_自定义倒计时数和倒计时间隔 代码讲解 仿真演示 总结 实例_24秒倒计时器 想说的话... 本次实现的是一个24秒倒计时器,功能顾 ...
- verilog实现毫秒计时器
verilog实现毫秒计时器 整体电路图 实验状态图 Stop代表没有计时,Start代表开始计时,Inc代表计时器加1,Trap代表inc按钮按下去时候的消抖状态. 状态编码表 实验设计思路 时钟分 ...
- [FPGA] Verilog 燃气灶控制器的设计与实现
燃气灶控制器的设计与实现 一.引述 本次实验所用可编程器件型号为MAXII EPM1270T144C5(其引脚表见本人另一博文:可编程实验板EPM1270T144C5使用说明),通过可编程实验板实现一 ...
- FPGA Verilog HDL 系列实例--------步进电机驱动控制
[连载] FPGA Verilog HDL 系列实例 Verilog HDL 之 步进电机驱动控制 步进电机的用途还是非常广泛的,目前打印机,绘图仪,机器人等等设备都以步进电机为动力核心.那么,下面我 ...
- 秒表计时器以及Stopwatch
Stopwatch:秒表计时器,用来记录程序的运行时间,通常用来测试代码在时间上的执行效率.(需要引用:System.Diagnostics.) Stopwatch sw=new Stopwatch( ...
- verilog实验2:基于FPGA的59秒计时器设计
一.实验任务 利用四个数码管显示59秒计时器. 二.代码实现 将开发板的48M晶振分频出1M,然后计数器累加,将计数器结果显示在数码管上.低位逢十进一,第二位逢五进一,依次构成59秒计时器. 部分代码 ...
- 基于FPGA的数字秒表(数码管显示模块和按键消抖)实现
本文主要是学习按键消抖和数码管动态显示,秒表显示什么的,个人认为,拿FPGA做秒表真是嫌钱多. 感谢 感谢学校和至芯科技,笔者专业最近去北京至芯科技培训交流了一周.老师的经验还是可以的,优化了自己的代 ...
- xilinx 赛灵思fpga verilog hdl 教程
http://www.eefocus.com/article/08-03/37231s.html http://wenku.baidu.com/link?url=5mdkMmm4BGGi7gRdgSk ...
- [FPGA]Verilog实现JK触发器组成的8421BCD码十进制计数器
目录 概述 电路分析 代码实现 参考文献 概述 本文以异步时序计数器为例,用Verilog实现以\(JK\)触发器组成的8421BCD码十进制异步计数器,并用ModelSim软件进行仿真验证. 电路分 ...
随机推荐
- 深入理解计算机系统 第二章 信息的表示和处理 Part1 第二遍
<深入理解计算机系统> 第三版 第二遍读这本书,每周花两到三小时时间,能读多少读多少(这次看了 22 ~ 28 页) 第一遍对应笔记链接 https://www.cnblogs.com/s ...
- 【微信小程序】踩坑指南(持续更新)
前言 说明: 基于mpvue框架:mpvue官方文档 语法同vue框架:vue官方文档 小程序中会有一些坑点,这里会就工作中遇到的坑一一列举出来 无说明时请直接看代码注释 v-show无法使用在小程序 ...
- Linux命令大全(个人整理,如不全面望谅解)
系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...
- Python 常用模块系列学习(3)--configparser module
configpaser 模块----用于生成和修改常见配置文档 1. config 对象的创建: import configparser #导入模块 config = configparser.Con ...
- 力扣(LeetCode)寻找数组的中心索引 个人题解
给定一个整数类型的数组 nums,请编写一个能够返回数组“中心索引”的方法. 我们是这样定义数组中心索引的:数组中心索引的左侧所有元素相加的和等于右侧所有元素相加的和. 如果数组不存在中心索引,那么我 ...
- Elasticsearch系列---常见搜索方式与聚合分析
概要 本篇主要介绍常见的6种搜索方式.聚合分析语法,基本是上机实战,可以和关系型数据库作对比,如果之前了解关系型数据库,那本篇只需要了解搜索和聚合的语法规则就可以了. 搜索响应报文 以上篇建立的mus ...
- Pytorch文本分类(imdb数据集),含DataLoader数据加载,最优模型保存
用pytorch进行文本分类,数据集为keras内置的imdb影评数据(二分类),代码包含六个部分(详见代码) 使用环境: pytorch:1.1.0 cuda:10.0 gpu:RTX2070 (1 ...
- 【Luogu P3379】LCA问题的倍增解法
Luogu P3379 题意:对于两个节点,寻找他们的最近公共祖先. 一个显而易见的解法是对于每一个节点我们都往上遍历一遍,记录下它每一个祖先,然后再从另一个节点出发,一步一步往上走,找到以前记录过第 ...
- 【NHOI2018】跳伞登山赛
[题目描述] 某山区有高高低低的 n 个山峰,根据海拔高度的不同,这些山峰由低到高进行了 1 到 n 编号.有 m 条只能单向通行的羊肠小道连接这些山峰.现在,这里要举行一场跳伞登山赛,选手们伞降到某 ...
- 模型量化原理及tflite示例
模型量化 什么是量化 模型的weights数据一般是float32的,量化即将他们转换为int8的.当然其实量化有很多种,主流是int8/fp16量化,其他的还有比如 二进制神经网络:在运行时具有二进 ...