FPGA巩固基础:秒表的设计

news2024/12/22 18:21:38

设计要求:

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     
);
    // localparam
    localparam      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 signal
    wire                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) begin
        if(~sys_rst_n) 
            state_c <= IDLE ;
        else 
            state_c <= state_n ;
    end
    // reg     [2:0]       state_n     ;
    always @(*) begin
        if(~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 ;
        endcase
    end

    assign  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) begin
        if(~sys_rst_n) 
            cnt_1ms <= 16'd0 ;
        else if(add_cnt_1ms) begin
            if(end_cnt_1ms)
                cnt_1ms <= 16'd0 ;
            else 
                cnt_1ms <= cnt_1ms + 1'b1 ;
        end
        else 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) begin
        if(~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 ;
        else
            po_data_one <= po_data_one ;
    end
    // output      reg     [3:0]       po_data_two     ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~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 ;
        else
            po_data_two <= po_data_two ;
    end
    // output      reg     [3:0]       po_data_thr     ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~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 ;
        else
            po_data_thr <= po_data_thr ;
    end
    // output      reg     [3:0]       po_data_fou     , 显示秒的个位 0 ~ 9
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~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 ;
        else
            po_data_fou <= po_data_fou ;
    end
    // output      reg     [3:0]       po_data_fiv     , 显示秒的十位 0 ~ 5
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~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 ;
        else
            po_data_fiv <= po_data_fiv ;
    end
    // output      reg     [3:0]       po_data_six     ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~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 ;
        else
            po_data_six <= po_data_six ;
    end
    // reg minute_flag
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~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 ;
    end
    
endmodule

状态机设计:

当复位按键按下,现态与次态都需要回到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        ; // 移位寄存器的移位时间,计数器。
    // wire
    wire                    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) begin
        if(~sys_rst_n) 
            cnt_time <= 32'd0 ;
        else if(add_cnt_time) begin
            if(end_cnt_time)
                cnt_time <= 32'd0 ;
            else 
                cnt_time <= cnt_time + 1'b1 ;
        end
        else 
            cnt_time <= 32'd0 ; // 注意这里,是保持还是归零。
    end
    // reg         dot ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~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) begin
        if(~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) begin
        if(~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  }        ;
        endcase
    end

endmodule

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

减少重复劳动。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1313574.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android BluetoothAdapter 使用(二)

Android BluetoothAdapter 使用(二) 本篇文章主要讲下蓝牙设备的配对. 1: 蓝牙设备列表展示 下 面是蓝牙设备adapter的代码: package com.test.bluetooth;import android.bluetooth.BluetoothDevice; import android.content.Context; import android.view.LayoutInflater;…

Netty—NIO万字详解

文章目录 NIO基本介绍同步、异步、阻塞、非阻塞IO的分类NIO 和 BIO 的比较NIO 三大核心原理示意图NIO的多路复用说明 核心一&#xff1a;缓存区 (Buffer)Buffer类及其子类Buffer缓冲区的分类MappedByteBuffer类说明&#xff1a; 核心二&#xff1a;通道 (Channel)Channel类及其…

解决vue3 动态引入报错问题

之前这样写的&#xff0c;能使用&#xff0c;但是有警告 警告&#xff0c;查了下&#xff0c;是动态引入的问题&#xff0c;看到说要用glob 然后再我的基础上&#xff0c;稍微 改了下&#xff0c;就可以了&#xff1a; 最后打印了下&#xff0c;modules[../../components/flowc…

Javascript高频面试题

系列文章目录 文章目录 系列文章目录前言1.JavaScript常见数据类型null 和 undefind区别symbol&#xff08;ES6新增&#xff09;、bigInt&#xff08;ES10新增&#xff09; 2.JavaScript判断数据类型的方式3. 和 区别&#xff0c;分别在什么情况使用&#xff1f;4.变量声明 va…

c#winform学生信息管理系统sqlserver

vs2022开发 数据库sqlserver和c#winform结合设计的学生信息管理系统 一&#xff0e;需求分析 1.1设计可视化界面&#xff0c;具有身份验证功能&#xff0c;需要登录时输入账号及密码。 1.2学生用户能够注册自己的账号&#xff0c;添加自己的基本注册信息&#xff1a;学号、密…

JAVA的关键字、标识符和命名规范

目录 一、Java 二、关键字 三、标识符 四、命名规范 一、Java Java是一种面向对象的高级编程语言&#xff0c;最初由Sun Microsystems公司于1995年发布。它的特点是可移植性强、可靠性高、安全性好以及简单易学。Java是一种跨平台的语言&#xff0c;它可以在不同的操作系统…

在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)

背景 在项目过程中&#xff0c;有时候你需要调用非C#编写的DLL文件&#xff0c;尤其在使用一些第三方通讯组件的时候&#xff0c;通过C#来开发应用软件时&#xff0c;就需要利用DllImport特性进行方法调用。本篇文章将引导你快速理解这个调用的过程。 步骤 1. 创建一个CSharp…

java web系统的常见安全问题

