FPGA学习之数码管时间显示模块

数码管时间显示模块

背景

在学习完小梅哥的串口通信以及数码管显示教程后,他留下了一个课后作业,也就是本次的数码管时间显示模块。作为一个FPGA新人,这也算是第一个比较完整的练手小项目了,也推荐和我一样的新人花时间去完成一下。总体功能虽然比较简单,但是我也花了小两天的时间去编写加调试,其中遇到的具体问题会在后续进行阐述。

代码功能介绍

1、使用数码管完成时间显示功能(即手表时间);
2、通过串口通讯,完成时间的上传(每秒传一次);
3、可通过串口通讯设置时间;

具体代码

TOP模块

`timescale 1ns / 1ps
//
//  
// 		设计顶层 需完成时钟显示以及串口通信
// 
//

module TOP(
	input clk,
	input rst_n,
	input rx_data,
	output tx_data,
	//output [7:0]smg_sel,
	output [3:0]smg_sel,
	output [7:0]smg_display
    );

//
//  
// 		                  时钟计时与更新功能
// 
//	
	wire clk_10mhz;
	wire [23:0]final_time;
	
	pll_10mhz pll_inst(
	.inclk0(clk),
	.c0(clk_10mhz));
	
	
	
	timer_and_update(
	.clk(clk_10mhz),
	.rst_n(rst_n),
	.rx_data(rx_data),
	.final_time(final_time)
    );
	
//
//  
// 		                  数码管显示
// 
//
	LED_TOP SMG_inst(
	.clk(clk_10mhz),
	.rst_n(rst_n),
	.real_time(final_time),
	.smg_display(smg_display),
	.smg_sel(smg_sel)
    );

//
//  
// 		                  串口通信--每一秒将时间上传
//
//
	
	time_send(
			.clk_10mhz(clk_10mhz),
			.rst_n(rst_n),
			.time_rec(final_time),
			.tx_data(tx_data)
		);
		
endmodule

在顶层模块中,我们将此次功能代码主要分成3个部分:
1、时间计算及修改模块:通过该模块主要输出数码管最终显示的时间数据
2、数码管显示模块:通过该模块实现时间数据到数码管显示的转换
3、时间上传模块:通过串口进行时间上传

对于代码中的串口发送、接收代码则沿用之前博客中已验证的代码。

timer_and_update模块

`timescale 1ns / 1ps
//
//  
// 		                  时钟计时功能--可通过串口接收数据更改时间
// 
//
module timer_and_update(
	input clk,
	input rst_n,
	input rx_data,
	output [23:0]final_time
    );
	
	wire rx_done;
	wire [7:0]save_rx_data;
	uart_rx_v2 rx_inst(
		.clk(clk),
		.rst_n(rst_n),
		.rx_data(rx_data),
		.rx_done(rx_done),
		.save_rx_data(save_rx_data)
	);
	
	reg [23:0]TEM_final_time;
	reg rx_done_3byte;
	reg [1:0]rx_cnter;
	always @(posedge clk, negedge rst_n) begin
		if(!rst_n) begin
			rx_done_3byte <= 'd0;
			TEM_final_time <= 'd0;
			rx_cnter <= 2'd0;
		end else begin
			if(rx_done) begin
				rx_cnter <= rx_cnter + 'd1;
				if(rx_cnter <= 2) begin	
					case(rx_cnter)
						'd0: begin 
								//TEM_final_time[7:0] <= save_rx_data;
								TEM_final_time[23:16] <= save_rx_data;
								rx_done_3byte <= 0;
							  end
						'd1: begin 
								TEM_final_time[15:8] <= save_rx_data;
								rx_done_3byte <= 0;
							  end
						'd2: begin 
								//TEM_final_time[23:16] <= save_rx_data;
								TEM_final_time[7:0] <= save_rx_data;
								rx_cnter <= 'd0;
								rx_done_3byte <= 1;
							  end
						default: TEM_final_time <= TEM_final_time;
					endcase
				end else begin
					rx_cnter <= 'b0;
				end
			end else begin
				rx_done_3byte <= 0;
			end
		end
	end
	
	time_cal cal_inst(
		.clk_10mhz(clk),
		.rst_n(rst_n),
		.set_time(TEM_final_time),	    
		.valid(rx_done_3byte),	 	
		.final_time(final_time)
    );
