Verilog 串口收发:

亲测可用最快波特率可以达到1_500_000HZ;

module data_rx #(parameter  clk_fre=50_000_000, baud_rate=9600,allbits=8,done_width=4)
               (
					input clk, rstn,
					input data_in,
					output [allbits-2:0]data_out,
					output done
					);
			//bits为总共要接收的数据位数(起始位+数据位(数据+校验))
			//done_width为done信号的宽度,最多为15个输入时钟宽度;
			localparam baud_cnt=clk_fre/baud_rate;
			localparam bits=allbits-1;
					reg buff1,buff2,flag_begin;
					wire en;
					reg r_over;
			always @(posedge clk or negedge rstn)
			      begin
					if(!rstn)
						begin
						buff1<=1'b1;
						buff2<=1'b1;
						end
					else if(!flag_begin)
					begin
					buff1<=data_in;
					buff2<=buff1;
					end
					else
					begin
						buff1<=1'b1;
						buff2<=1'b1;
					end
					end
        assign en=buff2&~buff1;
	
	always @(posedge clk or negedge rstn)
			begin
				if(!rstn)
					begin
					flag_begin<=1'b0;
					end
				else if (en)
					begin
				   flag_begin<=1'b1;
					end
				else if (r_over)
					begin
					flag_begin<=1'b0;
					end
				else
					begin
					flag_begin<=flag_begin;
					end
			end
		reg [13:0]cnt;
			//产生一个波特率时钟
			always @(posedge clk or negedge rstn)
					begin
						if(!rstn)
							begin
								cnt<=baud_cnt-1;
							end
					   else if (flag_begin)
							begin
							cnt<=cnt==baud_cnt-1 ? 0:cnt+1;
							end
						else
							begin
							cnt<=baud_cnt-1;
							end
					end
		reg baud_clk;
			always @(posedge clk or negedge rstn )
					begin
					if (!rstn)
						begin
						baud_clk<=1'b0;
						end
					else if (flag_begin)
						begin
						baud_clk<=cnt==0?1'b1:(cnt==baud_cnt/2?1'b0:baud_clk);
						end
					else
						begin
						baud_clk<=1'b0;
						end
				   end
		reg[3:0] bit_cnts;
		reg[bits:0] out_buff;
				reg temp1,temp2;
				always @(posedge clk or negedge rstn)
					begin
						if (!rstn)
							begin
							temp1<=1'b0;
							temp2<=1'b0;
							end
						else
							begin
							temp1<=baud_clk;
							temp2<=temp1;
							end
					end
					//baud_clk的上升沿位数加一;
						always @(posedge clk or negedge rstn)
							begin
								if (!rstn)
									begin
									bit_cnts<=4'b1111;
									end
								else if (flag_begin)
									begin
									bit_cnts<=~temp2&temp1? bit_cnts+4'd1:bit_cnts;
									end
								else
									begin
									bit_cnts<=4'b1111;
									end
							
							end
				//baud_clk为下降沿时将数据存入寄存器
			 always @(posedge clk or negedge rstn)
			      begin
						if (!rstn)
							begin
							out_buff<=0;
							end
					   else if(flag_begin&(~temp1&temp2))
						   begin
							out_buff[bit_cnts]<=data_in;
							end
					end
					
			 always@(posedge clk or negedge rstn)
				 if(!rstn)
						begin
						r_over<=1'b0;
						end
				 else if (cnt==baud_cnt-2&bit_cnts==bits)
						begin
						r_over<=1'b1;
						end
				 else
						begin
						r_over<=1'b0;
						end
				reg [3:0] done_cnt;
				reg done_flag;
				reg st;
			  always @(posedge clk or negedge rstn)
						begin 
							if(!rstn)
								begin
									done_cnt<=4'd0;
									done_flag<=1'b0;
									st<=1'b0;
								end
							else	
								begin
								case(st)
								1'b0: begin
								       	done_cnt<=4'd0;
								      	done_flag<=1'b0;
								         st<=r_over?1'b1:1'b00;
								       end
								1'b1: begin
								       done_flag<=1'b1;
										 done_cnt<=done_cnt+1;
								       st<= done_cnt==done_width?1'b0:1'b1;
										end
								endcase
								end
						end
				assign done=done_flag;
				assign data_out=out_buff[bits:1];
					
					
					
					
					
					
					
					
endmodule

