verilog改进篇:UART串口连续接收传输实现

        一直想抽空实现下串口信号的连线接收与传输,并且波特率可调,今天终于实现了。

代码功能:

        1. 实现9600,19200,38400,57600bps的传输;

        2. 实现串口连续接收,然后将接收到的数据再传输出去。

 

 实测发现在第一次输出时可能会出错,后面传输就没问题了。有时候接线不稳也会有干扰,导致传输错误。

代码如下:

module uart_ctrl(
	input clk,rst_n,   //clk=50M
	input data_in,
	input [2:0]baud_set,
	output reg [7:0]uart_data_out,
	output wire rev_end,
	output reg rev_state);

reg [11:0]clk_cnt;
reg [11:0]div_cnt;
reg clk_bps;
reg [7:0]clk_bps_cnt;
reg [2:0] uart_data_out_r[7:0];
reg [2:0] start_bit;
reg [2:0] stop_bit;
/***** uart input register, eliminate metastable state******/
reg [2:0]uart_data_in_r; //串口信号接收寄存
wire start_flag;         //信号接收开始标志
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)begin
		uart_data_in_r[2]<=0;
		uart_data_in_r[1]<=0;
		uart_data_in_r[0]<=0;
		end
	else begin
		uart_data_in_r[0]<=data_in;
		uart_data_in_r[1]<=uart_data_in_r[0];
		uart_data_in_r[2]<=uart_data_in_r[1];
		end
	end
assign start_flag=!uart_data_in_r[1] & uart_data_in_r[2];
assign rev_end=(clk_bps_cnt==159)?1'b1:1'b0;

/*****************clk_bps genertion******************/

		// 波特率选择(将一个波特率时钟分成16个采样时钟)
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)begin
		clk_cnt<=0;
		end
	else begin
		case(baud_set)
			0: clk_cnt<=12'd314;  // 9600/16  every bit need sample time is 16
			1: clk_cnt<=12'd163;  //19200
			2: clk_cnt<=12'd81;   //38400
			3: clk_cnt<=12'd54;   //57600
			4: clk_cnt<=12'd26;   //115200
			default: clk_cnt<=12'd314;
			endcase
		end
	end
		//采样时钟生成
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)  div_cnt<=0;
	else if (rev_state)
		if (div_cnt==clk_cnt-1) div_cnt<=0;
		else div_cnt<=div_cnt+1'b1;
	else div_cnt<=0;
	end
always @(posedge clk or negedge rst_n)begin
	if(~rst_n) clk_bps<=0;
	else if(div_cnt==1'b1) clk_bps<=1;
	else clk_bps<=0;
	end

		//采样时钟计数
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)	clk_bps_cnt<=0;
	else if(clk_bps_cnt==8'd159 || (clk_bps_cnt==8'd12 && start_bit > 3'd2)) clk_bps_cnt<=0;
	else if(clk_bps==1) clk_bps_cnt<=clk_bps_cnt+1'b1;
	else clk_bps_cnt<=clk_bps_cnt;
	 end
		//模块串口(一帧)数据接收状态
always @(posedge clk or negedge rst_n)begin
	if(~rst_n) rev_state<=0;
	else if(start_flag) rev_state<=1;
	else if(rev_end ||(clk_bps_cnt==8'd12 && start_bit > 3'd2) ) rev_state<=0;
	else rev_state<=rev_state;
	end
	
/********************protol process***************************/
	
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)begin
		start_bit<=3'd0;
		uart_data_out_r[0]<=3'd0;
		uart_data_out_r[1]<=3'd0;
		uart_data_out_r[2]<=3'd0;
		uart_data_out_r[3]<=3'd0;
		uart_data_out_r[4]<=3'd0;
		uart_data_out_r[5]<=3'd0;
		uart_data_out_r[6]<=3'd0;
		uart_data_out_r[7]<=3'd0;
		stop_bit<=3'd0;
		end
	else if (clk_bps)begin
		case(clk_bps_cnt)
			0:begin
				start_bit<=3'd0;
				uart_data_out_r[0]<=3'd0;
				uart_data_out_r[1]<=3'd0;
				uart_data_out_r[2]<=3'd0;
				uart_data_out_r[3]<=3'd0;
				uart_data_out_r[4]<=3'd0;
				uart_data_out_r[5]<=3'd0;
				uart_data_out_r[6]<=3'd0;
				uart_data_out_r[7]<=3'd0;
				end
		   6,7,8,9,10,11: start_bit<=start_bit+uart_data_in_r[2];
			22,23,24,25,26,27: uart_data_out_r[0]<=uart_data_out_r[0]+uart_data_in_r[2];
			38,39,40,41,42,43: uart_data_out_r[1]<=uart_data_out_r[1]+uart_data_in_r[2];
			54,55,56,57,58,59: uart_data_out_r[2]<=uart_data_out_r[2]+uart_data_in_r[2];
			70,71,72,73,74,75: uart_data_out_r[3]<=uart_data_out_r[3]+uart_data_in_r[2];
			86,87,88,89,90,91: uart_data_out_r[4]<=uart_data_out_r[4]+uart_data_in_r[2];
			102,103,104,105,106,107: uart_data_out_r[5]<=uart_data_out_r[5]+uart_data_in_r[2];
			118,119,120,121,122,123: uart_data_out_r[6]<=uart_data_out_r[6]+uart_data_in_r[2];
			134,135,136,137,138,139: uart_data_out_r[7]<=uart_data_out_r[7]+uart_data_in_r[2];
			150,151,152,153,154,155: stop_bit<=stop_bit+uart_data_in_r[2];
			default:begin
				start_bit<=start_bit;
				uart_data_out_r[0]<=	uart_data_out_r[0];
				uart_data_out_r[1]<=	uart_data_out_r[1];
				uart_data_out_r[2]<=	uart_data_out_r[2];
				uart_data_out_r[3]<=	uart_data_out_r[3];
				uart_data_out_r[4]<=	uart_data_out_r[4];
				uart_data_out_r[5]<=	uart_data_out_r[5];
				uart_data_out_r[6]<=	uart_data_out_r[6];
				uart_data_out_r[7]<=	uart_data_out_r[7];
				stop_bit<=stop_bit;
				end
			endcase
		end
	end
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)uart_data_out<=8'd0;
	else if (rev_end) begin
		uart_data_out[0]<=uart_data_out_r[0][2];
		uart_data_out[1]<=uart_data_out_r[1][2];
		uart_data_out[2]<=uart_data_out_r[2][2];
		uart_data_out[3]<=uart_data_out_r[3][2];
		uart_data_out[4]<=uart_data_out_r[4][2];
		uart_data_out[5]<=uart_data_out_r[5][2];
		uart_data_out[6]<=uart_data_out_r[6][2];
		uart_data_out[7]<=uart_data_out_r[7][2];
		end
	end	