endmodule

timer_and_update模块–uart_rx_v2(设置时间接收)子模块
//
//
//				UART 接收模块
//			   此代码中将额外考虑通讯链路稳定问题
//				接收数据将进行7次采样,出现大于4次的信号数据将作为最终采样结果
//
/
module uart_rx_v2(
	input clk,
	input rst_n,
	input rx_data,
	output reg rx_done,
	output reg [7:0]save_rx_data
);
//
//
//				 检测开始接收标志位
//			  
/
	
	wire RX_START;
	reg RX_data_0;
	reg RX_data_1;
	always @(posedge clk, negedge rst_n)begin
		if(!rst_n) begin
			RX_data_0 <= 0;
			RX_data_1 <= 0;
		end else begin
			RX_data_0 <= rx_data;
			RX_data_1 <= RX_data_0;
		end
	end
	assign RX_START = !RX_data_0 && RX_data_1;
	
//
//
//								bps设置以及计时器
//			  
/	
	parameter CLK_HZ		=		10_000_000,
				 BPS			=		9600,
				 BPS_CNT		=		CLK_HZ / BPS,          //每BPS
				 BPS_CNT_7 =		BPS_CNT / 7;		  //1BPS的7次采样
	

//计数7分之1个bps的中间位置--更加精确采集数据	
	reg [31:0]bps_cnter;
	reg [7:0]receive_num;   
	reg START_CNT;
	reg half_bps_flag;
	always @(posedge clk, negedge rst_n)begin
		if(!rst_n) begin
			bps_cnter <= 32'b0;
			receive_num <= 8'b0;
			half_bps_flag <= 1'b0;
		end else begin
			if(START_CNT) begin
				if(bps_cnter > BPS_CNT_7 - 1) begin
					receive_num <= receive_num + 1'b1;
					half_bps_flag <= 1'b1;
					bps_cnter <= 1'b0;
				end else begin
					bps_cnter <= bps_cnter + 1'b1;
					half_bps_flag <= 1'b0;
					receive_num <= receive_num;
				end
			end else begin
				bps_cnter <= 32'b0;
				half_bps_flag <= 1'b0;
				receive_num <= 8'b0;
			end
		end
	end
	
//产生开始计数标志位
	
	always @(posedge clk, negedge rst_n) begin
		if(!rst_n) begin
			START_CNT <= 1'b0;
		end else begin
			if(RX_START) begin
				START_CNT <= 1'b1;
			end else begin
				if(rx_done) begin
					START_CNT <= 1'b0;
				end
			end
		end
	end

