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代码#