题目描述
在板子上的七段数码管上的八个数字分别显示:计时器(两位)、按照拨码开关的输入(两位)、班级(两位)、学号(两位)
其中计时器为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