module data_tx #(parameter clk_fre=50_000_000,baud_rate=9600,allbits=10,done_width=6)
					(
					 input clk,en,rstn,
					 input [bits-2:0]data_bit,
					 output d_out,done
					);
					//bits=一位起始位(一位低电平)+data_bit+一位停止位(一位高电平)
					//data_bit=校验位+数据
   localparam baud_cnts=clk_fre/baud_rate;
	localparam bits=allbits-1;
	wire [bits:0] data;
	assign data={1'b1,data_bit,1'b0};
			reg buff1,buff2;
			reg flag_send,send_over;
				always @(posedge clk or negedge rstn)
						begin
						if (!rstn)
							begin
							buff1<=1'b0;
							buff2<=1'b0;
							end
						else
							begin
							buff1<=en;
							buff2<=buff1;
							end
						end
				
				always @(posedge clk or negedge rstn)
						begin
							if(!rstn)
								begin
								flag_send<=1'b0;
								end
							else if (buff2&~buff1)
								begin
								flag_send<=1'b1;
								end
							else if (send_over)
								begin
								flag_send<=1'b0;
								end
							else
								begin
								flag_send<=flag_send;
								end
						end
				
		//产生波特率时钟
		reg [13:0]cnt;
		always @(posedge clk or negedge rstn)
			begin
			 if (!rstn)
				begin
				cnt<=baud_cnts-1;
				end
			 else if(flag_send)
				begin
				cnt<=cnt==baud_cnts-1? 0:cnt+10'd1;
				end
			else
				begin
				cnt<=baud_cnts-1;
				end
			end
				reg baud_clk;
					always @(posedge clk or negedge rstn)
						begin
							if (!rstn)
								begin
								baud_clk<=1'b0;
								end
						    else if (flag_send)
								begin
								baud_clk<=cnt==0? 1'b1:(cnt==baud_cnts/2 ? 1'b0 : baud_clk);
								end
							else 
								begin
								baud_clk<=1'b0;
								end
						end
		//在波特时钟下降沿发送新数据
			reg temp1,temp2;
			always @(posedge clk or negedge rstn)
				begin
					if (!rstn)
						begin
							temp1<=1'b0;
							temp2<=1'b0;
						end
				   else if (flag_send)
						begin
						temp1<=baud_clk;
						temp2<=temp1;
						end
					else
						begin
						temp1<=1'b0;
						temp2<=1'b0;
						end
				end
				reg [3:0]bits_cnt;
				reg out_temp;
			always @(posedge clk or negedge rstn)
				begin
					if (!rstn)
						begin
							out_temp<=1'b1;
							bits_cnt<=4'd0;
						end
					else if (flag_send&(temp1&~temp2))
						begin
							bits_cnt<=bits_cnt+4'd1;
						end
					else if (flag_send&(temp2&~temp1))
						begin
							out_temp<=data[bits_cnt-1];
						end
					else if(~flag_send)
						begin
							out_temp<=1'b1;
							bits_cnt<=4'd0;
						end
				end
				always @(posedge clk or negedge rstn)
					begin
						if(!rstn)
							begin
							send_over<=1'b0;
							end
						else if (bits_cnt==bits+1&cnt==baud_cnts/2-1)
							begin
							send_over<=1'b1;
							end
						else 
							begin
							send_over<=1'b0;
							end
					end
			 reg [3:0]done_cnt;
			 reg st,done_flag;
			 //产生一定宽度的DONE信号
			always @(posedge clk or negedge rstn)
				begin
				if (!rstn)
					begin
					st<=1'b0;
					done_flag<=1'b0;
					done_cnt<=4'd0;
					end
				else 
					begin
						case(st)
						1'b0:begin
						     done_flag<=1'b0;
							  done_cnt<=4'd0;
							  st<= send_over?1'b1:1'b0;
							  end
						1'b1:begin
								done_flag<=1'b1;
								done_cnt<=done_cnt+1;
								st<= done_cnt==done_width?1'b0:1'b1;
							  end
						endcase
					end
				end
			assign done=done_flag;
			assign d_out=out_temp;

endmodule

module AT_test(
					input clk,rstn,D_rx,
					output D_tx
					);
					

	wire [7:0]rx_data;
	wire rx_done;
    data_rx   #(.clk_fre(50_000_000),.baud_rate(1500000),.allbits(9),.done_width(6))
          rx0  (
					.clk(clk), .rstn(rstn),.data_in(D_rx),
					.data_out(rx_data),.done(rx_done)
					);
						
    data_tx   #(.clk_fre(50_000_000),.baud_rate(1500000),.allbits(10),.done_width(6))
			 tx0  (
			       .clk(clk),.en(rx_done),.rstn(rstn),.data_bit(rx_data),
					 
					 .d_out(D_tx),.done()
					);
endmodule

如有错误之处欢迎在评论区一起共同探讨;

#Verilog代码#
全部评论

相关推荐

不愿透露姓名的神秘牛友
11-26 15:46
已编辑
字节国际 电商后端 24k-35k
点赞 评论 收藏
分享
点赞 评论 收藏
分享
专心打鱼:互联网搬运工,贴子都要偷
点赞 评论 收藏
分享
评论
2
1
分享
牛客网
牛客企业服务