FPGA巩固基础:秒表的设计

news/2025/1/12 19:44:06/

设计要求:

6位8段数码管,低三位显示毫秒计数,最高位显示分钟,其余两位显示秒计数。

开始案件与暂停按键,复位按键直接全部归零。

扩展部分:每计满一次,led移位一次。

框图设计:

 

思路讲解:

首先按键信号经过消抖再用,然后把产生的标志信号传给控制模块,由于控制逻辑很简单就把这部分控制逻辑放进“数据产生模块中了”;

然后把数码管与led接口模块interface放进去。

按理来讲,应该重新定义个接口模块再把led与nixie放进去,比较规范。

模块讲解:

值得一提就是数据产生模块与数码管接口模块:

数据产生模块:

 其实输出端口是几个级联得计数器。

代码奉上:

`include "para.v"
module data_gen (input		wire				sys_clk         ,input		wire				sys_rst_n       ,input       wire                start_flag      ,input       wire                stop_flag       ,output      reg     [3:0]       po_data_one     ,output      reg     [3:0]       po_data_two     ,output      reg     [3:0]       po_data_thr     ,output      reg     [3:0]       po_data_fou     ,output      reg     [3:0]       po_data_fiv     ,output      reg     [3:0]       po_data_six     ,output      reg                 minute_flag     
);// localparamlocalparam      IDLE    = 3'b001 ,WORKING = 3'b010 ,STOP    = 3'b100 ;// reg signal reg     [15:0]      cnt_1ms     ;reg     [2:0]       state_c     ;reg     [2:0]       state_n     ;// wire signalwire                add_cnt_1ms     ;wire                end_cnt_1ms     ;wire                IDLEtoWORKING   ;wire                WORKINGtoSTOP   ;wire                STOPtoWORKING   ;   
/******************************************************************************************
********************************************main code**************************************
*******************************************************************************************/// // reg signal // reg     [2:0]       state_c     ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) state_c <= IDLE ;else state_c <= state_n ;end// reg     [2:0]       state_n     ;always @(*) beginif(~sys_rst_n)state_n = IDLE ;else case(state_c)IDLE   :    if(IDLEtoWORKING)state_n = WORKING ;else state_n = IDLE ;WORKING:    if(WORKINGtoSTOP)state_n = STOP ;else state_n = WORKING ;STOP   :    if(STOPtoWORKING)state_n = WORKING ;else state_n = STOP ;default:        state_n = IDLE ;endcaseendassign  IDLEtoWORKING   = (state_c == IDLE      ) && (start_flag) ;assign  WORKINGtoSTOP   = (state_c == WORKING   ) && (stop_flag ) ;assign  STOPtoWORKING   = (state_c == STOP      ) && (start_flag) ;// reg     [15:0]      cnt_1ms     ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) cnt_1ms <= 16'd0 ;else if(add_cnt_1ms) beginif(end_cnt_1ms)cnt_1ms <= 16'd0 ;else cnt_1ms <= cnt_1ms + 1'b1 ;endelse if(state_c == IDLE) cnt_1ms <= 16'd0 ; else cnt_1ms <= cnt_1ms ;// 注意这里,是保持还是归零。end// wire                add_cnt_1ms ;assign  add_cnt_1ms = (state_c == WORKING   ) ;// wire                end_cnt_1ms ;assign  end_cnt_1ms = add_cnt_1ms && (cnt_1ms == `MAX_CNT_1MS - 1) ;// output signal description// output		reg     [3:0]       po_data_one    ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) po_data_one <= 4'd0 ;else if(end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1)po_data_one <= 4'd0 ;else if(end_cnt_1ms)po_data_one <= po_data_one + 1'b1 ;elsepo_data_one <= po_data_one ;end// output      reg     [3:0]       po_data_two     ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) po_data_two <= 4'd0 ;else if((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)po_data_two <= 4'd0 ;else if(end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1)po_data_two <= po_data_two + 1'b1 ;elsepo_data_two <= po_data_two ;end// output      reg     [3:0]       po_data_thr     ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) po_data_thr <= 4'd0 ;else if((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1))po_data_thr <= 4'd0 ;else if(((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1))po_data_thr <= po_data_thr + 1'b1 ;elsepo_data_thr <= po_data_thr ;end// output      reg     [3:0]       po_data_fou     , 显示秒的个位 0 ~ 9always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) po_data_fou <= 4'd0 ;else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1))po_data_fou <= 4'd0 ;else if((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1))po_data_fou <= po_data_fou + 1'b1 ;elsepo_data_fou <= po_data_fou ;end// output      reg     [3:0]       po_data_fiv     , 显示秒的十位 0 ~ 5always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) po_data_fiv <= 4'd0 ;else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5))po_data_fiv <= 4'd0 ;else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1))po_data_fiv <= po_data_fiv + 1'b1 ;elsepo_data_fiv <= po_data_fiv ;end// output      reg     [3:0]       po_data_six     ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) po_data_six <= 4'd0 ;else if((((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5)) && (po_data_six == `MAX_CNT_NUM - 1))po_data_six <= 4'd0 ;else if(((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5))po_data_six <= po_data_six + 1'b1 ;elsepo_data_six <= po_data_six ;end// reg minute_flagalways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) minute_flag <= 1'b0 ;else if((((((end_cnt_1ms && po_data_one == `MAX_CNT_NUM - 1) && po_data_two == `MAX_CNT_NUM - 1)) && (po_data_thr == `MAX_CNT_NUM - 1)) && (po_data_fou == `MAX_CNT_NUM - 1) && (po_data_fiv == `MAX_CNT_NUM - 5)) && (po_data_six == `MAX_CNT_NUM - 1))minute_flag <= 1'b1 ;else minute_flag <= 1'b0 ;endendmodule

