七段数码管的使用(使能端分时控制)

题目描述

在板子上的七段数码管上的八个数字分别显示:计时器(两位)、按照拨码开关的输入(两位)、班级(两位)、学号(两位)
其中计时器为2HZ的,从10到到0,当倒计时为0时,从10重新开始计数;当按下开关s0,立即变化为10并重新计数。
拨码开关共有八个,分为两组,前四个控制第一个显示,后四个控制第二个的显示,从0到F都有。
班级学号为常数,但是班级和学号的第二位要显示小数点。

分析

数码管的显示

数码管的显示部分应该是整体的最难环节了,首先我们先介绍一下一个数码管的显示原理。数码管之所以是七段数码管,是因为在构成中分为八个显示部分,(为什么叫七段,可能是显示数字只需要七个,最后一个小数点被忽略了)
《七段数码管的使用(使能端分时控制)》
我们只需要在对应的8位信号分别对应给出高低信号,就能控制数码管的显示了。
需要注意一下,我们在实验过程中采用的数码管是共阴极,也就是将阴极连接在一起,有的数码管是共阳极,也就是对应低电平有效,那么我们就需要将输入翻转。
0~F的显示方式:
《七段数码管的使用(使能端分时控制)》
对应的二进制和十六进制:
A B C D E F G DP(点)
0 8’b1111_1100;fc
1 8’b0110_0000;60
2 8’b1101_1010;da
3 8’b1111_0010;f2
4 8’b0110_0110;66
5 8’b1011_0110;b6
6 8’b1011_1110;be
7 8’b1110_0000;e0
8 8’b1111_1110;fe
9 8’b1111_0110;f6
A 8’b1110_1110;ee
B 8’b0011_1110;3e
C 8’b0001_1010;1a
D 8’b0111_1010;7a
E 8’b1001_1110;9e
F 8’b1000_1110;8e

那么多个数码管呢
虽然我们知道了单个的数码管控制方式,但是如何控制多个数码管呢?
每一个都给一个八位的使能信号?
好主意,但是太浪费了,所以人们有更好的方法。
因为是数码管显示,是需要人眼来观察的,我们都知道人眼有视觉暂留特性,因此思路就是将数码管分为两组,一组四个用一个四位使能端控制,那么一边只需要一个八位信号了。只要使能端交替的够快,就相当于每一个数码管都在显示。 人眼的分辨约在25HZ,为了保证功能的实现以及能耗的问题,我们选择1khz交替

显示模块:
输入为8个八位二进制数(其实4位也可以,只需要在内部进行翻译),时钟信号,输出位左右端的数据和使能信号。

因为是1HZ,我们还是需要一个分频,分频在之前的博客有讲解,这里只贴出代码:
(10-8和10-3差了105,所以我们数到99999)

`timescale 1ns / 1ps

module all_divider(
    input clk_i,
    output reg clk_o
    );
    reg [16:0] cnt=0;
    always@(posedge clk_i) begin
    if(cnt == 99999)
        cnt <= 'b000;
    else 
        cnt <= cnt + 1'b1;
    
    if(cnt <= 49999)
        clk_o <= 1'b1;
    else 
        clk_o <= 1'b0;
    end
endmodule

显示模块主部分:

`timescale 1ns / 1ps

module all_counter(
    input [7:0]out0,
    input [7:0]out1,
    input [7:0]out2,
    input [7:0]out3,
    input [7:0]out4,
    input [7:0]out5,
    input [7:0]out6,
    input [7:0]out7,
    input clk_i,
    output reg [7:0]left,
    output reg [7:0]right,
    output reg [3:0]dn0,
    output reg [3:0]dn1
    );
    wire clk_o;						//分频后的时钟信号
    reg  [1:0]count=2'b00;    			//计数器,控制使能端(相当于一个24译码器)

    //分频模块的调用
    all_divider div(clk_i,clk_o);

    always @(posedge clk_o) begin
    if(count == 3)					//到3记得将计数器清零即可
        begin
            count = 2'b00;
            left <= out3;
            right<= out7;
            dn0<=4'b0001;
            dn1<=4'b0001; 
        end
    else 
        begin
            case(count)				//case语句正常判断使能端的内容
                2'b00:
                begin 
                    left<=out0;
                    right<=out4;
                    dn0<=4'b1000;
                    dn1<=4'b1000; 
                end
                2'b01:
                begin 
                    left<=out1;
                    right<=out5;
                    dn0<=4'b0100;
                    dn1<=4'b0100;  
                end
                2'b10:
                begin 
                    left<=out2;
                    right<=out6;
                    dn0<=4'b0010;
                    dn1<=4'b0010;  
                end
            endcase
            count = count + 1'b1;
        end
    end
    