//
//
//								数据接收
//			  
/		

	parameter IDLE = 3'd1,
			    STRAT_JUDGE = 3'd2,
				 RECEIVE_BEGIN = 3'd3,
				 FINISH = 3'd4;
	reg [2:0]current_state;	
	reg [2:0]each_data_7[9:0];
	always @(posedge clk, negedge rst_n) begin
		if(!rst_n) begin
			current_state <= IDLE;
		end else begin
			case(current_state)
				IDLE: if(RX_START) current_state <= STRAT_JUDGE;
				STRAT_JUDGE: begin 
						if(each_data_7[0][2] == 0 && receive_num > 7 - 1) current_state <= RECEIVE_BEGIN;
						else begin
							if(receive_num > 7 - 1) begin
								current_state <= IDLE;
							end
						end 
				end
				RECEIVE_BEGIN: if(receive_num > 69 - 1) current_state <= FINISH;
				FINISH: current_state <= IDLE;
				default: current_state <= IDLE;
			endcase
		end
	end
	
	always @(posedge clk, negedge rst_n) begin
		if(!rst_n) begin
			save_rx_data <= 8'b0;
			each_data_7[0] <= 'd0;
			each_data_7[1] <= 'd0;
			each_data_7[2] <= 'd0;
			each_data_7[3] <= 'd0;
			each_data_7[4] <= 'd0;
			each_data_7[5] <= 'd0;
			each_data_7[6] <= 'd0;
			each_data_7[7] <= 'd0;
			each_data_7[8] <= 'd0;
			each_data_7[9] <= 'd0;
		end else begin
			case(current_state)
				IDLE: begin
					rx_done <= 1'b0;
					each_data_7[0] <= 'd0;
					each_data_7[1] <= 'd0;
					each_data_7[2] <= 'd0;
					each_data_7[3] <= 'd0;
					each_data_7[4] <= 'd0;
					each_data_7[5] <= 'd0;
					each_data_7[6] <= 'd0;
					each_data_7[7] <= 'd0;
					each_data_7[8] <= 'd0;
					each_data_7[9] <= 'd0;
				end
				STRAT_JUDGE: begin
					if(half_bps_flag) begin
						case(receive_num) 
							'd0,'d1,'d2,'d3,'d4,'d5, 'd6: each_data_7[0] <= each_data_7[0] + rx_data;
						endcase					
					end
				end
				RECEIVE_BEGIN: begin
					if(half_bps_flag) begin
						case(receive_num) 
							'd7,'d8,'d9,'d10,'d11,'d12, 'd13: each_data_7[1] <= each_data_7[1] + rx_data;
							'd14,'d15,'d16,'d17,'d18,'d19, 'd20: each_data_7[2] <= each_data_7[2] + rx_data;
							'd21,'d22,'d23,'d24,'d25,'d26, 'd27: each_data_7[3] <= each_data_7[3] + rx_data;
							'd28,'d29,'d30,'d31,'d32,'d33, 'd34: each_data_7[4] <= each_data_7[4] + rx_data;
							'd35,'d36,'d37,'d38,'d39,'d40, 'd41: each_data_7[5] <= each_data_7[5] + rx_data;
							'd42,'d43,'d44,'d45,'d46,'d47, 'd48: each_data_7[6] <= each_data_7[6] + rx_data;
							'd49,'d50,'d51,'d52,'d53,'d54, 'd55: each_data_7[7] <= each_data_7[7] + rx_data;
							'd56,'d57,'d58,'d59,'d60,'d61, 'd62: each_data_7[8] <= each_data_7[8] + rx_data;
							'd63,'d64,'d65,'d66,'d67,'d68, 'd69: each_data_7[9] <= each_data_7[9] + rx_data;  //停止位
						endcase
					end
				end
				FINISH: begin 
					rx_done <= 1'b1;
					save_rx_data <= {each_data_7[8][2], each_data_7[7][2],each_data_7[6][2],each_data_7[5][2],each_data_7[4][2],
					each_data_7[3][2],each_data_7[2][2],each_data_7[1][2]};
				end
			endcase
		end
	end	
