首页 > 其他分享 >基于EP4CE6F17C8的FPGA双数码管六十进制秒计数实例

基于EP4CE6F17C8的FPGA双数码管六十进制秒计数实例

时间:2024-03-25 23:44:55浏览次数:26  
标签:count FPGA 计数 EP4CE6F17C8 seg 数码管 模块

一、电路模块

本例的电路模块与“基于EP4CE6F17C8的FPGA数码管动态显示实例”中的完全一样,此处就不再给出了。

二、实验代码

本例实现2个数码管循环显示00~59,显示间隔为1秒,代码使用Verilog编写,采用例化的形式,共有三个文件。

先编写数码管实现显示字形解码的程序,模块名称为seg_decode,文件名称为seg_decode.v,代码如下。

module seg_decode(
    input[3:0]  data,                //显示的字形,可显示0~9十个字形,所以需要4位
    output reg[7:0] seg              //字形编码,包含小数点,共8位
);

always@(*)                           //敏感信号为所有输入量
begin
    case(data)
        4'd0:seg <= 8'b1100_0000;    //字形0的编码
        4'd1:seg <= 8'b1111_1001;    //字形1的编码
        4'd2:seg <= 8'b1010_0100;    //字形2的编码
        4'd3:seg <= 8'b1011_0000;    //字形3的编码
        4'd4:seg <= 8'b1001_1001;    //字形4的编码
        4'd5:seg <= 8'b1001_0010;    //字形5的编码
        4'd6:seg <= 8'b1000_0010;    //字形6的编码
        4'd7:seg <= 8'b1111_1000;    //字形7的编码
        4'd8:seg <= 8'b1000_0000;    //字形8的编码
        4'd9:seg <= 8'b1001_0000;    //字形9的编码
        default:seg <= 7'b111_1111;  //默认不显示
    endcase
end
endmodule

接下来编写秒计数程序,共有两个模块,名称分别为count_m10和count_m6。先看count_m10的模块,文件名称为count_m10.v,代码如下。

module count_m10(
      input          clk,                    //板载50HMz系统时钟
      input          rst_n,                  //复位按键
      input          en,                     //计数使能位  
      output reg[3:0]data,                   //计数值,从0~9共10位,所以用4位
      output reg     t                       //进位位
);

