用FPGA控制6个数码管。FPGA上电时刻计时,两个为一组,分别显示时、分、秒数值。
1.端口列表
信号名 | I/O | 位宽 | 功能 |
clk | I | 1 | 时钟 |
rst_n | I | 1 | 复位 |
tube_data | O | 8 | 数码管段选 |
tube_place | O | 6 | 数码管位选 |
2.逻辑框图
3.时、分、秒信号产生模块
使用4个计数器实现。其中一个计数器实现一秒计数,一个计数器实现0-59秒计数,一个计数器实现0-59分计数,一个计数器实现0-23时计数。时、分、秒计数器的计数结果直接给到数码管模块。Verilog代码如下:
//时、分、秒产生模块
module time_get( clk , rst_n ,
shi , fen , miao
);
input clk; //50MHz
input rst_n;
output [7:0] shi; //小时
output [7:0] fen; //分钟
output [7:0] miao; //秒
//--------------------------------
//计数50_000_000产生一秒信号
reg [31:0] cnt0;
wire add_cnt0;
wire end_cnt0;
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt0 <= 32'd0;
else if( add_cnt0 ) begin
if( end_cnt0 )
cnt0 <= 32'd0;
else
cnt0 <= cnt0 + 1'b1;
end
end
assign add_cnt0 = 1'b1;
assign end_cnt0 = add_cnt0 && cnt0 == 50_000_000-1;
//--------------------------------
//秒计数器
reg [7:0] cnt1;
wire add_cnt1;
wire end_cnt1;
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt1 <= 8'd0;
else if( add_cnt1 ) begin
if( end_cnt1 )
cnt1 <= 8'd0;
else
cnt1 <= cnt1 + 1'b1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1 == 60-1;
//--------------------------------
//分钟计数器
reg [7:0] cnt2;
wire add_cnt2;
wire end_cnt2;
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt2 <= 8'd0;
else if( add_cnt2 ) begin
if( end_cnt2 )
cnt2 <= 8'd0;
else
cnt2 <= cnt2 + 1'b1;
end
end
assign add_cnt2 = end_cnt1;
assign end_cnt2 = add_cnt2 && cnt2 == 60-1;
//--------------------------------
//小时计数器
reg [7:0] cnt3;
wire add_cnt3;
wire end_cnt3;
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt3 <= 8'd0;
else if( add_cnt3 ) begin
if( end_cnt3 )
cnt3 <= 8'd0;
else
cnt3 <= cnt3 + 1'b1;
end
end
assign add_cnt3 = end_cnt2;
assign end_cnt3 = add_cnt3 && cnt3 == 24-1;
//--------------------------------
assign miao = cnt1;
assign fen = cnt2;
assign shi = cnt3;
//--------------------------------
endmodule
4.数码管模块
数码管模块把时、分、秒计数器的计数结果用移位加三算法拆为个、十位,并根据状态机对应的状态给数码管相应的段选与位选信号。Verilog代码如下:
//数码管驱动
module tube( clk , rst_n ,
shi , fen , miao ,
tube_data , tube_place
);
input clk;
input rst_n;
input [7:0] shi;
input [7:0] fen;
input [7:0] miao;
output reg [7:0] tube_data;
output reg [5:0] tube_place;
//--------------------------------
//数据存储
//不带小数点
reg [7:0] number_data[9:0]; //0-9的数据
always @( negedge rst_n ) begin
number_data[0] <= 8'hc0;
number_data[1] <= 8'hf9;
number_data[2] <= 8'ha4;
number_data[3] <= 8'hb0;
number_data[4] <= 8'h99;
number_data[5] <= 8'h92;
number_data[6] <= 8'h82;
number_data[7] <= 8'hf8;
number_data[8] <= 8'h80;
number_data[9] <= 8'h90;
end
//带小数点
reg [7:0] number_data_dot[9:0];
always @( negedge rst_n ) begin
number_data_dot[0] <= 8'h40;
number_data_dot[1] <= 8'h79;
number_data_dot[2] <= 8'h24;
number_data_dot[3] <= 8'h30;
number_data_dot[4] <= 8'h19;
number_data_dot[5] <= 8'h12;
number_data_dot[6] <= 8'h02;
number_data_dot[7] <= 8'h78;
number_data_dot[8] <= 8'h00;
number_data_dot[9] <= 8'h10;
end
//---------------------------------
//移位加三算法
reg [15:0] temp_miao;
reg [15:0] temp_fen;
reg [15:0] temp_shi;
always @( miao[7:0] ) begin
temp_miao = 16'd0;
temp_miao[7:0] = miao[7:0]; //写入第8位
repeat(8) begin //循环8次
if( temp_miao[11:8] > 4 )
temp_miao[11:8] = temp_miao[11:8] + 2'b11;
if( temp_miao[15:12] > 4 )
temp_miao[15:12] = temp_miao[15:12] + 2'b11;
temp_miao[15:1] = temp_miao[14:0]; //左移一位
end
end
///
always @( fen[7:0] ) begin
temp_fen = 16'd0;
temp_fen[7:0] = fen[7:0]; //写入第8位
repeat(8) begin //循环8次
if( temp_fen[11:8] > 4 )
temp_fen[11:8] = temp_fen[11:8] + 2'b11;
if( temp_fen[15:12] > 4 )
temp_fen[15:12] = temp_fen[15:12] + 2'b11;
temp_fen[15:1] = temp_fen[14:0]; //左移一位
end
end
///
always @( shi[7:0] ) begin
temp_shi = 16'd0;
temp_shi[7:0] = shi[7:0]; //写入第8位
repeat(8) begin //循环8次
if( temp_shi[11:8] > 4 )
temp_shi[11:8] = temp_shi[11:8] + 2'b11;
if( temp_shi[15:12] > 4 )
temp_shi[15:12] = temp_shi[15:12] + 2'b11;
temp_shi[15:1] = temp_shi[14:0]; //左移一位
end
end
//--------------------------------
//状态机
//时间计数器
reg [15:0] cnt_ms; //1ms计数器
wire add_cnt_ms; //加1条件
wire end_cnt_ms; //结束条件
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt_ms <= 16'd0;
else if( add_cnt_ms ) begin
if( end_cnt_ms )
cnt_ms <= 160'd0;
else
cnt_ms <= cnt_ms + 1'b1;
end
end
assign add_cnt_ms = 1'b1;
assign end_cnt_ms = add_cnt_ms && ( cnt_ms == 50000-1 ); //每个1ms产生高电平 //50000-1
reg [7:0] cnt_10ms; //10ms计数器
wire add_cnt_10ms;
wire end_cnt_10ms;
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
cnt_10ms <= 8'd0;
else if( add_cnt_10ms ) begin
if( end_cnt_10ms )
cnt_10ms <= 8'd0;
else
cnt_10ms <= cnt_10ms + 1'b1;
end
end
assign add_cnt_10ms = end_cnt_ms;
assign end_cnt_10ms = add_cnt_10ms && ( cnt_10ms == 1-1 );
/
parameter s0 = 3'd0,
s1 = 3'd1,
s2 = 3'd2,
s3 = 3'd3,
s4 = 3'd4,
s5 = 3'd5;
//状态表
reg [2:0] state_c; //现态
reg [2:0] state_n; //次态
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
state_c <= s0;
else
state_c <= state_n;
end
//
wire s0_to_s1_start;
wire s1_to_s2_start;
wire s2_to_s3_start;
wire s3_to_s4_start;
wire s4_to_s5_start;
wire s5_to_s0_start;
assign s0_to_s1_start = state_c == s0 && end_cnt_10ms;
assign s1_to_s2_start = state_c == s1 && end_cnt_10ms;
assign s2_to_s3_start = state_c == s2 && end_cnt_10ms;
assign s3_to_s4_start = state_c == s3 && end_cnt_10ms;
assign s4_to_s5_start = state_c == s4 && end_cnt_10ms;
assign s5_to_s0_start = state_c == s5 && end_cnt_10ms;
//
always @( * ) begin
case( state_c )
s0 : begin
if( s0_to_s1_start )
state_n = s1;
else
state_n = state_c;
end
s1 : begin
if( s1_to_s2_start )
state_n = s2;
else
state_n = state_c;
end
s2 : begin
if( s2_to_s3_start )
state_n = s3;
else
state_n = state_c;
end
s3 : begin
if( s3_to_s4_start )
state_n = s4;
else
state_n = state_c;
end
s4 : begin
if( s4_to_s5_start )
state_n = s5;
else
state_n = state_c;
end
s5 : begin
if( s5_to_s0_start )
state_n = s0;
else
state_n = state_c;
end
default : state_n = s0;
endcase
end
/
//位选输出
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
tube_place <= 6'd0;
else if( state_c == s0 )
tube_place <= 6'b011111;
else if( state_c == s1 )
tube_place <= 6'b101111;
else if( state_c == s2 )
tube_place <= 6'b110111;
else if( state_c == s3 )
tube_place <= 6'b111011;
else if( state_c == s4 )
tube_place <= 6'b111101;
else if( state_c == s5 )
tube_place <= 6'b111110;
end
//端选输出
always @( posedge clk or negedge rst_n ) begin
if( !rst_n )
tube_data <= 8'd0;
else if( state_c == s0 )
tube_data <= number_data[ temp_shi[15:12] ];
else if( state_c == s1 )
tube_data <= number_data_dot[ temp_shi[11:8] ];
else if( state_c == s2 )
tube_data <= number_data[ temp_fen[15:12] ];
else if( state_c == s3 )
tube_data <= number_data_dot[ temp_fen[11:8] ];
else if( state_c == s4 )
tube_data <= number_data[ temp_miao[15:12] ];
else if( state_c == s5 )
tube_data <= number_data[ temp_miao[11:8] ];
end
endmodule
5.顶层模块
//top
module jssz_top( clk , rst_n ,
tube_data , tube_place
);
input clk;
input rst_n;
output [7:0] tube_data;
output [5:0] tube_place;
//------------------------------
wire [7:0] shi;
wire [7:0] fen;
wire [7:0] miao;
time_get time_get(
.clk( clk ) ,
.rst_n( rst_n ) ,
.shi( shi ) ,
.fen( fen ) ,
.miao( miao )
);
//------------------------------
wire [7:0] tube_data;
wire [5:0] tube_place;
tube tube(
.clk( clk ) ,
.rst_n( rst_n ) ,
.shi( shi ) ,
.fen( fen ) ,
.miao( miao ) ,
.tube_data( tube_data ) ,
.tube_place( tube_place )
);
endmodule