【FPGA】UART串口_V1.1


之前的串口用得有些不稳定所以弄了这个串口,这个串口适用于各种常见得波特率设置,这里不讲解串口原理,直接代码分享和输入输出讲解。

一、代码

1.UART_RX

`timescale 1ns / 1ps
module uart_rx
#(parameter BPS =5208)
(

               input               clk          ,		
               input               rst_n        ,	
               input               din          ,
               output  reg[7:0]    dout         /* synthesis syn_keep=1 */,		
               output  reg         dout_vld     
               );

//parameter    	   BPS	  =	434;//115200    5208;	//9600波特率

reg   [14:0]        cnt0         ;
wire                add_cnt0     ;
wire                end_cnt0     ;

reg   [ 3:0]        cnt1         ;
wire                add_cnt1     ;
wire                end_cnt1     ;

reg                 rx0          ;	
reg                 rx1          ;	
reg                 rx2          ;	
wire                rx_en/* synthesis syn_keep=1 */;

reg                 flag_add     ;

//对数据的跨时钟处理,防止出现亚稳态
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		rx0 <= 1'b1;
        rx1 <= 1'b1;
        rx2 <= 1'b1;
	end
	else begin
		rx0 <= din;
        rx1 <= rx0;
        rx2 <= rx1;
	end
end

assign rx_en = rx2 & ~rx1;
//检测到下降沿,即空闲位从1置为0,数据传输开始

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt0 <= 15'd0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0 <= 15'd0;
        else
            cnt0 <= cnt0 + 15'd1;
    end
end

assign add_cnt0 = flag_add;
assign end_cnt0 = add_cnt0 && cnt0==(BPS-15'd1);

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt1 <= 4'd0;
    end
    else if(add_cnt1)begin
        if(end_cnt1)
            cnt1 <= 4'd0;
        else
            cnt1 <= cnt1 + 4'd1;
    end
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1==4'd9-4'd1 ; //由于是接收程序,此处也不设校验位,所以只需要接收数据就可以,后面的第10位必然位停止位,可以不理,节省资源

always @ (posedge clk or negedge rst_n)begin
	if(!rst_n) begin
		flag_add <= 1'b0;
	end
	else if(rx_en && flag_add==1'b0) begin		
		flag_add <= 1'b1;	
	end
    else if(end_cnt1) begin		
		flag_add <= 1'b0;	
	end
end

always @ (posedge clk or negedge rst_n)begin
	if(!rst_n) begin
		dout <= 8'd0;
	end
	else if(add_cnt0 && cnt0==(BPS/2-1) && cnt1!=0) begin		//在中间时刻采样,此时的数据比较稳定,从低位到高位依次采样
		case(cnt1)
			4'd1:dout[0]<=rx2;
			4'd2:dout[1]<=rx2;
			4'd3:dout[2]<=rx2;
			4'd4:dout[3]<=rx2;
			4'd5:dout[4]<=rx2;
			4'd6:dout[5]<=rx2;
			4'd7:dout[6]<=rx2;
			4'd8:dout[7]<=rx2;
			default:
			  ;
		endcase
	end
	else
	  ;
end


//传输完数据信号
always @ (posedge clk or negedge rst_n)begin
	if(!rst_n) begin
		dout_vld <= 1'b0;
	end
    else if(end_cnt1) begin		
		dout_vld <= 1'b1;	
	end
	else begin	
        dout_vld <= 1'b0;			
	end
end

endmodule

模块接口说明

uart_rx

引脚位宽方向说明
clk1IN模块时钟50M
rst_n1IN复位信号低位有效
din1INRX数据输入
dout8OUT数据输出
dout_vld1OUT数据输出有效

2.UART_TX

下面展示一些 内联代码片

`timescale 1ns / 1ps
	
module uart_tx
#(parameter BPS =5208)
(
                 input             clk    ,			
                 input             rst_n  ,		
                 input [7:0]       din    ,
                 input             din_vld,	 
                 output reg        rdy    ,  
                 output            byte_1 ,  
                 output reg        dout   
             );

//parameter         BPS    = 434;

reg   [7:0]       tx_data_tmp;	

reg               flag_add   ;
reg   [14:0]      cnt0       ;
wire              add_cnt0   ;
wire              end_cnt0   ;


reg   [ 3:0]      cnt1       ;
wire              add_cnt1   ;
wire              end_cnt1   ;

wire  [ 9:0]      data       ;

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        flag_add <= 1'b0;
    end
    else if(flag_add==1'b0 && din_vld)begin
        flag_add <= 1'b1;
    end
    else if(end_cnt1)begin
        flag_add <= 1'b0;
    end
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt0 <= 15'd0;
    end
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0 <= 15'd0;
        else
            cnt0 <= cnt0 + 15'd1;
    end
end

assign add_cnt0 = flag_add;
assign end_cnt0 = add_cnt0 && cnt0==(BPS-15'd1);

always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cnt1 <= 4'd0;
    end
    else if(add_cnt1)begin
        if(end_cnt1)
            cnt1 <= 4'd0;
        else
            cnt1 <= cnt1 + 4'd1;
    end
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1==4'd10-4'd1 ;


always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		tx_data_tmp <=8'd0;
	end
	else if(flag_add==1'b0 && din_vld) begin	
		tx_data_tmp <= din;	
	end
end

always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		dout <= 1'b1;
	end
	else if(add_cnt0 && cnt0==1-1)begin
        dout<= data[cnt1];
    end 
end

assign  data = {1'b1,tx_data_tmp,1'b0}; //传输时是从低到高 data = {停止位,数据[7],数据[6] ~ 数据[0],起始位};

always  @( * )begin
    if(din_vld || flag_add)
        rdy = 1'b0;
    else
        rdy = 1'b1;
end


assign byte_1 = end_cnt1;

endmodule

模块接口说明

uart_tx

引脚位宽方向说明
clk1IN模块时钟50M
rst_n1IN复位信号低位有效
din8IN发送数据输入
din_vld1IN发送数据输入有效
rdy1OUTbusy信号 1:不忙 0:忙
byte_11OUT一字节传输完成标志
dout1OUTTX数据输出

二、总结注意

波特率分频系数设置

parameter BPS =5208

常用波特率 50M时钟分频系数

  BAUD_9600   5208
  BAUD_19200  2604
  BAUD_38400  1302
  BAUD_115200 434

busy信号注意

always  @( * )begin
    if(din_vld || flag_add)
        rdy = 1'b0;
    else
        rdy = 1'b1;
end

该处使用组合逻辑将数据有效赋值给busy信号忙状态,建议使用时序逻辑给数据输入有效赋值,或使用组合逻辑试将代码这里的有效位移除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值