宋桓公

Verilog打造除法器驱动数码管(下)

0
阅读(2327)


上次讲到了如何利用自制的除法器,来驱动数码管的基本方法,这次让他支持负数显示,并让其“动起来”做一个“倒计时器”。

先把模块的层次图贴出来:

“除法器模块”不变,源代码在《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...等等~~


Baidu
map