状态机设计:

当复位按键按下,现态与次态都需要回到IDLE状态。
在代码层面,给state_n设置一个复位情况。

数码管模块: 

创新点,与以往不同的代码设计,这次用了“函数”,function。

代码奉上:

`include "para.v"
module nixie (input		wire				sys_clk         ,input		wire				sys_rst_n       ,input       wire     [3:0]      pi_data_one     ,input       wire     [3:0]      pi_data_two     ,input       wire     [3:0]      pi_data_thr     ,input       wire     [3:0]      pi_data_fou     ,input       wire     [3:0]      pi_data_fiv     ,input       wire     [3:0]      pi_data_six     ,output		reg     [5:0]       sel             , output		reg     [7:0]       dig              
);// reg reg                     dot             ; // 数码管上的小数点。reg     [31:0]          cnt_time        ; // 移位寄存器的移位时间,计数器。// wirewire                    add_cnt_time    ;      wire                    end_cnt_time    ;      
/******************************************************************************************
********************************************main code**************************************
*******************************************************************************************/   // reg signal description // reg     [31:0]          cnt_time    ; // 移位寄存器的移位时间。always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) cnt_time <= 32'd0 ;else if(add_cnt_time) beginif(end_cnt_time)cnt_time <= 32'd0 ;else cnt_time <= cnt_time + 1'b1 ;endelse cnt_time <= 32'd0 ; // 注意这里,是保持还是归零。end// reg         dot ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) dot <= 1'b1 ;else dot <= 1'b1 ;end// wire signal description assign  add_cnt_time = 1'b1 ;assign  end_cnt_time = add_cnt_time && (cnt_time == `MAX_CNT_TIES - 1) ;// task// task       nixie_dig ;//     input   [3:0]   data_num    ;//     output  [7:0]   po_dig      ;//     case (data_num)//     0      :    po_dig  = {dot, `ZERO  } ;//     1      :    po_dig  = {dot, `ONE   } ;//     2      :    po_dig  = {dot, `TWO   } ;//     3      :    po_dig  = {dot, `THREE } ;//     4      :    po_dig  = {dot, `FOUR  } ;//     5      :    po_dig  = {dot, `FIVE  } ;//     6      :    po_dig  = {dot, `SIX   } ;//     7      :    po_dig  = {dot, `SEVEN } ;//     8      :    po_dig  = {dot, `EIGHT } ;//     9      :    po_dig  = {dot, `NINE  } ;//     default:    po_dig  = 8'd0   ;//     endcase// endtask// function
function [6:0]  dig_num;input   [3:0]   data_in ;case (data_in)0      :    dig_num  = `ZERO  ;1      :    dig_num  = `ONE   ;2      :    dig_num  = `TWO   ;3      :    dig_num  = `THREE ;4      :    dig_num  = `FOUR  ;5      :    dig_num  = `FIVE  ;6      :    dig_num  = `SIX   ;7      :    dig_num  = `SEVEN ;8      :    dig_num  = `EIGHT ;9      :    dig_num  = `NINE  ;default:    dig_num  = 7'd0   ;endcase
endfunction// Output signal description// output		reg     [5:0]       sel             , always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) sel <= 6'b111_110 ;else if(end_cnt_time)sel <= {sel[4:0],sel[5]} ;else sel <= sel ;end// output		reg     [7:0]       dig  always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) dig <= 8'd0 ;else case (sel)6'b111_110: dig <= {dot, dig_num(pi_data_one)} ;6'b111_101: dig <= {dot, dig_num(pi_data_two)} ;6'b111_011: dig <= {dot, dig_num(pi_data_thr)} ;6'b110_111: dig <= {1'b0, dig_num(pi_data_fou)} ;6'b101_111: dig <= {dot, dig_num(pi_data_fiv)} ;6'b011_111: dig <= {1'b0, dig_num(pi_data_six)} ;default   : dig <= {dot, `SIX  }        ;endcaseendendmodule

