FPGA实现UART协议的接收与发送

一、接收模块uart_rx.v

        UART协议,空闲时,TX和RX数据线都是通过上拉电阻拉高的状态,这样才能在起始位到来时检测到一个下降的边沿。 

 UART数据格式

FPGA实现UART协议的接收与发送_第1张图片

uart_rx.v模块输入输出示意图

FPGA实现UART协议的接收与发送_第2张图片 

  1. RX_start。首先,找到起始位的开始时刻RX_start,这是一个接收字节的最一开始。对RX打拍两次得到RX_1、RX_2。并找出传输每个字节的RX的起始时刻RX_start。

    (注意!:只有在cnt=0时RX出现的下降沿才是起始时刻,否则RX传输过程中也会有由高电平变低电平的情况,这种情况显然不能判定为起始时刻)

  2. cnt。最小是0,最大是传输(1+8+0.5)byte所用时间。cnt平时为0,RX_start出现时cnt立刻开始累加,一直累加到最大值才停止然后恢复到0,等待下一个RX_start到来从新触发cnt累加。cnt不为零的时候,就是说明RX线上正在传输一个字节。
  3. 在何时刻读取RX线上的数据位?定义一个8位的临时寄存器——RX_data_r。在cnt累加到bit1_OK时,到达LSB最低位的中间时刻,中间时刻是最稳定的所以选择在每一位的中间时刻保存该位。以此类推,当cnt累加到bit8_OK时即保存到第8位MSB,这样就保存完一个字节。
  4. 输出结果RX_data、RX_OK。每次都是在cnt累加到bitstop_OK处,把RX_data_r赋值给RX_data,同时产生一个与数据同步的单脉冲RX_OK告知外界本字节接收完且数据可用(注意!:cnt累加到bitstop_OK处时,其实不算完全接收完,因为刚刚接收完停止位的一半)
  5. uart_rx.v程序如下:
module uart_rx#(
	parameter	OSC 		= 50_000_000,
	parameter	BPS 		= 9600,
	parameter	bit_1_cnt 	= 5208,	//bit_1_cnt = OSC/BPS。代表接收1位UART数据时,需要的clk周期个数
	parameter	bit_0_5_cnt = 2604,	//bit_0_5_cnt = bit_1_cnt/2。代表接收0.5位UART数据时,需要的clk周期个数
	parameter	cnt_max 	= 52083	//cnt_max = bit_1_cnt*10。代表接收10位UART数据时,需要的clk周期个数
)(
	input				clk,
	input				RSTn,
	//
	input				RX,
	output reg [7:0]	RX_data,	//接收到的字节数据,在停止位的中间时刻被赋值生效
	output reg			RX_OK		//当一个字节传输完后,也就接收完毕,在停止位结束的最后一刻产生一个接收完成单脉冲信号。RX_data和RX_OK不同步
);

//******************************************************
//		parameter
//******************************************************
localparam	bit1_OK 	= bit_0_5_cnt+bit_1_cnt;
localparam	bit2_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit3_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit4_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit5_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit6_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit7_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit8_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bitstop_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;


//-------------------------RX_1,RX_2-----------------------------------
reg RX_1,RX_2;		//对输入进来的RX信号打两拍,方便检测出下降沿
wire RX_start;		//起始位到来那一时刻,产生一个单脉冲信号

//-------------------------cnt-----------------------------------
reg [31:0] cnt;

//-------------------------RX_data_r-----------------------------------
reg [7:0] RX_data_r;


//******************************************************
//		RX_1,RX_2
//******************************************************
always@(posedge clk or negedge RSTn)begin
	if(!RSTn)begin
		RX_1<=1'b0;
		RX_2<=1'b0;
	end
	else begin
		RX_1<=RX;
		RX_2<=RX_1;
	end
end