endmodule
timer_and_update模块–time_cal(时间计算)子模块
`timescale 1ns / 1ps
//
//  
// 					时钟计数功能
// 				1秒--10MHZ 100ns 10_000_000;
//					
//
//


module time_cal(
	input clk_10mhz,
	input rst_n,
	input [23:0]set_time,	     	//串口设置时间
	input valid,	 	//串口时间有效
	output [23:0]final_time
    );
	
	reg [31:0]sec_cnt;
	reg sec_flag;
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			sec_cnt <= 32'd0;
			sec_flag <= 1'b0;
		end else begin 
			if(sec_cnt <= 10_000_000 - 1) begin
				sec_cnt <= sec_cnt + 1'b1;
				sec_flag <= 1'b0;
			end else begin
				sec_cnt <= 32'd0;
				sec_flag <= 1'b1;
			end
		end
	end
	
	reg [3:0]time_sec_1;   //0-9
	reg sec_1_flag;
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			time_sec_1 <= 'd0;
			sec_1_flag <= 'd0;
		end else begin 
			if(valid) begin
				time_sec_1 <= set_time[3:0];
			end else begin
				if(sec_flag) begin
					if(time_sec_1 <= 'd8) begin
						time_sec_1 <= time_sec_1 + 1'b1;
						sec_1_flag <= 1'b0;
					end else begin
						time_sec_1 <= 'd0;
						sec_1_flag <= 1'b1;
					end
				end else begin
					sec_1_flag <= 1'b0;
				end
			end			
		end
	end
	
	reg [3:0]time_sec_2;   //0-5
	reg sec_2_flag;
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			time_sec_2 <= 'd0;
			sec_2_flag <= 'd0;
		end else begin 
			if(valid) begin
				time_sec_2 <= set_time[7:4];
			end else begin
				if(sec_1_flag) begin
					if(time_sec_2 <= 4) begin
						time_sec_2 <= time_sec_2 + 1'b1;
						sec_2_flag <= 'd0;
					end else begin
						time_sec_2 <= 'd0;
						sec_2_flag <= 'd1;
					end
				end else begin
					sec_2_flag <= 1'b0;
				end	
			end					
		end
	end
	
	reg [3:0]time_min_1;   //0-9
	reg min_1_flag;
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			time_min_1 <= 'd0;
			min_1_flag <= 'd0;
		end else begin 
			if(valid) begin
				time_min_1 <= set_time[11:8];
			end else begin
				if(sec_2_flag) begin
					if(time_min_1 <= 8) begin
						time_min_1 <= time_min_1 + 1'b1;
						min_1_flag <= 'd0;
					end else begin
						time_min_1 <= 'd0;
						min_1_flag <= 'd1;
					end
				end else begin
					min_1_flag <= 1'b0;
				end
			end				
		end
	end
	
	reg [3:0]time_min_2;   //0-5
	reg min_2_flag;
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			time_min_2 <= 'd0;
			min_2_flag <= 'd0;
		end else begin 
			if(valid) begin
				time_min_2 <= set_time[15:12];
			end else begin
				if(min_1_flag) begin
					if(time_min_2 <= 4) begin
						time_min_2 <= time_min_2 + 1'b1;
						min_2_flag <= 'd0;
					end else begin
						time_min_2 <= 'd0;
						min_2_flag <= 'd1;
					end
				end else begin
					min_2_flag <= 1'b0;
				end	
			end			
		end
	end
	
	reg [3:0]time_h_1; //0-9
	reg h_1_flag;	
	reg reverse_flag;
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			time_h_1 <= 'd0;
			h_1_flag <= 'd0;
			reverse_flag <= 'd0;
		end else begin 
			if(valid) begin
				time_h_1 <= set_time[19:16];
				//if(set_time[23:21] == 'b101) begin
				//if(set_time[23:16] > 'd19) begin	 	 不行
				//if(set_time[23:16] > 'b10011) begin   不行
				if(set_time[23:16] > 'b0001_0011) begin 
					reverse_flag <= 1;
				end else begin
					reverse_flag <= 0;
				end
			end else begin
				if(min_2_flag) begin
					if(time_h_1 <= 8 && !reverse_flag) begin
						time_h_1 <= time_h_1 + 1'b1;
						h_1_flag <= 'd0;
					end else begin
						if(!reverse_flag) begin
							reverse_flag <= ~ reverse_flag;
							time_h_1 <= 'd0;
							h_1_flag <= 'd1;
						end else begin
							if(time_h_1 <= 2 && reverse_flag) begin
								time_h_1 <= time_h_1 + 1'b1;
								h_1_flag <= 'd0;
							end else begin
								if(reverse_flag) begin
									reverse_flag <= ~ reverse_flag;
									time_h_1 <= 'd0;
									h_1_flag <= 'd1;
								end
							end
						end
					end
				end else begin
					h_1_flag <= 'd0;
				end 
			end		
		end
	end
	
	reg [3:0]time_h_2;   //0-2
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			time_h_2 <= 'd0;
		end else begin 
			if(valid) begin
				time_h_2 <= set_time[23:20];		
			end else begin
				if(h_1_flag) begin
					if(time_h_2 <= 1) begin
						time_h_2 <= time_h_2 + 1'b1;
					end else begin
						time_h_2 <= 'd0;
					end
				end	
			end			
		end
	end
	assign final_time =  {time_h_2, time_h_1, time_min_2, time_min_1, time_sec_2, time_sec_1};
endmodule

数码管显示模块(LED_TOP)

该模块主要实现将上述模块得到的时间数据用于数码管驱动

`timescale 1ns / 1ps
//
//
//       该模块实现时钟的4位数码管显示
// 
//
module LED_TOP(
	input clk,
	input rst_n,
	input [23:0]real_time,
	output reg [7:0]smg_display,
	//output reg [7:0] smg_sel
	output reg [3:0] smg_sel
    );
	

	wire [47:0]led_ctrl;
	LED_DECODE LED_second_1(
	.led_num(real_time[3:0]),
	.led_show(led_ctrl[7:0])
    );
		
	LED_DECODE LED_second_2(
	.led_num(real_time[7:4]),
	.led_show(led_ctrl[15:8])
    );
	
	LED_DECODE LED_min_1(
	.led_num(real_time[11:8]),
	.led_show(led_ctrl[23:16])
    );
	
	LED_DECODE LED_min_2(
	.led_num(real_time[15:12]),
	.led_show(led_ctrl[31:24])
    );
	
	LED_DECODE LED_h_1(
	.led_num(real_time[19:16]),
	.led_show(led_ctrl[39:32])
    );
	
	LED_DECODE LED_h_2(
	.led_num(real_time[23:20]),
	.led_show(led_ctrl[47:40])
    );
	