一、背景 java开发的系统在发布到互联网后都需要进行安全扫描&#xff0c;本文主要总结开发web系统需要注意的与系统安全相关的问题。因为在做需求开发时&#xff0c;很少产品会将系统安全的因素考虑在内&#xff0c;总觉得实现个需求很简单&#xff0c;就是一些页面&#xff0…

Leetcode—131.分割回文串【中等】

2023每日刷题&#xff08;五十九&#xff09; Leetcode—131.分割回文串 算法思想 实现代码 class Solution { public:bool isPalindrome(string s, int left, int right) {while(left < right) {if(s[left] ! s[right--]) {return false;}}return true;}vector<vector…

云服务配置docker镜像容器以及常用操作命令

首先通过ssh进入云服务器。如何ssh进入云服务器。 简单讲解一下docker中镜像和容器&#xff0c;打个比方&#xff0c;镜像相当于印钱的那个模板&#xff0c;容器相当于从模板上拓下来的钱&#xff0c;不同的模板可以印出不同的钱。但容器被修改后也可以变成新的镜像&#xff0…

flink yarn-session 启动失败retrying connect to server 0.0.0.0/0.0.0.0:8032

原因分析&#xff0c;启动yarn-session.sh&#xff0c;会向resourcemanager的端口8032发起请求&#xff1a; 但是一直无法请求到8032端口&#xff0c;触发重试机制会不断尝试 备注&#xff1a;此问题出现时&#xff0c;我的环境ambari部署的HA 高可用hadoop&#xff0c;三个节点…

Amortized Bootstrapping of LWE:使用 BFV 打包处理

参考文献&#xff1a; [AP13] Alperin-Sheriff J, Peikert C. Practical bootstrapping in quasilinear time[C]//Annual Cryptology Conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 2013: 1-20.[MS18] Micciancio D, Sorrell J. Ring packing and amortized F…

电源适配器老化测试方法分享 电源测试系统助力老化测试

电源适配器老化测试是指对适配器进行高负荷、长时间的运行测试&#xff0c;从而评估电源适配器的性能、稳定性和可靠性。通过老化测试可以检测电源适配器长时间的使用情况&#xff0c;从而指导适配器的设计和研发&#xff0c;提高电源适配器的质量。由于老化测试要求长时间运行…

DVGO 代码阅读

BBx 的大小范围是 根据 相机的 位姿来构建的&#xff0c;会刚好 Cover 相机的移动范围&#xff0c;相当于 StreetSurf 里面的 close-range 的部分&#xff0c;代码在compute_bbox_by_cam_frustrm_unbounded 这个函数里面&#xff1a; xyz_min, xyz_max _compute_bbox_by_cam_f…

如何为您的企业制定客户服务政策(7个步骤+免费模板)

当企业制定客户服务政策时&#xff0c;其核心目标是调整客户期望&#xff0c;并建立精确的程序和政策来促进这一目标。这些书面政策作为员工指南&#xff0c;概述了公司的期望&#xff0c;并为处理各种情况提供了框架。通过全面了解客户服务政策并掌握创建有效政策的方法&#…

LVS 负载均衡群集 NAT

目录 企业群集应用概述 群集的含义 企业群集分类 根据群集所针对的目标差异&#xff0c;可分为三种类型 负载均衡群集(Load Balance Cluster) 高可用群集(High Availability Ciuster) 高性能运算群集 (High Performance Computer Cluster) 负载均衡群集架构 负载均衡的…

炒股怎么做杠杆?安全正规的融资融券了解一下!

加杠杆炒股是指放大投资资金进行股票交易&#xff0c;比如自有资金100万&#xff0c;向证券公司融资100万&#xff0c;那么投资者炒股的本金就有200万。当股市行情好的时候可以放大我们的收益&#xff01; 目前我国股票加杠杆通过融资融券来实现&#xff0c;这个是唯一安全正规…

协作办公原来如此简单?详解 ONLYOFFICE 协作空间 2.0 更新

协作办公原来如此简单&#xff1f;详解 ONLYOFFICE 协作空间 2.0 更新 上周&#xff0c;ONLYOFFICE 的协作空间推出升级版 2.0 版本了&#xff1a; ONLYOFFICE 协作空间 2.0 现已发布&#xff1a;新增公共房间、插件、重新分配数据、RTL 界面等功能 ONLYOFFICE 协作空间是去…

chromium硬件加速播放video观察(intel630和Mali G610)

Intel UHD Graphics 630 Intel(R) UHD Graphics 630驱动程序版本: 27.20.100.8935 驱动程序日期: 2020/10/28 DirectX 版本: 12 (FL 12.1) 物理位置&#xff1a; PCI 总线 0、设备 2、功能 0利用率 2% 专用 GPU 内存 共享 GPU 内存 0.3/7.9 GB GPU 内存…

JDK21+HADOOP3.2.2+Windows安装步骤

哈哈哈 最近转战大数据这块了&#xff0c;分享一下hadoop3.2.2的安装步骤 借鉴了不少大佬的文章&#xff0c;如有雷同&#xff0c;都是大佬们的 1.JDK安装 我选择的是JDK21 以下是下载网址和截图&#xff0c;这个没有太多的&#xff0c;一般下载最新的就可以 JDK: Java Down…