endmodule

接下来就是每一个八位数的内容了,后两个只需要在顶层模进行常量赋值即可。

计时器
还是需要进行分频,并且我们需要有复位端。
输入:时钟信号和复位使能端
输出:两个八位二进制数(控制前两个的)

`timescale 1ns / 1ps
module counter(
    input clk_i,
    input s,
    output reg [7:0]out0,
    output reg [7:0]out1
);  
    wire clk;
    reg [3:0]middle=4'b1010;//计数器,从10开始
    divider div(clk_i,clk);
    always @(posedge s or posedge clk) begin
        if(s)							//复位使能端有效
        begin
            middle = 10;
            out0 = 8'b0110_0000;			//1
            out1 = 8'b1111_1100;			//0
        end
        else if(middle==0)					//到0了,重新开始计数
        begin
            middle = 10;
            out0 = 8'b0110_0000;
            out1 = 8'b1111_1100;
        end
        else
        begin
            middle = middle - 1'b1;
            out0 = 8'b1111_1100;			//高位为0
            case(middle)
                4'b0000:out1 = 8'b1111_1100;	//按照计数器内容控制
                4'b0001:out1 = 8'b0110_0000;
                4'b0010:out1 = 8'b1101_1010;
                4'b0011:out1 = 8'b1111_0010;
                4'b0100:out1 = 8'b0110_0110;
                4'b0101:out1 = 8'b1011_0110;
                4'b0110:out1 = 8'b1011_1110;
                4'b0111:out1 = 8'b1110_0000;
                4'b1000:out1 = 8'b1111_1110;
                4'b1001:out1 = 8'b1111_0110;
                4'b1010:out1 = 8'b1111_1100;
            endcase
        end
        
    end    
endmodule

(这里的代码有一点不怎么规范,应该都采用非阻塞赋值的,但是因为使能端需要立即改变,而如果是非阻塞则需要等到下一个always块,会相对慢一个周期)

控制四位拨码开关
这个比较简答,就是一个4-16译码器,直接上代码:

`timescale 1ns / 1ps

module four(
    input [3:0] in,
    output reg [7:0] out
    );
    
    always@(*) begin
        case(in)
            4'b0000:out=8'b1111_1100;
            4'b0001:out=8'b0110_0000;
            4'b0010:out=8'b1101_1010;
            4'b0011:out=8'b1111_0010;
            
            4'b0100:out=8'b0110_0110;
            4'b0101:out=8'b1011_0110;
            4'b0110:out=8'b1011_1110;
            4'b0111:out=8'b1110_0000;
            
            4'b1000:out=8'b1111_1110;
            4'b1001:out=8'b1111_0110;
            4'b1010:out=8'b1110_1110;
            4'b1011:out=8'b0011_1110;
            
            4'b1100:out=8'b0001_1010;
            4'b1101:out=8'b0111_1010;
            4'b1110:out=8'b1001_1110;
            4'b1111:out=8'b1000_1110;
        endcase        
    end
endmodule

然后使用一个顶层模块串起来就行了:

`timescale 1ns / 1ps


module hexseg8(
    input s,
    input [3:0]sw1,
    input [3:0]sw2,
    input clk_i,
    output wire [7:0]left,
    output wire [7:0]right,
    output wire [3:0]dn0,
    output wire [3:0]dn1
    );
    wire [7:0]out0;
    wire [7:0]out1;
    wire [7:0]out2;
    wire [7:0]out3;
    wire [7:0]out4=8'b;	//班级
    wire [7:0]out5=8'b;	//班级(记得加小数点
    wire [7:0]out6=8'b;	//学号
    wire [7:0]out7=8'b;
    
    wire [15:0]temp=0;
    
    //四位拨码开关
    four four1(sw1,out3);
    four four2(sw2,out2);
    //计数器
    counter counter1(clk_i,s,out0,out1);
	//数码管显示分频模块
    all_counter counter2(out0,out1,out2,out3,out4,out5,out6,out7,clk_i,left,right,dn0,dn1);

endmodule
    原文作者:筱羊冰冰
    原文地址: https://blog.csdn.net/rebortt/article/details/111355748
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