//
//  
// 		                  数码管切换
// 
//
	
	reg [32:0]smg_sel_cnt;
	reg flag;
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			smg_sel_cnt <= 'b0;
			flag <= 0;
		end else begin 
			if(smg_sel_cnt <= 'd100) begin
				smg_sel_cnt <= smg_sel_cnt + 1;
				flag <= 0;
			end else begin
				smg_sel_cnt <= 0;
				flag <= 1;
			end
		end
	end
	
	
	reg [1:0]smg_cnt;
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			smg_cnt <= 2'b0;
		end else begin 
			if(flag) begin
				smg_cnt <= smg_cnt + 1'b1;
			end else begin
				smg_cnt <= smg_cnt;
			end	
		end
	end
	
	//由于开发板只有四个数码管,故此处只写了4个
	always @(smg_cnt) begin
		case(smg_cnt)
			'b00: smg_sel = 'b1110;
			'b01: smg_sel = 'b1101;
			'b10: smg_sel = 'b1011;
			'b11: smg_sel = 'b0111;	
			default: smg_sel = 'b1111;
		endcase
	end

	always @(posedge clk or negedge rst_n) begin
		if(!rst_n) begin
			smg_display <= 'd0;
		end else begin
			case(smg_sel)
				//4'b1110:smg_display <= led_ctrl[7:0];
				//4'b1101:smg_display <= led_ctrl[15:8];
				4'b0111:smg_display <= led_ctrl[23:16];
				4'b1011:smg_display <= led_ctrl[31:24];
				4'b1101:smg_display <= led_ctrl[39:32];
				4'b1110:smg_display <= led_ctrl[47:40];
				default:smg_display <= 8'b1111_1111;
			endcase
		end
	end	
endmodule
数码管显示模块(LED_TOP)–(数码管解码子模块)LED_DECODE
`timescale 1ns / 1ps

//
// 
//			该模块主要实现将接收到的数据转换成LED对应显示(8段数码管)
//
//

module LED_DECODE(
	input [3:0] led_num,
	output reg [7:0] led_show
    );
	
//将接收到的数据转换成数码管形式

	parameter NUM_ZERO = 8'b0000_0011,
			  NUM_ONE  = 8'b1001_1111,
			  NUM_TWO = 8'b0010_0101,
			  NUM_THREE = 8'b0000_1101,
			  NUM_FOUR  = 8'b1001_1001,
			  NUM_FIVE = 8'b0100_1001,
			  NUM_SIX = 8'b0100_0001,
			  NUM_SEVEN  = 8'b0001_1111,
			  NUM_EIGHT = 8'b0000_0001,
			  NUM_NINE = 8'b0000_1001;
	
	always @(*) begin	
		case(led_num)
			4'd0: led_show = NUM_ZERO;
			4'd1: led_show = NUM_ONE;
			4'd2: led_show = NUM_TWO;
			4'd3: led_show = NUM_THREE;
			4'd4: led_show = NUM_FOUR;
			4'd5: led_show = NUM_FIVE;
			4'd6: led_show = NUM_SIX;
			4'd7: led_show = NUM_SEVEN;
			4'd8: led_show = NUM_EIGHT;
			4'd9: led_show = NUM_NINE;
			default: led_show = NUM_ZERO;
		endcase	
	end 	
endmodule

时间数据上传模块(time_send)

`timescale 1ns / 1ps
//
//  
// 		                  串口通信--每一秒将时间上传
// 						需将时间数据拆成3包 分别发送
//
//

module time_send(
		input clk_10mhz,
		input rst_n,
		input [23:0]time_rec,
		output tx_data
    );
	
	reg sec_flag;
	reg [31:0]sec_cnt;	
	always @(posedge clk_10mhz, negedge rst_n) begin
		if(!rst_n) begin
			sec_cnt <= 32'd0;
			sec_flag <= 'd0;
		end else begin 
			if(sec_cnt <= 10_000_000 - 1) begin
				sec_cnt <= sec_cnt + 1'b1;
				sec_flag <= 'd0;			
			end else begin
				sec_cnt <= 32'd0;
				sec_flag <= 'd1;				
			end
		end
	end
	
	reg [1:0]send_pos_cnt;
	always @(posedge clk_10mhz, negedge rst_n) begin	
		if(!rst_n) begin
			send_pos_cnt <= 2'b0;
		end else begin
			send_pos_cnt <= send_pos_cnt + 1'b1;
		end
	end	
	
	reg [7:0]time_8bit;
	always @(posedge clk_10mhz, negedge rst_n) begin	
		if(!rst_n) begin
			time_8bit <= 'd0;
		end else begin
		case(send_pos_cnt)
			'd0:time_8bit <= time_rec[23:16];
			'd1:time_8bit <= time_rec[15:8];
			'd2:time_8bit <= time_rec[7:0];
			'd3:time_8bit <= 'b1111_1111;
			default: time_8bit <= 'b1111_1111;
		endcase
		end
	end
	
	wire tx_done;
	uart_tx(.clk(clk_10mhz),
			.rst_n(rst_n),
			.tx_en(sec_flag),	
			.data(time_8bit),
			.tx_data(tx_data),
			.tx_done(tx_done)
	);
endmodule

时间数据上传模块(time_send)–串口发送子模块 (uart_tx)

/
            UART发送模块
		8BIT数据位+1BIT停止位
			 波特率默认9600
/

module uart_tx(input clk,
					input rst_n,
					input tx_en,	
					input [7:0]data,
					output reg tx_data,
					output reg tx_done
);
	
/
            
		    波特率计算以及bps计数器
			
/	
	parameter CLK_BPS = 9600;
	parameter BPS_cnt = 10_000_000/CLK_BPS;
	
	reg clk_bps;
	reg [31:0]CNT_BPS;
	always @(posedge clk, negedge rst_n) begin
	
		if(!rst_n) begin
			clk_bps <= 0;
			CNT_BPS <= 0;
		end else begin
			if(CNT_BPS <= BPS_cnt) begin
				clk_bps <= 1'b0;
				CNT_BPS <= CNT_BPS + 1;
			end else begin
				clk_bps <= 1'b1;
				CNT_BPS <= 0;
			end
		end	
	end
	
	reg [7:0]need_tx_data;
	always @(posedge clk) begin
		if(tx_en) begin
			need_tx_data <= data;
		end	
	end

/
            
		       发送状态机
			
/		
	
	parameter IDLE = 6'd0,
				 SEND_1 = 6'd1,
				 SEND_2 = 6'd2,
				 SEND_3 = 6'd3,
				 SEND_4 = 6'd4,
				 SEND_5 = 6'd5,
				 SEND_6 = 6'd6,
				 SEND_7 = 6'd7,
				 SEND_8 = 6'd8,
				 SEND_9 = 6'd9,
				 SEND_10 = 6'd10,
				 FINISH = 6'd11;

	reg [5:0]current_state;
	reg [3:0]tx_cnt;
	
	always @(posedge clk, negedge rst_n) begin
	
		if(!rst_n) begin
			current_state <= 3'd0;
		end else begin
			case(current_state)
				IDLE:  begin 
							if(tx_en) current_state <= SEND_1;
							else current_state <= current_state;
						 end
						 
				SEND_1: begin 
							if(clk_bps) begin
								current_state <= SEND_2;
							end else current_state <= current_state;
						end
				SEND_2: begin 
							if(clk_bps) begin
								current_state <= SEND_3;
							end else current_state <= current_state;
						end
				SEND_3: begin 
							if(clk_bps) begin
								current_state <= SEND_4;
							end else current_state <= current_state;
						end
				SEND_4: begin 
							if(clk_bps) begin
								current_state <= SEND_5;
							end else current_state <= current_state;
						end
				SEND_5: begin 
							if(clk_bps) begin
								current_state <= SEND_6;
							end else current_state <= current_state;
						end
				SEND_6: begin 
							if(clk_bps) begin
								current_state <= SEND_7;
							end else current_state <= current_state;
						end
				SEND_7: begin 
							if(clk_bps) begin
								current_state <= SEND_8;
							end else current_state <= current_state;
						end
				SEND_8: begin 
							if(clk_bps) begin
								current_state <= SEND_9;
							end else current_state <= current_state;
						end
				SEND_9: begin 
							if(clk_bps) begin
								current_state <= SEND_10;
							end else current_state <= current_state;
						end
				SEND_10: begin 
							if(clk_bps) begin
								current_state <= FINISH;
							end else current_state <= current_state;
						end
						
				FINISH: current_state <= IDLE;
				default: current_state <= IDLE;
			endcase
		end
	end
	
	always @(posedge clk, negedge rst_n) begin
		if(!rst_n) begin
			tx_cnt <= 4'd0;
		end else begin
			case(current_state)
				IDLE: begin 
							tx_data <= 1'b1;
							tx_done <= 1'd0;
						end	
				SEND_1: begin 
							if(clk_bps) begin
								tx_data <= 0;								//发送开始位
							end
						end
				SEND_2: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[0];
							end
						end
				SEND_3: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[1];
							end
						end
				SEND_4: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[2];
							end
						end
				SEND_5: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[3];
							end
						end
				SEND_6: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[4];
							end
						end
				SEND_7: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[5];
							end
						end
				SEND_8: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[6];
							end
						end
				SEND_9: begin 
							if(clk_bps) begin
								tx_data <= need_tx_data[7];
							end
						end
				SEND_10: begin 
							if(clk_bps) begin
								tx_data <= 1;            //发送停止位
							end
						end
						
				FINISH: begin
							tx_cnt <= 4'd0;
							tx_done <= 1'd1;
						end
			endcase
		end
	end
endmodule

代码验证

串口助手验证

时间上传

在这里插入图片描述
注意:我的上传时间是每一秒传一个时间单位(小时、分钟、秒钟),在串口中可以看出,目前时间是下午13点22分08秒;其中FF只是为了方便看当前时间,作分割用。

时间设置

在这里插入图片描述
可以看见当我像开发板发送21 30 12时,其对应时间也被设置为了晚上21点30分15秒(由于3秒延时上传)。

开发板数码管显示

在这里插入图片描述
上图显示时间为21点33分

问题总结

1、数码管切换问题:
数码管的选通实际是以非常快的速度逐个切换的(即同一时间实际只有一个数码管亮),由于视觉暂留效果会得到4个数码管同时显示的效果。但实际开发中,我发现若以10MHZ的频率去切换数码管,实际将导致数码管显示错乱,后续增加了一个延时(计时100个clk才切换)才解决该问题。
在未加延时时,通过signaltop对信号进行抓取,发现case语句居然跑飞了(会出现进入default语句的结果),这也实在是不可思议。

2、串口时间接收问题
在串口助手中,我们直接发送需要设置的时间,例如233021(21点30分21秒)。一开始我以为串口发送数据的顺序为21–>30–>23,但是实际上串口发送助手是发送23、30、21。

3、数组的比较问题
一开始我使用了 if(set_time[23:16] > 'd19) 和 if(set_time[23:16] > 'b10011) 形式,但实际上都是行不通的,这种数据切片比较必须把所有位数列出:if(set_time[23:16] > 'b0001_0011)

已知BUG

目前代码并未对设置时间进行检查,也就是说如果你设置时间为99点99分99秒也是会继续计时下去的,并未对其进行防护,如果有有兴趣的可以自己在时间计算模块内部进行设置时间检查代码的添加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值