verilog实现滚动显示学号(含按键消抖)

verilog滚动显示学号

前言

经过了前前后后将近十个小时的时间,总算能够正确上板并写完了最终的实验报告。花费了我大量时间的实验我觉得有必要记录并分享出来。声明:本人写verilog的能力不强,看我花了这么多时间就知道了,如果代码有问题感谢指正,代码是在这位学长的基础上修改的 零时的轻语者

代码部分

  • 顶层模块:

      module top(
      input clk100mhz, //时钟信号
      input clr, //复位信号
      input s, //模式选择
      input key1, // 四个拨码开关
      input key2,
      input key3,
      input key4,
      input push, //切换按键,以按的次数来确定输入位数
      output [3:0] pos1, //两个数码管使能
      output [3:0] pos2,
      output [7:0] seg1, // 两个链接数码管的信号
      output [7:0] seg2
      );
     	wire [3:0]data;
      wire clk190hz, clk3hz;
      wire [15:0]dataBus1;
      wire [15:0]dataBus2;
      wire [2 : 0] count1;
      clkDiv U1(clk100mhz, clk190hz, clk3hz);
      GPU U2(.clk3hz(clk3hz), .clr(clr),.s(s),.n(data),.w(count1),.dataBus1(dataBus1),.dataBus2(dataBus2));
      segMsgout1 U3(clk190hz,dataBus1, pos1, seg1);//输入显示数码管
      segMsgout2 U4(clk190hz,dataBus2, pos2, seg2);//输出显示数码管
      pushin U5(key1,key2,key3,key4,clk100mhz,data);
      delayPush U6(clr, push, clk100mhz, count1); //按键消抖
      endmodule
    
  • 时钟分频:

    module clkDiv(
    input clk100mhz,
    output clk190hz,
    output clk3hz
    );
    reg [25:0]count=0;
    assign clk190hz=count[18];
    assign clk3hz=count[25];
    always@(posedge clk100mhz)
    count<=count+1;
    endmodule
    
  • GPU控制部分:

      module GPU(                                            
      input clk3hz,
      input clr,
      input s, // 控制输入显示和输出显示
      input [3:0]n, // 当前输入的十进制数
      input [2:0]w, // 当前输入的数的位数
      output reg [15:0]dataBus1, // 输入显示数据流
      output reg [15:0]dataBus2 //输出显示数据流
      );
      reg [31:0]msgArray; //存放输入的学号
    
      //处理数据流
      always@(posedge clk3hz or posedge clr)
      begin
      if(!clr)    //清零功能
      begin
              dataBus1<=16'b1100_1100_1100_1100;
              dataBus2<=16'b1010_1010_1010_1010;
      end
      else
      begin
          if(s)  //输出显示模式
          begin
                   dataBus1 <= 16'b1100_1100_1100_1100; //输出显示模式时,输入显示数据流赋值无效值
                   dataBus2 <= msgArray[31:16]; //更新输出显示数据流
          end
          else  //输入显示模式
          begin
              dataBus2[11 : 0] <= 12'b1010_1010_1010; // 输入显示模式时,输出显示数据流赋值无效值
              dataBus2[15 : 12] <= w;
              if(w>=4) // 输入的位数大于四,跳转到低四位
              dataBus1<=msgArray[15:0];
              else
              dataBus1<=msgArray[31:16]; // 截取显示前四位
          end
       end
      end
      // 处理输入的学号
      always@(posedge clk3hz or posedge clr) // 数据更新和显示输入数据的频率一样
          begin
              if(!clr)
              begin
                  msgArray <= 32'b1111_1111_1111_1111_1111_1111_1111_1111;
              end
              else 
              begin
                  if(s) //移位操作:将高四位移动到低四位,同时将27-0位移动到31-4位,这样便实现了一个数据的移动
                      begin
                          msgArray[3:0]<=msgArray[31:28];
                          msgArray[31:4]<=msgArray[27:0];
                      end
                  else 
                  case(w) // 每一位对应输入一个数字
                              0:msgArray[31:28] <= n[3:0];
                              1:msgArray[27:24] <= n[3:0];
                              2:msgArray[23:20]<= n[3:0];
                              3:msgArray[19:16]<= n[3:0];
                              4:msgArray[15:12]<= n[3:0];
                              5:msgArray[11:8]<= n[3:0];
                              6:msgArray[7:4] <= n[3:0];
                              7:msgArray[3:0] <= n[3:0];
                          default:msgArray[31:0]=32'b1111_1111_1111_1111_1111_1111_1111_1111;
                          endcase
              end
          end
      endmodule    
    
  • 数据译码模块:
    1和2几乎没有区别,为此不再赘述

        module segMsgout1(
        input clk190hz,
        input [15:0] dataBus, 
        output reg [3:0] pos,
        output reg [7:0] seg
    );
        reg [1:0] posC; 
        reg [3:0] dataP;
    always @(posedge clk190hz )begin
    case(posC)
        0: begin
        pos<=4'b1000;
        dataP<=dataBus[15:12];
        end
        1:begin
        pos <=4'b0100;
        dataP <= dataBus[11:8];
        end
        2:begin
        pos <=4'b0010;
        dataP <= dataBus[7:4];
        end
        3:begin
        pos <=4'b0001;
        dataP <= dataBus[3:0];
        end
        endcase
        posC = posC + 1;
    end
    always @(dataP)
    case(dataP)
            4'b0000:seg=8'b0011_1111;
            4'b0001:seg=8'b0000_0110;
            4'b0010:seg=8'b0101_1011;
            4'b0011:seg=8'b0100_1111;
            4'b0100:seg=8'b0110_0110;
            4'b0101:seg=8'b0110_1101;
            4'b0110:seg=8'b0111_1101;
            4'b0111:seg=8'b0000_0111;
            4'b1000:seg=8'b0111_1111;
            4'b1001:seg=8'b0110_1111;
            4'b1010:seg=8'b0100_0000;
            4'b1011:seg=8'b0000_0000;
            default:seg=8'b0000_1000;
    endcase
    endmodule
    
  • 数值输入模块:

    module pushin(
          input key1, key2, key3, key4,
          input clk,
          output reg [3:0] data
          );
          always@(posedge clk)begin
              data <= {key4, key3, key2, key1};
          end
      
      endmodule
    
  • 按键消抖模块:

    module delayPush(
          input clr,
          input key_in,
          input clk,
          output reg[2:0] count1
          );
    
          reg[25 : 0] count_high; //延迟高位信号
          reg key_out;
          parameter DelayTime = 1000000;
          always@(posedge clk)begin
              if(key_in ==1'b1)
                  count_high <= count_high + 1;
              else
                  count_high <= 0;
          end
          always@(posedge clk)begin
              if(count_high == DelayTime) 
                  key_out <=  1'b1;        
              else key_out <= 1'b0;
          end
          always@(posedge clk or negedge clr)begin
              if(!clr) count1 <= 0;
              else if(key_out == 1'b1) count1 <= count1 + 1;
          end
      endmodule
    
    

系统结构模块说明:

  • 接口说明:四个拨码开关控制输入的数字,一个按键控制输入的bit位,一个复位键,一个模式选择开关,总共7个输入接口;最终的效果都是在七段数码管上显示某些内容,所以输出接口就是数码管的使能和led。
  • 实现的大致思路:实验要求我们在两个不同的阶段,左右两端的四个数码管要显示不同的内容,(阶段的选择由拨码开关实现),那么我们可以在输入数字阶段,传输给右侧的数码管是有效的,左侧的数码管无效显示;在滚动显示阶段,让右侧数码管的显示无效,左侧开始滚动显示

实现细节

由于本实验的细节还是非常多的,而且每个人上手实验会遇到的问题也不同,这里我只将一些我觉得重要的地方

  • 为什么要分频:说到这个,我们要先看一下分频出来的两个信号190hz和3hz分别传输给了哪个模块,从代码中可以看出,前者给了两个数码管译码模块,后者给了GPU模块。先看数码管译码模块,这个时钟信号是控制4个数码管快速的依次显示,因为四个数码管公用同一个seg数据,所以无法实现真正意义上的同时点亮四个数码管,只能以很快的速度依次点亮,这在人眼观察下是一起点亮的,但是用手机录像可以发现数码管是依次点亮的。下面再来说3hz,这个时钟频率是用来控制滚动的频率的,显然滚动之前,四个数码管必须要都被点亮过,所以滚动的周期是要远远大于点亮四个数码管的时间的。

  • 模块间接口的类型确定:接口信号大体上分为两种(模块内接口和模块外接口),总结上就是这样,如果给这个信号赋值的是外部信号,那么这个信号必须实时反映该外部信号,所以为wire类型,如果给这个信号赋值的是模块内部信号,就要看当前信号在assign还是always内被赋值,前者为wire,后者为reg,注意,模块的内外是相对的,对于顶层模块中的信号,内部的实例模块中的信号就是该信号的外部信号。所以,是以该信号被赋值的情况来判断该信号的类型。我们以顶层模块中的count1信号为例,它是用来接收delayPush产生的信号的(该信号对于顶层模块属于外部信号),所以count1信号要实时反映该外部信号,定义为wire类型。

  • 按键消抖:本实验中,通过按键的按下次数来给定输入的bit位的信息,当按下按钮是,我们认为只按了一次(按下是由低转高),实际上可能会经历多次高低信号的变换后才稳定:
    如图:
    信号抖动

    我们要做的事情很简单,就是对于输入信号进行多次判定,如果该信号维持的时间足够长,则输出该信号。相当于我们只检测信号稳定的部分,信号抖动的部分我们不理睬

关于仿真

本人不太会编写仿真测试,这里就不放仿真激励了,各位自行实现。

上板效果

完成学号的输入
最左端显示当前输入位数,右边四个数码管实时显示学号
滚动显示学号
左端四个数码管开始滚动显示学号

  • 24
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Verilog实现按键消抖的方法是通过添加适当的延迟和边沿检测技术来实现的。 首先,按键消抖的基本原理是通过适当的延迟来判断按键是否被按下或释放。这个延迟可以使得按键抖动部分不会被检测到,从而滤除掉抖动的影响,实现按键消抖。延迟时间通常很短,例如10毫秒,这样可以避免漏检真实按下或释放按键的情况。 其次,按键消抖的关键技术之一是边沿检测。边沿检测是通过检测延迟前后按键输出电平值的变化来判断按键是否发生了边沿信号。边沿检测可以分为上升沿检测和下降沿检测。当按键从低电平变为高电平时,称为上升沿;当按键从高电平变为低电平时,称为下降沿。通过检测这些边沿信号,可以确定按键的按下和释放动作。 因此,在Verilog实现按键消抖的关键步骤包括: 1. 添加合适的延迟,通常为几毫秒的时间。这可以通过使用计数器或者延时模块来实现。 2. 在延迟前后对按键的输出电平进行检测,判断边沿信号的变化。 3. 根据边沿信号的变化来确定按键的按下和释放动作,进而实现按键消抖。 综上所述,Verilog实现按键消抖的方法包括添加适当的延迟和使用边沿检测技术来判断按键的按下和释放动作。这样可以有效地滤除按键抖动,保证按键信号的稳定性和可靠性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Verilog按键消抖检测的实现](https://blog.csdn.net/CLL_caicai/article/details/105159165)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值