函数或者任务的使用,是使得代码写起来更方便,设计起来更节省时间。

减少重复劳动。

要灵活使用。多观察,多分析,多获取信息。找到相关性,相似性。


http://www.ppmy.cn/news/1270796.html

相关文章

【反射】Java小白也能手写的简易版框架

文章目录 1. 概要2. 反射的基本使用2.1 获取类的字节码2.2 反射获取构造器2.3 反射获取构造器的作用2.4 反射获取成员变量及其使用2.5 反射获取成员方法 3. 基于反射手写简易版框架 1. 概要 在日常实习开发中&#xff0c;反射基本其实是用不太到的。但是如果你想学习有些框架的…

第P7周:咖啡豆识别(VGG-16复现)

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/rbOOmire8OocQ90QM78DRA) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https://mtyjkh.blog.csdn.net/)** 一、前期工作 import …

明明随机数

明明想在学校中请一些同学一起做一项问卷调查&#xff0c;为了实验的客观性&#xff0c;他先用计算机生成了N个1到1000之间的随机整数(N<100)&#xff0c;对于其中重复的数字&#xff0c;只保留一个&#xff0c;把其余相同的数去掉&#xff0c;不同的数对应着不同的学生的学…

一个简单的cmake模板(C++)

链接&#xff1a;小黑屋1024 / Python GitCode #对cmake版本的要求&#xff0c;此处不低于3.16 cmake_minimum_required(VERSION 3.16)#项目名称&#xff1a;此处为test project(test)#设置编译生成产物输出路径 ##可执行文件exe SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURC…

C#科学绘图之scottPlot绘制多个图像

文章目录 示例移除图像图例信号图 scott系列&#xff1a;绘图初步 示例 从名字就能看出&#xff0c;ScottPlot的绘图函数AddScatter的作用是为图窗添加数据点&#xff0c;换言之&#xff0c;每调用一次AddScatter&#xff0c;就可以在图窗中添加一组图像。下面添加两个按钮&a…

AI:ElasticSearch

ElasticSearch是一款开源的分布式搜索引擎和数据分析引擎&#xff0c;主要用于处理海量数据并提供近实时的搜索和分析功能。它具有全文检索、结构化检索和数据分析等特点&#xff0c;能够满足各种复杂的搜索需求。ElasticSearch使用Java编写&#xff0c;可以运行在多个服务器上…

线性代数运算方法总结

线性方程组的行列式解法&#xff08;克拉默法则&#xff09; 首先写出方程的系数行列式&#xff0c;第一列x1第二列x2以此类推&#xff0c;然后用每个方程式的结果分别代替第一列到第列&#xff0c;得到每个未知数对应的代数行列式&#xff0c;方程的解为代数行列式比系数行列…

docker整体环境转移

最近配了个docker&#xff0c;配完才发现&#xff0c;有点小G&#xff0c;还得自己安装cuda&#xff0c;有点麻烦&#xff0c;如果选择重新在新的cuda镜像上安装&#xff0c;也不轻松&#xff0c;所以找了下资料&#xff0c;搞出来了docker整体转移 首先介绍一个命令 docker c…