endmodule
module uart_frame_receiver(
	input clk,rst_n,
	input rx_success,   //一字节数据接收成功
	input [15:0]fram_time_set,  //字节接收后最大等待时间
	output reg fram_success);

/********产生1K时钟,用于计数*******/
reg  base_clk;
reg [15:0] base_clk_cnt;
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)  base_clk_cnt<=0;
	else if(base_clk_cnt==16'd49_999) base_clk_cnt<=0;
	else base_clk_cnt<=base_clk_cnt+1'b1;
	end
always @(posedge clk or negedge rst_n)begin
	if(~rst_n) 	base_clk<=0;
	else if(base_clk_cnt==16'd49_999) 	base_clk<=1;
	else base_clk<=0;
	end
	
/********当一个字节接收成功后开始对基准时钟计数,到最大值后清零*******/
reg [15:0] cnt;
reg state;
		//帧计数状态标志,当有字节接收成功,开始计数,计数到输入的最大值后清零
always @(posedge clk or negedge rst_n)begin
	if(~rst_n) state <=0;
	else if(rx_success) state<=1;
	else if(fram_success) state <=0;
	end
		// 计数,只有在字节接收成功时开始计数,并且以基准时钟1K计数
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)	cnt<=0;
	else if(rx_success ||(cnt==fram_time_set)) cnt<=0;
	else if(state && base_clk )cnt<=cnt+1'b1;
	end
		//	帧成功标志
always @(posedge clk or negedge rst_n)begin
	if(~rst_n)	fram_success<=0;
	else if(cnt==fram_time_set) fram_success<=1;
	else fram_success<=0;
	end
endmodule

 

module uart_rx(
	input clk,rst_n,  //clk=50M
	input uart_din,
	input [2:0]baud_set,
	input [15:0]fram_time_set,
	output[7:0]uart_data_out,
	output byte_end,
	output fram_end);

uart_ctrl u1(
	.clk(clk),
	.rst_n(rst_n),   
	.data_in(uart_din),
	.baud_set(baud_set),
	.uart_data_out(uart_data_out),
	.rev_end(byte_end),
	.rev_state());
uart_frame_receiver u2(
	.clk(clk),
	.rst_n(rst_n),
	.rx_success(byte_end),   //一字节数据接收成功
	.fram_time_set(fram_time_set),  //字节接收后最大等待时间
	.fram_success(fram_end));
	
endmodule
module uart_tx(
	input clk,rst_n,
	input [7:0] data,         //需要发送的数据输入
	input [2:0]baud_set,
	input start,             //8比特数据输入进来,可以开始串口发送标志
	output reg uart_dout,
	output reg uart_trans_state,  //串口发送状态,=1表示有数据在发送,=0表示此模块空闲
	output wire uart_trans_end);   //串口发送结束

/********波特率时钟的选择与生成**********/		
reg [15:0]clk_cnt;  //波特率需要计数值
reg [15:0]div_cnt;  //对时钟进行计数
reg [15:0] half_clk_cnt; //波特率计数值的一半
reg [3:0] bps_clk_cnt; //对波特率时钟计数
reg bps_clk;
reg bps_clk_r;
wire pose_bps_clk;   //波特率时钟上升沿,后面的数据发送主要是对上升沿的计数
assign pose_bps_clk= !bps_clk_r && bps_clk;
always @(posedge clk or negedge rst_n)begin   // 波特率选择
	if(~rst_n)begin
		clk_cnt<=0;
		half_clk_cnt<=0;
		end
	else begin
		case(baud_set)
			0: clk_cnt<=16'd5028;  // 9600/16  every bit need sample time is 16
			1: clk_cnt<=16'd2604;  //19200
			2: clk_cnt<=16'd1302;   //38400
			3: clk_cnt<=16'd868;   //57600
			4: clk_cnt<=16'd434;   //115200
			default: clk_cnt<=16'd5028;
			endcase
		 half_clk_cnt<={1'b0,clk_cnt[15:1]};
		end
	end
always @(posedge clk or negedge rst_n)begin  
	if(~rst_n)  div_cnt<=0;
	else if (uart_trans_state)
		if (div_cnt==clk_cnt-1) div_cnt<=0;
		else div_cnt<=div_cnt+1'b1;
	else div_cnt<=0;
	end		
always @(posedge clk or negedge rst_n)begin  //波特率时钟生成
	if(~rst_n) bps_clk<=0;
	else if(uart_trans_state)
		if(div_cnt==half_clk_cnt) bps_clk<=1;
		else if(div_cnt==clk_cnt-1) bps_clk<=0;
	else bps_clk<=bps_clk;
	end
always @(posedge clk or negedge rst_n)begin  //波特率时钟打一拍
	if(~rst_n) bps_clk_r<=0;
	else bps_clk_r<=bps_clk;
	end	
always @(posedge clk or negedge rst_n)begin  //对波特率时钟计数
	if(~rst_n)	bps_clk_cnt<=0;
	else if(uart_trans_state)
		if(pose_bps_clk)bps_clk_cnt<=bps_clk_cnt+1'b1;
		else bps_clk_cnt<=bps_clk_cnt;
	else bps_clk_cnt<=0;
	end

/***********************串口数据发送**********************/	
always @(posedge clk or negedge rst_n)begin  //对波特率时钟计数
	if(~rst_n)	uart_dout<=1;
	else if(uart_trans_state)
		case (bps_clk_cnt)
			0: uart_dout<=0;
			1: uart_dout<=data[0];
			2: uart_dout<=data[1];
			3: uart_dout<=data[2];
			4: uart_dout<=data[3];
			5: uart_dout<=data[4];
			6: uart_dout<=data[5];
			7: uart_dout<=data[6];
			8: uart_dout<=data[7];
			9: uart_dout<=1;
			default:uart_dout<=1;
		endcase
	end
/******************串口发送状态标志***************************/
reg start_r;
wire start_flag;   //开始传输标志
assign start_flag = ~start_r & start;
assign uart_trans_end=(bps_clk_cnt==4'd9)? 1'b1:1'b0;
always @(posedge clk or negedge rst_n)begin  //对波特率时钟计数
	if(~rst_n)start_r<=0;
	else  start_r<=start;
	end
always @(posedge clk or negedge rst_n)begin  //对波特率时钟计数
	if(~rst_n) uart_trans_state<=0;
	else if(start_flag) uart_trans_state<=1;
	else if(uart_trans_end) uart_trans_state<=0;
	end
endmodule
module uart_tx_rx(	
	input clk,rst_n,
	input PC_tx,
	output PC_rx);

wire [15:0]fram_time_set=16'd20; 	
wire [2:0]baud_set=3'd0;   //修改波特率******************
wire fram_end;
wire byte_end;
wire [7:0]uart_data_out;

uart_rx RX(
	.clk(clk),
	.rst_n(rst_n),  //clk=50M
	.uart_din(PC_tx),
	.baud_set(baud_set),
	.fram_time_set(fram_time_set),
	.uart_data_out(uart_data_out),
	.byte_end(byte_end),
	.fram_end(fram_end));

uart_tx TX(
	.clk(clk),
	.rst_n(rst_n),
	.data(uart_data_out),         //需要发送的数据输入
	.baud_set(baud_set),
	.start(byte_end),             //8比特数据输入进来,可以开始串口发送标志
	.uart_dout(PC_rx),
	.uart_trans_state(),  //串口发送状态,=1表示有数据在发送,=0表示此模块空闲
	.uart_trans_end());	
endmodule

希望大家多多支持,多多提意见,一起进步哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值