always@(posedge clk or negedge rst_n)        //敏感信号为时钟上沿或复位下沿 
begin
    if(rst_n==0)                             //低电平复位
    begin
        data <= 4'd0;                        //复位时计数值及进位位清零
        t <= 1'd0;
    end
    else if(en)                              //如果计数使能,则执行计数,否则保持上一次的值不变
    begin
        if(data==4'd9)                       //如果计数到达9时
        begin
            t<= 1'b1;                        //进位位置1
            data <= 4'd0;                    //计数值清零
        end
        else
        begin
            t <= 1'b0;                       //否则进位位清零,计数值加1
            data <= data + 4'd1;
        end
    end
    else                                     //如果计数不使能,进位位置0
        t <= 1'b0;
end
endmodule

再来看count_m6的模块,文件名称为count_m6.v,代码如下。

module count_m6(
      input          clk,                    //板载50HMz系统时钟
      input          rst_n,                  //复位按键
      input          en,                     //计数使能位  
      output reg[3:0]data,                   //计数值,从0~9共10位,所以用4位
      output reg     t                       //进位位
);

always@(posedge clk or negedge rst_n)        //敏感信号为时钟上沿或复位下沿 
begin
    if(rst_n==0)                             //低电平复位
    begin
        data <= 4'd0;                        //复位时计数值及进位位清零
        t <= 1'd0;
    end
    else if(en)                              //如果计数使能,则执行计数,否则保持上一次的值不变
    begin
        if(data==4'd5)                       //如果计数到达5时
        begin
            t<= 1'b1;                        //进位位置1
            data <= 4'd0;                    //计数值清零
        end
        else
        begin
            t <= 1'b0;                       //否则进位位清零,计数值加1
            data <= data + 4'd1;
        end
    end
    else                                     //如果计数不使能,进位位置0
        t <= 1'b0;
end
endmodule

最后编写数码管显示程序,并设置为顶层模块,模块名称为seg_count,文件名称为seg_count.v,代码如下。

module seg_count(
    input clk,                              //板载50HMz系统时钟
    input rst,                              //复位按键
    output reg[7:0] seg7,                   //段码端口
    output reg[1:0] bit                     //位选端口
);

reg [25:0] cnt;                            //定义26位时钟计数器
reg sec;                                   //定义秒信号

always@(posedge clk or negedge rst)        //敏感信号为时钟上沿或复位下沿
begin
    if(rst == 0)                           //低电平复位时秒计数清零
    begin
        sec <= 1'b0;
    end
    else if(cnt == 26'd49_999_999)         //时钟计数器到达1秒时
    begin
        cnt <= 26'd0;                      //时钟计数器清零
        sec <= 1'b1;                       //产生秒信号
    end
    else
    begin
        sec <= 1'b0;                       //否则秒信号清零
        cnt <= cnt + 26'd1;                //时钟计数器加1,即来一次时钟脉冲加一次
    end
end

wire t0;                                   //定义个位的进位位
wire [3:0] count_data0,count_data1;        //定义显示的值(个位、十位共两个)
wire [7:0] seg_0,seg_1;                    //定义显示字形码的值(个位、十位共两个)
//下面例化秒的个位计数单元(十进制)
count_m10 u0(.clk(clk), .rst_n(rst), .en(sec), .data(count_data0), .t(t0));
//下面例化秒的十位计数单元(六进制)
count_m6 u1(.clk(clk), .rst_n(rst), .en(t0), .data(count_data1), .t());
//下面例化秒的个位字形解码单元
seg_decode seg0(.data(count_data0), .seg(seg_0));
//下面例化秒的十位字形解码单元
seg_decode seg1(.data(count_data1), .seg(seg_1));

reg[17:0]     time_cnt;                    //定义20位时钟计数器
reg[3:0]      scan_sel;                    //定义扫描位置计数器
//3.3毫秒循环计数
always@(posedge clk or negedge rst)        //敏感信号为时钟上沿或复位下沿
begin
    if(rst == 1'b0)                        //低电平复位时计数器全部清零
    begin
        time_cnt <= 18'd0;
        scan_sel <= 4'd0;
    end
    else if(time_cnt >= 18'd166_666)       //时钟计数器到达3.3毫秒时
    begin
        time_cnt <= 18'd0;                 //时钟计数器清零
        if(scan_sel == 4'd3)               //如果扫描位置计数器已经到1则恢复0
            scan_sel <= 4'd0;
        else
            scan_sel <= scan_sel + 4'd1;   //否则扫描位置计数器加1,即每3.3ms加一次
    end
    else
        begin
            time_cnt <= time_cnt + 18'd1;  //否则时钟计数器加1,即来一次时钟脉冲加一次
        end
end

//数码管扫描显示
always@(posedge clk or negedge rst)        //敏感信号为时钟上沿或复位下沿
begin
    if(!rst)                               //低电平复位时数码管全灭
    begin
        bit <= 6'b111111;
        seg7 <= 8'hff;
    end
    else 
        case(scan_sel)
            4'd0:                          //数码管0显示秒的个位
            begin
                bit <= 6'b111110;
                seg7 <= seg_0;
            end
            4'd1:                          //数码管1显示秒的十位
            begin
                bit <= 6'b111101;
                seg7 <= seg_1;
            end
            default:                       //数码管全部熄灭
            begin
                bit <= 6'b111111;
                seg7 <= 8'hff;
            end
        endcase
end
endmodule

三、代码说明

1、要实现60进制的秒计数,可以拆分为个位上的10进制计数和十位上的6进制计数。个位通过计秒信号,直到9后,再计一次数清零,同时产生一个进位信号,十位通过计个位的进位信号,直到5后,再计一次数清零。如此就可实现从00~59的计数了。
2、count_m10模块主要负责10进制计数,在系统时钟的同步下,来一个en脉冲计一次数,计满后回零并产生进位信号t。计数的快慢取决于en端口输入的脉冲周期,产生的计数值则通过data端口向外输出,产生的进位信号通过t端口向外输出。
3、count_m6模块主要负责6进制计数,在系统时钟的同步下,来一个进位信号t计一次数,计满后回零并产生分的进位信号t。计数的快慢取决于个位进位信号t的周期,产生的计数值则通过data端口向外输出,产生的进位信号通过t端口向外输出。
4、seg_count模块为顶层模块,负责产生秒时钟信号(即en脉冲),通过例化10进制计数单元,把秒信号en传入,之后获得按秒变化的计数值count_data0。同时通过例化数码管字形解码单元,把计数值count_data0传入,之后获得个位上的字形编码seg7。同时,通过例化6进制计数单元,把个位上来的进位信号t传入,之后获得按十秒变化的计数值count_data1。同时通过例化数码管字形解码单元,把计数值count_data1传入,之后获得十位上的字形编码seg7。
5、数码管的扫描方式请参考“基于EP4CE6F17C8的FPGA数码管动态显示实例”一文,这里就不再赘述了。

四、实验步骤

FPGA开发的详细步骤请参见“基于EP4CE6F17C8的FPGA开发流程(以半加器为例)”一文,本例只对不同之处进行说明。

本例工程放在D:\EDA_FPGA\Exam_5文件夹下,工程名称为Exam_5。有四个模块文件,一个名称为seg_count.v,设置为顶层实体,另外三个名称分别为seg_decode.v、count_m10.v和count_m6.v,用于提供例化。其余步骤与“基于EP4CE6F17C8的FPGA开发流程”中的一样。

接下来看管脚约束,本例中只用到了两个数码管,一共有10个引脚,再加上时钟晶振和复位按钮,一共12个。具体的端口分配如下图所示。

对于未用到的引脚设置为三态输入方式,多用用途引脚全部做为普通I/O端口,电压设置为3.3-V LVTTL(与”基于EP4CE6F17C8的FPGA开发流程“中的一样)。需要注意,程序中的每个端口都必须为其分配管脚,如果系统中存在未分配的I/O,软件可能会进行随机分配,这将造成不可预料的后果,存在烧坏FPGA芯片的风险。

接下来对工程进行编译,编译完成后,可查看一下逻辑器件的消耗情况,如下图所示。

另外,还可以点击菜单Tools->Netlist Viewers->RTL Viewer,查看一下生成的RTL电路图,如下图所示。 

最后进行程序下载,并查看结果。下面是两位数码管动态显示秒计数图片的其中几张。

当按下复位键后,所有数码管熄灭,如下图所示。

标签:count,FPGA,计数,EP4CE6F17C8,seg,数码管,模块
From: https://www.cnblogs.com/fxzq/p/18094299

相关文章

  • FPGA图像处理——前置基础篇
    FPGA图像处理——前置基础篇本系列博客旨在结合FPGA来进行图像处理,致力于各种图像处理算法的实现,同时参考了博客原创作者——咸鱼FPGA的资料。以下是前置基础三节,我会以一个小白的角度去思考,解析学习过程中遇到的各种问题。1.Modelsim联合Matlab的图像仿真平台这是一个用于验......
  • fpga_fpga
    1电路 与c语言不同,verilog是并行执行语言,在看到一段简单的程序模块时,应该结合fpga内部逻辑模型,想到是什么样的功能电路。2时序 fpga的设计主要是以时序电路为主,它的所有动作都是在时钟一拍一拍的节奏下转变触发,即时钟是时序电路的控制者。 可以理解为时钟为心脏,功......
  • 基于肤色模型和中值滤波的手部检测算法FPGA实现,包括tb测试文件和MATLAB辅助验证
    1.算法运行效果图预览RTL图:   仿真图:   导入到matlab显示效果如下:   2.算法运行软件版本matlab2022a vivado2019.2 3.算法理论概述      在计算机视觉领域,基于肤色模型和中值滤波的手部检测方法是一种常见的初步定位策略。该方法主要分为......
  • 数码管的动态显示
    1.共阴极数码管实现HELLO #include<reg51.h>charstr[]={0x76,0x79,0x38,0x38,0x3F};//HELLOcharwei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; voiddelay(intn){ inti=0,j=0; for(i=0;i<n;i++) { for(j=0;j<120;j++); }} voidseg(){ ......
  • 基于FPGA温度采集的方案
    1.使用温度传感器与FPGA连接:FPGA可以通过接口与外部温度传感器进行通信,实时读取温度数据并进行处理。其中一种常用的温度传感器是LM75系列传感器,如LM75A、LM75B等。这些传感器具有高精度、温度测量范围广、低功耗等特点。                 ......
  • FPGA的串口接收部分的知识点
    在串口接收图像,存到RAM,然后读取RAM数据显示在TFT上的实验中发现发送图片的时候,发现花屏,发现是串口这边的问题。估计当时的串口接收代码没写好,这边重新看一下。moduleuart_byte_rx(Clk,Reset_n,uart_rx,Rx_Done,Rx_Data);inputClk;input......
  • FPGA使用两个HC595驱动8位数码管
    FPGA使用两个HC595驱动8位数码管本文章给出使用FPGA3根线来驱动8位数码管的示例代码,输入为disp_data,共7*8=56位,输出输入如图所示。硬件方面参数该程序只能控制数码管的7位,如有小数点位则控制不了,如有需要请自行修改。最低7位是最右边的那个数码管(这个需要根据你自己的板子......
  • proteus+keil5仿真学习笔记(第二章 1位数码管计数器)
    第二章1位数码管计数器目录第二章1位数码管计数器前言一、数码管的结构原理二、按键应用三、中断处理四、程序设计及仿真proteus电路程序总结前言主要介绍数码管、按键的应用,并涉及单片机中断处理技术。一、数码管的结构原理数码管结构如下:有两种数码......
  • proteus+keil5仿真学习笔记(第三章 4位数码管计数器)
    第三章4位数码管计数器前言一、多位数码管显示程序二、定时器原理三、程序设计与仿真proteus电路程序总结前言4位数码管计数器与1位数码管计数器相比,增加了片选电路,以确定选择哪个数码管进行工作。单片机定时器的应用也与中断处理相似,需要设置一些规定的寄存器,以......
  • 基于EP4CE6F17C8的FPGA单数码管秒计数实例
    一、电路模块本例的电路模块与“基于EP4CE6F17C8的FPGA数码管动态显示实例”中的完全一样,此处就不再给出了。二、实验代码本例实现1个数码管循环显示字符1~F,显示间隔为1秒,代码使用Verilog编写,采用例化的形式,共有三个文件。先编写数码管实现显示字形解码的程序,模块名称为seg_de......