从一个记忆游戏来说明Verilog——4、输出显示模块(8个七段数码管的控制)

前言

之前的第一篇博客讲到了我们这个小游戏的内容和分工,前几个博客也谈到了几个重要的子模块,到现在我们已经实现了所有的底层模块,剩下的还有输出显示模块和顶层模块了。

为什么说这两个模块是顶层模块呢?我们对顶层模块的定义为实现多个模块交互的模块
这可不是简单的调用模块,输入一个时钟信号,得到一个时钟信号(指除颤或者分频),我们需要通过读入使能信号来实现不同的数码管输出方式。
(如果到这里并不清楚数码管的工作逻辑,看这篇博客

分析

我们在最开始希望构建的输出显示模块就是简单的输8个四位二进制数,然后按照使能端判断主模块的状态来实现输出即可。这里我们也是采用这样的逻辑。

  1. 既然是4位的数据,我们就需要进行译码,转换成数码管能显示的8位数据。
  2. 分频是一定要有的模块了,这个不必多说,上面的链接中有完整代码。
  3. 因为主模块是按照状态来的,所以我们就一个个状态来分析,首先是产生随机数部分,我们的使能端是if_finish,(是在random模块判断读入结束后开始,在按下S1结束的信号)。
    这里我们只需要使用5位,第一组数码管的最后一位和第二组数码管的全部,所以前面一组使能端锁定0001,输入数据赋值为out3(从左到右第四个数码管的数据),第二组正常;
  4. 下一个状态是按下S1输入地址,主模块传入的使能端是从按下S1到按下S2之间有效的一个使能端。
    我们只需要按照读入地址模块传入的内容进行输出即可,不论是地址有误还是地址正确,模块中都进行了输出数据的赋值,比较良心;
  5. 然后是数据读入的状态,因为有匹配正确和错误两个大状态(这些我们在匹配模块中都进行了使能端的输出来控制)
    如果是错误我们还有闪烁的使能端,使能端有效则输出8个0,无效直接将数码管的使能端置零;
    正确的情况下,我们只需要七位,所以我们还需要在之前的显示中做一点小处理;另外有一个横的输出,我们创建了变量来进行处理。
  6. 我们虽然没有复位信号的控制,但是我们因为需要在开机和复位先显示8个常亮的0,所以我将状态外的情况都置为0

上代码

`timescale 1ns / 1ps
//负责亮灯,开机不用管,顶层有初始化

module light(
    //输入的内容
    input clk,
    input s_one,
    input s_two,
    input flash,
    input if_right,
    input if_finish,
    input [3:0]number1,
    input [3:0]number2,
    input [3:0]number3,
    input [3:0]number4,
    input [3:0]number5,
    input [3:0]number6,
    input [3:0]number7,
    input [3:0]number8,
    //输出的内容
    output reg [7:0]leda,
    output reg [7:0]ledb,
    output reg [3:0]dn0,
    output reg [3:0]dn1
    );
    
    reg [7:0]out0;                  //存放译码结果的寄存器
    reg [7:0]out1;
    reg [7:0]out2;
    reg [7:0]out3;
    reg [7:0]out4;
    reg [7:0]out5;
    reg [7:0]out6;
    reg [7:0]out7;
    
    wire clk_o;                     //分频信号和模块调用
    light_divider div1(clk,clk_o);

    reg  [1:0]count=2'b00;              //使能端控制器
    
    reg [7:0]heng = 8'b0000_0010;   //没错人家就是那个“横”
    //译码部分
    always@(number1,number2,number3,number4,number5,number6,number7,number8)
    begin
        case(number1)
        4'b0000: out0 = 8'b1111_1100;
        4'b0001: out0 = 8'b0110_0000;
        4'b0010: out0 = 8'b1101_1010;
        4'b0011: out0 = 8'b1111_0010;
        4'b0100: out0 = 8'b0110_0110;
        4'b0101: out0 = 8'b1011_0110;
        4'b0110: out0 = 8'b1011_1110;
        4'b0111: out0 = 8'b1110_0000;
        4'b1000: out0 = 8'b1111_1110;
        4'b1001: out0 = 8'b1111_0110;
        4'b1010: out0 = 8'b1110_1110;
        4'b1011: out0 = 8'b0011_1110;
        4'b1100: out0 = 8'b0111_1010;
        4'b1101: out0 = 8'b0111_1010;
        4'b1110: out0 = 8'b1001_1110;
        4'b1111: out0 = 8'b1000_1110;
        endcase
        
        case(number2)
        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'b1110_1110;
        4'b1011: out1 = 8'b0011_1110;
        4'b1100: out1 = 8'b0111_1010;
        4'b1101: out1 = 8'b0111_1010;
        4'b1110: out1 = 8'b1001_1110;
        4'b1111: out1 = 8'b1000_1110;
        endcase
        
        case(number3)
        4'b0000: out2 = 8'b1111_1100;
        4'b0001: out2 = 8'b0110_0000;
        4'b0010: out2 = 8'b1101_1010;
        4'b0011: out2 = 8'b1111_0010;
        4'b0100: out2 = 8'b0110_0110;
        4'b0101: out2 = 8'b1011_0110;
        4'b0110: out2 = 8'b1011_1110;
        4'b0111: out2 = 8'b1110_0000;
        4'b1000: out2 = 8'b1111_1110;
        4'b1001: out2 = 8'b1111_0110;
        4'b1010: out2 = 8'b1110_1110;
        4'b1011: out2 = 8'b0011_1110;
        4'b1100: out2 = 8'b0111_1010;
        4'b1101: out2 = 8'b0111_1010;
        4'b1110: out2 = 8'b1001_1110;
        4'b1111: out2 = 8'b1000_1110;
        endcase
        
        case(number4)
        4'b0000: out3 = 8'b1111_1100;
        4'b0001: out3 = 8'b0110_0000;
        4'b0010: out3 = 8'b1101_1010;
        4'b0011: out3 = 8'b1111_0010;
        4'b0100: out3 = 8'b0110_0110;
        4'b0101: out3 = 8'b1011_0110;
        4'b0110: out3 = 8'b1011_1110;
        4'b0111: out3 = 8'b1110_0000;
        4'b1000: out3 = 8'b1111_1110;
        4'b1001: out3 = 8'b1111_0110;
        4'b1010: out3 = 8'b1110_1110;
        4'b1011: out3 = 8'b0011_1110;
        4'b1100: out3 = 8'b0111_1010;
        4'b1101: out3 = 8'b0111_1010;
        4'b1110: out3 = 8'b1001_1110;
        4'b1111: out3 = 8'b1000_1110;
        endcase
        
        case(number5)
        4'b0000: out4 = 8'b1111_1100;
        4'b0001: out4 = 8'b0110_0000;
        4'b0010: out4 = 8'b1101_1010;
        4'b0011: out4 = 8'b1111_0010;
        4'b0100: out4 = 8'b0110_0110;
        4'b0101: out4 = 8'b1011_0110;
        4'b0110: out4 = 8'b1011_1110;
        4'b0111: out4 = 8'b1110_0000;
        4'b1000: out4 = 8'b1111_1110;
        4'b1001: out4 = 8'b1111_0110;
        4'b1010: out4 = 8'b1110_1110;
        4'b1011: out4 = 8'b0011_1110;
        4'b1100: out4 = 8'b0111_1010;
        4'b1101: out4 = 8'b0111_1010;
        4'b1110: out4 = 8'b1001_1110;
        4'b1111: out4 = 8'b1000_1110;
        endcase
        
        case(number6)
        4'b0000: out5 = 8'b1111_1100;
        4'b0001: out5 = 8'b0110_0000;
        4'b0010: out5 = 8'b1101_1010;
        4'b0011: out5 = 8'b1111_0010;
        4'b0100: out5 = 8'b0110_0110;
        4'b0101: out5 = 8'b1011_0110;
        4'b0110: out5 = 8'b1011_1110;
        4'b0111: out5 = 8'b1110_0000;
        4'b1000: out5 = 8'b1111_1110;
        4'b1001: out5 = 8'b1111_0110;
        4'b1010: out5 = 8'b1110_1110;
        4'b1011: out5 = 8'b0011_1110;
        4'b1100: out5 = 8'b0111_1010;
        4'b1101: out5 = 8'b0111_1010;
        4'b1110: out5 = 8'b1001_1110;
        4'b1111: out5 = 8'b1000_1110;
        endcase
        
        case(number7)
        4'b0000: out6 = 8'b1111_1100;
        4'b0001: out6 = 8'b0110_0000;
        4'b0010: out6 = 8'b1101_1010;
        4'b0011: out6 = 8'b1111_0010;
        4'b0100: out6 = 8'b0110_0110;
        4'b0101: out6 = 8'b1011_0110;
        4'b0110: out6 = 8'b1011_1110;
        4'b0111: out6 = 8'b1110_0000;
        4'b1000: out6 = 8'b1111_1110;
        4'b1001: out6 = 8'b1111_0110;
        4'b1010: out6 = 8'b1110_1110;
        4'b1011: out6 = 8'b0011_1110;
        4'b1100: out6 = 8'b0111_1010;
        4'b1101: out6 = 8'b0111_1010;
        4'b1110: out6 = 8'b1001_1110;
        4'b1111: out6 = 8'b1000_1110;
        endcase
        
        case(number8)
        4'b0000: out7 = 8'b1111_1100;
        4'b0001: out7 = 8'b0110_0000;
        4'b0010: out7 = 8'b1101_1010;
        4'b0011: out7 = 8'b1111_0010;
        4'b0100: out7 = 8'b0110_0110;
        4'b0101: out7 = 8'b1011_0110;
        4'b0110: out7 = 8'b1011_1110;
        4'b0111: out7 = 8'b1110_0000;
        4'b1000: out7 = 8'b1111_1110;
        4'b1001: out7 = 8'b1111_0110;
        4'b1010: out7 = 8'b1110_1110;
        4'b1011: out7 = 8'b0011_1110;
        4'b1100: out7 = 8'b0111_1010;
        4'b1101: out7 = 8'b0111_1010;
        4'b1110: out7 = 8'b1001_1110;
        4'b1111: out7 = 8'b1000_1110;
        endcase
    end
    //按照状态进行数码管内容赋值和使能端赋值
    always @(posedge clk_o) 
    begin
        if(if_finish)               //随机数生成成功,开始显示
        begin
            dn0 <= 4'b0001;         //左侧锁定
            leda <= out3;
            if(count == 3)
            begin
                count <= 1'b0;
                ledb  <= out7;
                dn1   <=4'b0001; 
            end
            else 
            begin
                case(count)
                2'b00:
                begin 
                    ledb<=out4;
                    dn1<=4'b1000; 
                end
                2'b01:
                begin 
                    ledb<=out5;
                    dn1<=4'b0100;  
                end
                2'b10:
                begin 
                    ledb<=out6;
                    dn1<=4'b0010;  
                end
                endcase
                count <= count + 1'b1;
            end
        end
        else if(s_one)              //开始输入地址
        begin
            if(count == 3)
            begin
                count = 1'b0;
                leda <= out3;
                ledb<= out7;
                dn0<=4'b0001;
                dn1<=4'b0001; 
            end
            else 
            begin
            case(count)
                2'b00:
                begin 
                    leda<=out0;
                    ledb<=out4;
                    dn0<=4'b1000;
                    dn1<=4'b1000; 
                end
                2'b01:
                begin 
                    leda<=out1;
                    ledb<=out5;
                    dn0<=4'b0100;
                    dn1<=4'b0100;  
                end
                2'b10:
                begin 
                    leda<=out2;
                    ledb<=out6;
                    dn0<=4'b0010;
                    dn1<=4'b0010;  
                end
            endcase
            count = count + 1;
            end
        end
        else if(s_two)              //开始匹配
        begin
            if(if_right)            //输入对的
            begin
                if(count == 3)
                begin
                    count = 1'b0;
                    leda <= out3;
                    ledb<= out7;
                    dn0<=4'b0001;
                    dn1<=4'b0001; 
                end
                else 
                begin
                case(count)
                2'b00:
                begin 
                    leda<=out0;
                    ledb<=out4;
                    dn0<=4'b0000;   //注意这里本来是左侧第一位的使能端控制,不需要所以锁死
                    dn1<=4'b1000; 
                end
                2'b01:
                begin 
                    leda<=out1;
                    ledb<=out5;
                    dn0<=4'b0100;
                    dn1<=4'b0100;  
                end
                2'b10:
                begin 
                    leda<=heng;     //输出“横”
                    ledb<=out6;
                    dn0<=4'b0010;
                    dn1<=4'b0010;  
                end
                endcase
                count = count + 1;
                end
            end
            else                    //输入不对
            begin
            leda <= 8'b1111_1100;   //数据都为0,直接赋值
            ledb <= 8'b1111_1100;
            if(!flash)              //不亮,使能端锁死
                begin
                    dn0 <= 4'b0000;
                    dn1 <= 4'b0000;
                end
            else                    //亮
                begin
                    if(count == 3)
                    begin
                        count = 1'b0;
                        dn0<=4'b0001;
                        dn1<=4'b0001; 
                    end
                    else 
                    begin
                    case(count)
                    2'b00:
                    begin 
                        dn0<=4'b1000;
                        dn1<=4'b1000; 
                    end
                    2'b01:
                    begin 
                        dn0<=4'b0100;
                        dn1<=4'b0100;  
                    end
                    2'b10:
                    begin 
                        dn0<=4'b0010;
                        dn1<=4'b0010;  
                    end
                    endcase
                    count = count + 1;
                    end
                end
            end
        end 
        else                        //其他情况,显示8个0
        begin
            leda <= 8'b1111_1100;
            ledb <= 8'b1111_1100;
            if(count == 3)
                begin
                    count = 1'b0;
                    dn0<=4'b0001;
                    dn1<=4'b0001; 
                end
            else 
                begin
                case(count)
                2'b00:
                begin 
                    dn0<=4'b1000;
                    dn1<=4'b1000; 
                end
                2'b01:
                begin 
                    dn0<=4'b0100;
                    dn1<=4'b0100;  
                end
                2'b10:
                begin 
                    dn0<=4'b0010;
                    dn1<=4'b0010;  
                end
                endcase
                count = count + 1;
            end
        end
    end
endmodule

整体的架构想明白了还好,也不是很难,但这小四百行确实有一点离谱,因为有很多部分没有经过化简
比如译码模块完全可以单拉出来一个;
数码管使能端改变也有能合并的部分。

当时在写这部分的时候,想的不算特别清楚,不少部分是直接CV,没有经过合并,这也算是以后做这种需要多模块交互功能的教训了。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值