时钟分频
激励文件
顶层模块
module top_seg_led(
//global clock
input sys_clk , // 全局时钟信号
input sys_rst_n, // 复位信号(低有效)
//seg_led interface
output [5:0] seg_sel , // 数码管位选信号
output [7:0] seg_led // 数码管段选信号
);
//wire define
wire [19:0] data; // 数码管显示的数值
wire [ 5:0] point; // 数码管小数点的位置
wire en; // 数码管显示使能信号
wire sign; // 数码管显示数据的符号位
//*****************************************************
//** main code
//*****************************************************
//计数器模块,产生数码管需要显示的数据
count u_count(
.clk (sys_clk ), // 时钟信号
.rst_n (sys_rst_n), // 复位信号
.data (data ), // 6位数码管要显示的数值
.point (point ), // 小数点具体显示的位置,高电平有效
.en (en ), // 数码管使能信号
.sign (sign ) // 符号位
);
//数码管动态显示模块
seg_led u_seg_led(
.clk (sys_clk ), // 时钟信号
.rst_n (sys_rst_n), // 复位信号
.data (data ), // 显示的数值
.point (point ), // 小数点具体显示的位置,高电平有效
.en (en ), // 数码管使能信号
.sign (sign ), // 符号位,高电平显示负号(-)
.seg_sel (seg_sel ), // 位选
.seg_led (seg_led ) // 段选
);
endmodule
动态显示模块
module seg_led(
//input
input clk,
input rst_n,
input [19:0] data, //数码管显示数据99_9999 20位二进制表示
input [5:0] point, //6个小数点
input en, //数码管使能信号
input sign, //符号位
//output
output reg [5:0] seg_sel, //数码管片选信号
output reg [7:0] seg_led //段选
);
//parameter define 模块内声明局部参数常数
localparam CLK_DIVIDE = 4'd10; //时钟分频系数10
localparam MAX_NUM = 13'd5000; //5MHz晶振5000*200ns=1ms
//reg define
reg [3:0] clk_cnt ; // 时钟分频计数器
reg dri_clk ; // 数码管的驱动时钟,5MHz
reg [23:0] num ; // 24位bcd码寄存器
reg [12:0] counter ; // 数码管驱动时钟计数器
reg flag ; // 标志信号(标志着counter计数达1ms)
reg [2:0] cnt_sel ; // 数码管位选计数器
reg [3:0] num_disp ; // 当前数码管显示的数据
reg dot_disp ; // 当前数码管显示的小数点
//wire define
wire [3:0] data0 ; // 个位数
wire [3:0] data1 ; // 十位数
wire [3:0] data2 ; // 百位数
wire [3:0] data3 ; // 千位数
wire [3:0] data4 ; // 万位数
wire [3:0] data5 ; // 十万位数
//**************************************
//** main code
//**************************************
//提取显示数值所对应的十进制数的各个位
//assign 连续赋值语句(总是处于激活状态)
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'd10_000 % 4'd10; // 万位数
assign data5 = data / 17'd100_000; // 十万位数
//对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_cnt <= 4'd0;
dri_clk <= 1'b1;
end
else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
clk_cnt <= 4'd0;
dri_clk <= ~dri_clk;
end
else begin
clk_cnt <= clk_cnt + 1'b1;
dri_clk <= dri_clk;
end
end
//将20位2进制转化为8421码
//dri_clk 数码管的驱动时钟
//cnt_sel数码管位选计数器
always @ (posedge dri_clk or negedge rst_n)begin
if(!rst_n)
num <= 24'b0;
else if(data5 || point[5])begin //显示6位数据
num[23:20] <= data5;
num[19:16] <= data4;
num[15:12] <= data3;
num[11:8] <= data2;
num[7:4] <= data1;
num[3:0] <= data0;
//num[23:0] <= {data5,data4,data3,data2,data1,data0};
end
else if(data4 || point[4])begin //显示5位数据
num[19:0] <= {data4,data3,data2,data1,data0};
if(sign)
num[23:20] <= 4'd11; //6位显示‘-’号
else
num[23:20] <= 4'd10; //6位不显示
end
else if(data3 || point[3])begin //显示4位数据
num[15:0] <= {data3,data2,data1,data0};
num[23:20] <= 4'd10; //6位不显示
if(sign)
num[19:16] <= 4'd11; //5位显示‘-’号
else
num[19:16] <= 4'd10; //5位不显示
end
else if(data2 || point[2])begin //显示3位数据
num[11:0] <= {data2,data1,data0};
num[23:20] <= 4'd10; //6位不显示
num[19:16] <= 4'd10; //5位不显示
if(sign)
num[15:12] <= 4'd11; //4位显示‘-’号
else
num[15:12] <= 4'd10; //4位不显示
end
else if(data1 || point[1])begin //显示2位数据
num[7:0] <= {data1,data0};
num[23:20] <= 4'd10; //6位不显示
num[19:16] <= 4'd10; //5位不显示
num[15:12] <= 4'd10; //4位不显示
if(sign)
num[11:8] <= 4'd11; //3位显示‘-’号
else
num[11:8] <= 4'd10; //3位不显示
end
else if(data0 || point[0])begin //显示1位数据
num[3:0] <= data0;
num[23:20] <= 4'd10; //6位不显示
num[19:16] <= 4'd10; //5位不显示
num[15:12] <= 4'd10; //4位不显示
num[11:8] <= 4'd10; //3位不显示
if(sign)
num[7:4] <= 4'd11; //2位显示‘-’号
else
num[7:4] <= 4'd10; //2位不显示
end
end
//5MHz计时1ms,切换片选
always @ (posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
counter <= 13'b0;
flag <= 1'b0;
end
else if(counter < MAX_NUM - 1'b1)begin
counter <= counter + 1'b1;
flag <= 1'b0;
end
else begin
counter <= 13'b0;
flag <= 1'b1;
end
end
//cnt_sel [2:0] 数码管位选计数器 高有效
//计数0-5 1ms 选择当前显示的数码管
always @ (posedge dri_clk or negedge rst_n)begin
if(!rst_n)begin
cnt_sel = 3'b0; //复位全灭
end
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'b111_111; //6'd63
end
else begin
if(en)begin //en=1
case(cnt_sel)
3'd0: begin
seg_sel <= 6'b111_110;//显示数码管第1位
num_disp <= num[3:0];
dot_disp <= ~point[0];
end
3'd1: begin
seg_sel <= 6'b111_101;//显示数码管第2位
num_disp <= num[7:4];
dot_disp <= ~point[1];
end
3'd2: begin
seg_sel <= 6'b111_011;//显示数码管第3位
num_disp <= num[11:8];
dot_disp <= ~point[2];
end
3'd3: begin
seg_sel <= 6'b110_111;//显示数码管第4位
num_disp <= num[15:12];
dot_disp <= ~point[3];
end
3'd4: begin
seg_sel <= 6'b101_111;//显示数码管第5位
num_disp <= num[19:16];
dot_disp <= ~point[4];
end
3'd5: begin
seg_sel <= 6'b011_111;//显示数码管第6位
num_disp <= num[23:20];
dot_disp <= ~point[5];
end
default: begin
seg_sel <= 6'b111_111;
end
endcase
end
else begin //en=0
seg_sel <= 6'b111111;
num_disp <= 4'b0;
dot_disp <= 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 <= {dot_disp,7'b1000000}; //显示数字 0
4'd1 : seg_led <= {dot_disp,7'b1111001}; //显示数字 1
4'd2 : seg_led <= {dot_disp,7'b0100100}; //显示数字 2
4'd3 : seg_led <= {dot_disp,7'b0110000}; //显示数字 3
4'd4 : seg_led <= {dot_disp,7'b0011001}; //显示数字 4
4'd5 : seg_led <= {dot_disp,7'b0010010}; //显示数字 5
4'd6 : seg_led <= {dot_disp,7'b0000010}; //显示数字 6
4'd7 : seg_led <= {dot_disp,7'b1111000}; //显示数字 7
4'd8 : seg_led <= {dot_disp,7'b0000000}; //显示数字 8
4'd9 : seg_led <= {dot_disp,7'b0010000}; //显示数字 9
4'd10: seg_led <= 8'b11111111; //不显示任何字符
4'd11: seg_led <= 8'b10111111; //显示负号(-)
default:
seg_led <= {dot_disp,7'b1000000};
endcase
end
end
endmodule
计时模块
module count(
//input
input clk,
input rst_n,
//output
//reg 寄存器数据类型,声明能保存数值的变量
output reg [19:0] data, //数码管显示数据99_9999 20位二进制表示
output reg [5:0] point, //6个小数点
output reg en, //数码管使能信号
output reg sign //符号位
);
//parameter define 模块内声明常数
//5000_000*20ns=100ms
parameter MAX_NUM=23'd5000_000; //计数器最大值
//reg define 寄存器数据类型声明
reg [22:0] counter; //计数器 23位 100ms
reg time_flag; //定时标志信号
//**************************************
//** main code
//**************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin //如果复位,执行
counter <= 23'b0; //计数器清零
time_flag <= 1'b0; //定时标志清零
end
else if(counter < MAX_NUM-1'b1)begin //定时未到,且counter(max)=MAX_NUM-1
counter <= counter + 1'b1; //counter++
time_flag <= 1'b0;
end
else begin //counter < MAX_NUM-1'b1
time_flag <= 1'b1; //定时标志清零
counter <= 23'b0; //计数器清零
end
end
//数码管显示的数据,0-999_999
always @ (posedge clk or negedge rst_n)begin
if(!rst_n)begin //复位初始化
data <= 20'b0;
point <= 6'b0;
sign <= 1'b0;
en <= 1'b0;
end
else begin
point <= 6'b0; //不显示小数点
sign <= 1'b0; //不显示符号
en <= 1'b1; //打开片选
if(time_flag)begin //100ms 累加一次
if(data < 20'd999_999)
data <= data + 1'b1; //data++
else
data <= 20'b0;
end
end
end
endmodule