assign RX_start = ((~RX_1&RX_2)&&(cnt==32'd0))?1'b1:1'b0;
//******************************************************
//		cnt
//******************************************************
always@(posedge clk or negedge RSTn)begin
	if(!RSTn)
		cnt<=32'd0;
	else if(cnt==32'd0&&RX_start==1'b1)		//平常cnt等于0,当检测到RX_start脉冲,就开始计数,一直计10个UART比特位发送时长(根据波特率不同,cnt计数最大值也不同)
		cnt<=32'd1;
	else if(cnt!=32'd0&&cnt=cnt_max-bit_0_5_cnt)
		cnt<=32'd0;
	else 
		cnt<=cnt;	
end
//******************************************************
//		RX_data_r
//******************************************************
always@(posedge clk or negedge RSTn)begin
	if(!RSTn)
		RX_data_r<=8'd0;
	else if(cnt==bit1_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else if(cnt==bit2_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else if(cnt==bit3_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else if(cnt==bit4_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else if(cnt==bit5_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else if(cnt==bit6_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else if(cnt==bit7_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else if(cnt==bit8_OK)
		RX_data_r<={RX,RX_data_r[7:1]};
	else
		RX_data_r<=RX_data_r;
end
//******************************************************
//		RX_data	RX_OK
//******************************************************
always@(posedge clk or negedge RSTn)begin
	if(!RSTn)
		RX_data<=8'd0;
	else if(cnt==bitstop_OK)
		RX_data<=RX_data_r;
	else
		RX_data<=RX_data;
end

always@(posedge clk or negedge RSTn)begin
	if(!RSTn)
		RX_OK<=1'b0;
	else if(cnt==bitstop_OK)
		RX_OK<=1'b1;
	else
		RX_OK<=1'b0;
end






endmodule

二、发送模块uart_tx.v

        发射模块的程序非常简单,就是在对应的时刻拉高或者拉低电平,达到模拟TX信号线的目的。  FPGA实现UART协议的接收与发送_第3张图片

 uart_rx.v模块输入输出示意图

FPGA实现UART协议的接收与发送_第4张图片

        TX_start是个单周期脉冲,是外界给的,当有TX_start单脉冲时,发送TX_data寄存器中的数据。

  1. 进入模块,只有当TX_start=1时,才将TX_data寄存到TX_data_r。其余时刻保持刚刚寄存下来的值。
  2. cnt是时间轴,什么时刻发送第几位,都是根据cnt判断的。最小是0,最大是cnt_max。平时cnt是0,只有当TX_start到来时cnt才开始累加,一直累加到cnt_max(10个完整的数据位占用的等长的clk周期个数)
  3. TX。0~cnt_max平均分成10份,对应着10个数据位,以次发送(改变电平)。
  4. TX_end。cnt==cnt_max时,产生TX_end单脉冲,表示完成一个字节的传输。
  5. uart_tx.v程序如下:
module uart_tx#(
	parameter	OSC 		= 50_000_000,
	parameter	BPS 		= 9600,
	parameter	bit_1_cnt	= 5208,	//bit_1_cnt = OSC/BPS
	parameter 	bit_0_5_cnt	= 2604,
	parameter	cnt_max 	= 52083	//cnt_max = bit_1_cnt*10
)(
	input			clk,
	input			RSTn,
	//
	input [7:0]		TX_data,	//要发送的数据
	input			TX_start,	//发送开始单脉冲使能。TX_data和TX_start同步到来
	output reg		TX,
	output			TX_end
);

//******************************************************
//		parameter
//******************************************************
localparam	bit1_send = bit_1_cnt;
localparam	bit2_send = bit_1_cnt+bit_1_cnt;
localparam	bit3_send = bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit4_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit5_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit6_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit7_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit8_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bitstop_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;

//------------------TX_data_r-----------------------------
reg [7:0] TX_data_r;	//每次在TX_start到来时,寄存一下要发送的数据TX_data给TX_data_r寄存器

//------------------cnt-----------------------------
reg [31:0] cnt;


//******************************************************
//		TX_data_r
//******************************************************
always@(posedge clk or negedge RSTn)begin
	if(!RSTn)
		TX_data_r<=8'd0;
	else if(TX_start==1'b1)
		TX_data_r<=TX_data;
	else
		TX_data_r<=TX_data_r;
end
//******************************************************
//		cnt
//******************************************************
always@(posedge clk or negedge RSTn)begin
	if(!RSTn)
		cnt<=32'd0;
	else if(cnt==32'd0&&TX_start==1'b1)		//平时cnt=0,当TX_start到来时cnt开始累加1,一直加到对应波特率下10个比特位全部发送完
		cnt<=32'd1;
	else if(cnt!=32'd0&&cnt=cnt_max)
		cnt<=32'd0;
	else
		cnt<=cnt;
end
//******************************************************
//		TX
//******************************************************
always@(posedge clk or negedge RSTn)begin
	if(!RSTn)
		TX<=1'b1;
	else if(cnt>=32'd1&&cnt=bit1_send&&cnt=bit2_send&&cnt=bit3_send&&cnt=bit4_send&&cnt=bit5_send&&cnt=bit6_send&&cnt=bit7_send&&cnt=bit8_send&&cnt=bitstop_send&&cnt

 

 

你可能感兴趣的:(fpga开发,单片机,嵌入式硬件)