先把模块的层次图贴出来:
“除法器模块”不变,源代码在《Verilog打造除法器驱动数码管(上)》中;
“数码管显示模块”,主要修改的地方是,让其支持负数显示,并加入Start_Sig信号,供顶层模块重复调用,具体修改的地方请看注释:
module Display
(
input CLK,
input RSTn,
input Start_Sig,
//--
input [15:0]Display_Num,
//--
output [7:0]Row_Scan_Sig,
output [5:0]Column_Scan_Sig
);
/***************************************/
parameter
_0 = 8'b1100_0000, _1 = 8'b1111_1001, _2 = 8'b1010_0100,
_3 = 8'b1011_0000, _4 = 8'b1001_1001, _5 = 8'b1001_0010,
_6 = 8'b1000_0010, _7 = 8'b1111_1000, _8 = 8'b1000_0000,
_9 = 8'b1001_0000, _fu = 8'b1011_1111;
parameter
wei_1 = 6'b111110, wei_2 = 6'b111101, wei_3 = 6'b111011,
wei_4 = 6'b110111, wei_5 = 6'b101111, wei_6 = 6'b011111;
//-------------------------除法器例化------------------------
reg[15:0] X1; //被除数
reg[15:0] X2; //除数
wire[15:0] Quotient; //商
wire[15:0] Reminder; //余数
reg Div_Start = 1'b0;
wire Done;
Divider Divi
(
.CLK(CLK),
.RSTn(RSTn),
.Start_Sig(Div_Start),
.X1(X1), //被除数
.X2(X2), //除数
.Quotient(Quotient),
.Reminder(Reminder),
.Done(Done)
);
//-------------------------利用除法器将数字分离出来----------------------------
reg [3:0]i = 4'd0;
reg [3:0]Num [0:5]; //内存的宽度4,内存的深度5;
reg [2:0]Num_i = 3'd0;
always @(posedge CLK or negedge RSTn)
if(!RSTn)begin i <= 4'd0; end
else if(Start_Sig)
case(i)
0://判断数的正负,用于支持负数的显示
begin
Div_Start <= 1'b1; //启动除法器
X1 <= Display_Num[15] ? (~Display_Num + 1'b1) : Display_Num;//若是负数转化成正数
X2 <= 16'd10;
i <= i + 1'b1;
end
1://利用除法器,将数字一个个分离出来
begin
if(Done)
begin
Div_Start <= 1'b0;
X1 <= Quotient;
X2 <= 16'd10;
Num[Num_i] <= Reminder[3:0];
i <= i + 1'b1;
end
else begin Div_Start <= 1'b1; i <= i; end
end
2://循环
begin
if(Num_i < 4)begin Num_i <= Num_i + 1'b1; i <= i - 1'b1;end
else i <= i + 1'b1;
end
3://完成卡死,等待下一次重启
begin
i <= i;
end
endcase
else// 当Start_Sig==0时,该模块重启
begin
i <= 4'd0;
Num_i <= 3'd0;
end
/**************加码模块*************************/
//每一个SegNum对应一个数码管,SegNum[5],对应的是数符号
reg [7:0]SegNum[5:0];
//------显示个位
always @(posedge CLK)
case(Num[0])
0:SegNum[0] <= _0;
1:SegNum[0] <= _1;
2:SegNum[0] <= _2;
3:SegNum[0] <= _3;
4:SegNum[0] <= _4;
5:SegNum[0] <= _5;
6:SegNum[0] <= _6;
7:SegNum[0] <= _7;
8:SegNum[0] <= _8;
9:SegNum[0] <= _9;
endcase
//------显示十位
always @(posedge CLK)
case(Num[1])
0:SegNum[1] <= _0;
1:SegNum[1] <= _1;
2:SegNum[1] <= _2;
3:SegNum[1] <= _3;
4:SegNum[1] <= _4;
5:SegNum[1] <= _5;
6:SegNum[1] <= _6;
7:SegNum[1] <= _7;
8:SegNum[1] <= _8;
9:SegNum[1] <= _9;
endcase
//------显示百位
always @(posedge CLK)
case(Num[2])
0:SegNum[2] <= _0;
1:SegNum[2] <= _1;
2:SegNum[2] <= _2;
3:SegNum[2] <= _3;
4:SegNum[2] <= _4;
5:SegNum[2] <= _5;
6:SegNum[2] <= _6;
7:SegNum[2] <= _7;
8:SegNum[2] <= _8;
9:SegNum[2] <= _9;
endcase
//------显示千位
always @(posedge CLK)
case(Num[3])
0:SegNum[3] <= _0;
1:SegNum[3] <= _1;
2:SegNum[3] <= _2;
3:SegNum[3] <= _3;
4:SegNum[3] <= _4;
5:SegNum[3] <= _5;
6:SegNum[3] <= _6;
7:SegNum[3] <= _7;
8:SegNum[3] <= _8;
9:SegNum[3] <= _9;
endcase
//------显示万位
always @(posedge CLK)
case(Num[4])
0:SegNum[4] <= _0;
1:SegNum[4] <= _1;
2:SegNum[4] <= _2;
3:SegNum[4] <= _3;
4:SegNum[4] <= _4;
5:SegNum[4] <= _5;
6:SegNum[4] <= _6;
7:SegNum[4] <= _7;
8:SegNum[4] <= _8;
9:SegNum[4] <= _9;
endcase
//-----显示符号位
always @(posedge CLK)
if(Display_Num[15])SegNum[5] <= _fu;
else SegNum[5] <= 8'hff;
//--------------------数码管循环扫描----------------------------
reg [8:0] C0 = 9'd0;
reg [5:0]Control = 6'b111110;
always @(posedge CLK)
if(C0 == 9'd500)//这个数字不能太小,否则出现从影~~
begin
C0 <= 9'd0;
Control <= {Control[4:0],Control[5]};
end
else if(i == 3)//说明数字分离完毕,那么开始扫描~~
begin
C0 <= C0 + 1'b1;
end
//------------将每一位数显示在对应的数码管上-----------------------
reg [7:0]Seg = 8'hff;
always @(posedge CLK)
case(Control)
wei_1: Seg <= SegNum[0];
wei_2: Seg <= SegNum[1];
wei_3: Seg <= SegNum[2];
wei_4: Seg <= SegNum[3];
wei_5: Seg <= SegNum[4];
wei_6: Seg <= SegNum[5];
endcase
assign Column_Scan_Sig = Control;
assign Row_Scan_Sig = Seg;
endmodule
紧接着来看“顶层模块”,它主要负责数字的更新,以及调用“数码管显示模块”:具体代码如下:
module Digital_V0
(
input CLK,
input RSTn,
//--
output [7:0]Row_Scan_Sig,
output [5:0]Column_Scan_Sig
);
reg [15:0]Display_Num;
reg Start_Sig;
wire Done;
Display Display
(
.CLK(CLK),
.RSTn(RSTn),
.Start_Sig(Start_Sig),
.Display_Num(Display_Num),
.Row_Scan_Sig(Row_Scan_Sig),
.Column_Scan_Sig(Column_Scan_Sig)
);
parameter delay = 10'd100;
reg [15:0]C0;
always @(posedge CLK or negedge RSTn)
if(!RSTn)begin C0 <= 16'd0; end
else if(C0 == 16'd50_000)C0 <= 16'd0;
else C0 <= C0 + 1'b1;
reg [9:0]C1;
always @(posedge CLK or negedge RSTn)
if(!RSTn)begin C1 <= 10'd0; end
else if(C0 == 16'd50_000)C1 <= C1 + 1'b1;
else if(C1 == delay)C1 <= 10'd0;
reg [3:0]i;
reg [15:0]TempData = 16'd1000;
always @(posedge CLK or negedge RSTn)
if(!RSTn)begin i <= 4'd0; Start_Sig <= 1'b0;end
else
case(i)
0://准备输入的数据
begin
Display_Num <= TempData;
i <= i + 1'b1;
end
1://启动显示模块
begin
Start_Sig <= 1'b1;
i <= i + 1'b1;
end
2://每0.1秒修改一次TempData
begin
if(C1 == delay)begin TempData <= TempData - 1'b1; i <= i + 1'b1; end
else begin TempData <= TempData; i <= i; end
end
3://重启显示模块
begin
Start_Sig <= 1'b0;
i <= 4'd0;
end
endcase
endmodule
现在,数码管就可以跑起来了,它会从1000开始递减,0.1秒改变一次,减到0后会继续变成负1...等等~~