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位的信息,当按下按钮是,我们认为只按了一次(按下是由低转高),实际上可能会经历多次高低信号的变换后才稳定:
如图:我们要做的事情很简单,就是对于输入信号进行多次判定,如果该信号维持的时间足够长,则输出该信号。相当于我们只检测信号稳定的部分,信号抖动的部分我们不理睬。
关于仿真
本人不太会编写仿真测试,这里就不放仿真激励了,各位自行实现。文章来源:https://www.toymoban.com/news/detail-762687.html
上板效果
最左端显示当前输入位数,右边四个数码管实时显示学号
左端四个数码管开始滚动显示学号文章来源地址https://www.toymoban.com/news/detail-762687.html
到了这里,关于verilog实现滚动显示学号(含按键消抖)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!