问题描述:在8 个7 段管上显示HELLO_ _ _(可以显示下划线或不亮也可),每隔1 秒钟,字符序列左移或右移一个七段管的位置。系统外部时钟50 MHz。左/右移位可以通过一个波动开关sw0 来控制。
分析1:如何实现这个功能? 我们需要8个7为的寄存器(或者一个7*8 = 56 位的寄存器)来保留"hello_ _ _"这个字符串,每秒对这8个寄存器里的值做出改变,让这八个七段管的里的值发生阻塞赋值,达到移动目的(如果是7*8的寄存器做一个循环左移/右移)。
分析2:如果实现每一秒进行一次变化? 根据系统外部时钟为50 MHz,我们可以写一个计数器,时钟每变化一个周期就记录一次,一直数到50 M时输出一个电平。或者每数到25M改变一个让一个输出寄存器里的值发生反转,那么对于这个寄存器,他的周期就是1Hz了。
分析3:"hello_ _ _"字符串怎么输入? 最简单的我们可以定义一个56位的输入,把值一股脑的全部塞进去。当然现实生活中我们往往不会这么高 ,而使用一个7位的寄存器存放要输入的变量,加上一个3(8个7段管 2*3 =8)位的寄存器来指定输入要放入的具体位置,有点类似计算机中的数据总线和地址总线。这样我们要赋值8次达到将字符串写入寄存器。
我们可以清楚的看见,开始时sw0处于高电位, 输出的高电平从高位移动向低位(七段管上文字向右移动),当 sw0 的值从高电平转换为低电平时,输出的高电平从低位移动向高位(七段管上的文字向左移动)。
如果你觉得没有输出字符,不怎么方便观察,可以使用以下测试代码。主要思想是使用函数来完成将七段管的数字转换为字符的工作,再由监视器监听七段管寄存器的输出,每当其发生移动就把输出的值显示在Transcript里。
`timescale 10 ns/ 1 ns module show_hello_vlg_tst(); reg clk50; reg ifinput; reg [2:0] inp; reg [6:0] inv; reg reset; reg sw0; wire [55:0] out; wire err; show_hello i1 ( .clk50(clk50), .ifinput(ifinput), .inp(inp), .inv(inv), .out(out), .reset(reset), .sw0(sw0), .err(err) ); function[7:0] showChar; input[6:0] _in; case(_in) 7'b1001000:showChar ="H"; 7'b0110000:showChar ="E"; 7'b1100010:showChar ="O"; 7'b1110001:showChar ="L"; default: showChar ="_"; endcase endfunction initial begin // 初始化方向 和 时钟 sw0 = 1; clk50 = 0; // 给每一个七段管子赋值 #00; ifinput = 1; inp = 7; inv=7'b1001000; #10 ifinput = 0; #10; ifinput = 1; inp = 6; inv=7'b0110000; #10 ifinput = 0; #10; ifinput = 1; inp = 5; inv=7'b1110001; #10 ifinput = 0; #10; ifinput = 1; inp = 4; inv=7'b1110001; #10 ifinput = 0; #10; ifinput = 1; inp = 3; inv=7'b1100010; #10 ifinput = 0; #10; ifinput = 1; inp = 2; inv=7'b1110111; #10 ifinput = 0; #10; ifinput = 1; inp = 1; inv=7'b1110111; #10 ifinput = 0; #10; ifinput = 1; inp = 0; inv=7'b1110111; #10 ifinput = 0; #1 ifinput = 1; // 赋值过程结束 // 经过1800 个单位时间的等待,观察输出的右移过程 #1799 sw0 = 0; #1; // 再经过1600 个单位时间的等待,暂停运行 #1600 $stop; end initial $monitor(out,,,"%c %c %c %c %c %c %c %c", showChar(out[55:49]), showChar(out[48:42]), showChar(out[41:35]), showChar(out[34:28]), showChar(out[27:21]), showChar(out[20:14]), showChar(out[13: 7]), showChar(out[6: 0]) ); always begin #1 clk50 =~ clk50; end endmodule现在对于我们来说,要向寄存器中写入“hello_ _ _" 需要用户知道七段管的表式方法才行,但我们常用的是 ASCLL 码或者是数值,所以我们可以在写一个转化的模块,将用户传来的数值或者ascll码转化为7短管的显示数组,来方便我们的赋值工作。 参考如下:
