电路设计
程序设计
顶层模块
测试显示内容 “-432.10”
module signed_seg_top(clk,rst_n,seg_sel,seg_led);
input clk;
input rst_n;
output [5:0] seg_sel;
output [7:0] seg_led;
signed_seg f0 (
.clk(clk) ,
.rst_n(rst_n) ,
.data(20'd43210) ,
.point_position(6'b000100) ,
.en(1'b1) ,
.sign(1'b1) ,
//seg pin
.seg_sel(seg_sel),
.seg_led(seg_led)
);
endmodule
主模块
//数码管-带符号位以及小数点程序
/*
接口:
signed_seg f0 (
.clk(clk) , // 时钟信号
.rst_n(rst_n) , // 复位信号
.data() , //显示的数值支持20'd0~20'd999999
.point_position(), //小数点具体显示的位置6bit独热码形式
.en(1'b1) , //数码管使能
.sign() , //符号(-),1有效
//seg pin
.seg_sel(seg_sel), // 数码管pin位选
.seg_led(seg_led) // 数码管pin段选
);
*/
module signed_seg(
input clk ,
input rst_n ,
input [19:0] data ,
input [5:0] point_position ,
input en ,
input sign ,
//seg pin
output reg [5:0] seg_sel,
output reg [7:0] seg_led
);
/******对50Mhz时钟进行:计数-译码,得到5Mhz的分频时钟dri_clk******/
reg [ 3:0] clk_cnt ;
reg dri_clk ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_cnt <= 4'd0;
end
else if(clk_cnt == 3'd4) begin
clk_cnt <= 4'd0;
end
else begin
clk_cnt <= clk_cnt + 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
dri_clk <= 1'b1;
end
else if(clk_cnt == 3'd4) begin
dri_clk <= ~dri_clk;
end
else begin
dri_clk <= dri_clk;
end
end
/******对输入进来的data(范围:0~999999)进行位拆分******/
wire [3:0] data0 ; //个位
wire [3:0] data1 ; //十位
wire [3:0] data2 ; //百位
wire [3:0] data3 ; //千位
wire [3:0] data4 ; //万位
wire [3:0] data5 ; //十万位
assign data0 = data % 4'd10;
assign data1 = data / 4'd10 % 4'd10 ;
assign data2 = data / 7'd100 % 4'd10 ;
assign data3 = data / 10'd1000 % 4'd10 ;
assign data4 = data / 14'd10000 % 4'd10;
assign data5 = data / 17'd100000;
/******判断待显示内容占几个数码管******/
wire six;
wire five;
wire four;
wire three;
wire two;
wire one;
assign six = data5 || point_position[5]; //若第六个数码管不为0 或 第六个数码管上存在小数点,则内容占6个数码管
assign five = data4 || point_position[4]; //...
assign four = data3 || point_position[3];
assign three = data2 || point_position[2];
assign two = data1 || point_position[1];
assign one = data0 || point_position[0];
/******根据上述的判断,为中间寄存器赋值******/
reg [23:0] num; //中间寄存器,寄存6个数码管每一个的显示内容
// 6 5 4 3 2 1
//num[23:20] num[19:16] num[15:12] num[11:8] num[7:4] num[3:0]
always @(posedge dri_clk or negedge rst_n) begin
if (!rst_n)
num <= 24'b0;
else if(six) //开始判断待显示内容占几个数码管,注意逐级判断.
begin
num[23:0] <= {data5,data4,data3,data2,data1,data0};
end
else if(!six && five)
begin
num[19:0] <= {data4,data3,data2,data1,data0};
if(sign)
num[23:20] <= 4'd11;
else
num[23:20] <= 4'd10;
end
else if(!six && !five && four)
begin
num[15:0] <= {data3,data2,data1,data0};
num[23:20] <= 4'd10; //第六个数码管多余,则将其关闭。
if(sign)
num[19:16] <= 4'd11;//如果需要显示负号,则第五个数码管显示负号
else //不需要显示负号时,则第五个数码管关闭
num[19:16] <= 4'd10;
end
else if(!six && !five && !four && three)
begin
num[11: 0] <= {data2,data1,data0};
num[23:16] <= {2{4'd10}};
if(sign)
num[15:12] <= 4'd11;
else
num[15:12] <= 4'd10;
end
else if(!six && !five && !four && !three && two)
begin
num[ 7: 0] <= {data1,data0};
num[23:12] <= {3{4'd10}};
if(sign)
num[11:8] <= 4'd11;
else
num[11:8] <= 4'd10;
end
else if(!six && !five && !four && !three && !two && one)
begin
num[3:0] <= data0;
num[23:8] <= {4{4'd10}};
if(sign)
num[7:4] <= 4'd11;
else
num[7:4] <= 4'd10;
end
end
/******计数1ms,输出一个flag******/
reg [12:0] cnt0;
reg flag;
always @ (posedge dri_clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
cnt0 <= 13'b0;
flag <= 1'b0;
end
else if (cnt0 < 13'd5000 - 1'b1) begin
cnt0 <= cnt0 + 1'b1;
flag <= 1'b0;
end
else begin
cnt0 <= 13'b0;
flag <= 1'b1;
end
end
/******动态数码管显示核心部分******/
/*根据计数器,快速动态轮流切换数码管,那么总有一个数码管可以被称为"当前数码管"*/
reg [2:0] cnt_sel ;
reg [3:0] num_disp ; // 当前数码管显示的数据是什么
reg dtdpe; // dtdpe = Does the decimal point exist,当前数码管存在小数点吗
always @ (posedge dri_clk or negedge rst_n) begin
if (rst_n == 1'b0)
cnt_sel <= 3'b0;
else if(flag) begin
if(cnt_sel < 3'd5)
cnt_sel <= cnt_sel + 1'b1;
else
cnt_sel <= 3'b0;
end
else
cnt_sel <= cnt_sel;
end
always @ (posedge dri_clk or negedge rst_n) begin
if(!rst_n) begin
seg_sel <= 6'b111111; //位选信号低电平有效
num_disp <= 4'b0;
dtdpe <= 1'b1; //共阳极数码管,低电平导通
end
else begin
if(en) begin
case (cnt_sel)
3'd0 :begin
seg_sel <= 6'b111110; //当前数码管是哪个数码管
num_disp <= num[3:0] ; //当前数码管显示什么值
dtdpe <= ~point_position[0];//当前数码管是否有小数点
end
3'd1 :begin
seg_sel <= 6'b111101;
num_disp <= num[7:4] ;
dtdpe <= ~point_position[1];
end
3'd2 :begin
seg_sel <= 6'b111011;
num_disp <= num[11:8];
dtdpe <= ~point_position[2];
end
3'd3 :begin
seg_sel <= 6'b110111;
num_disp <= num[15:12];
dtdpe <= ~point_position[3];
end
3'd4 :begi n
seg_sel <= 6'b101111;
num_disp <= num[19:16];
dtdpe <= ~point_position[4];
end
3'd5 :begin
seg_sel <= 6'b011111;
num_disp <= num[23:20];
dtdpe <= ~point_position[5];
end
default :begin
seg_sel <= 6'b111111;
num_disp <= 4'b0;
dtdpe <= 1'b1;
end
endcase
end
else begin
seg_sel <= 6'b111111; //使能信号为0时,所有数码管disable
num_disp <= 4'b0;
dtdpe <= 1'b1;
end
end
end
/******译码:将数字、符号、小数点,翻译成数码管专用段选信号******/
always @ (posedge dri_clk or negedge rst_n) begin
if (!rst_n)
seg_led <= 8'hc0;
else begin
case (num_disp)
4'd0 : seg_led <= {dtdpe,7'b1000000}; //0
4'd1 : seg_led <= {dtdpe,7'b1111001}; //1
4'd2 : seg_led <= {dtdpe,7'b0100100}; //2
4'd3 : seg_led <= {dtdpe,7'b0110000}; //3
4'd4 : seg_led <= {dtdpe,7'b0011001}; //4
4'd5 : seg_led <= {dtdpe,7'b0010010}; //5
4'd6 : seg_led <= {dtdpe,7'b0000010}; //6
4'd7 : seg_led <= {dtdpe,7'b1111000}; //7
4'd8 : seg_led <= {dtdpe,7'b0000000}; //8
4'd9 : seg_led <= {dtdpe,7'b0010000}; //9
4'd10: seg_led <= 8'b11111111; //空
4'd11: seg_led <= 8'b10111111; //-
default:
seg_led <= {dtdpe,7'b1000000};
endcase
end
end
endmodule