FPGA 串口通讯

 

 

module Baud #
(
parameter				BPS_PARA = 1250 //12MHz时钟时参数1250对应9600的波特率,12000000/9600
)
(
input					clk,		//系统时钟
input					rst_n,		//系统复位,低有效
input					bps_en,		//接收或发送时钟使能
output	reg				bps_clk		//接收或发送时钟输出
);	

reg				[12:0]	cnt;
//计数器计数满足波特率时钟要求
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
		cnt <= 1'b0;
	else if((cnt >= BPS_PARA-1)||(!bps_en)) //当时钟信号不使能(bps_en为低电平)时,计数器清零并停止计数
		cnt <= 1'b0;	                    //当时钟信号使能时,计数器对系统时钟计数,周期为BPS_PARA个系统时钟周期
	else 
		cnt <= cnt + 1'b1;
end
	
//产生相应波特率的时钟节拍,接收模块将以此节拍进行UART数据接收
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) 
		bps_clk <= 1'b0;
	else if(cnt == (BPS_PARA>>1)) //右移一位等于除以2,终值BPS_PARA为数据更替点,中值数据稳定,做采样点
		bps_clk <= 1'b1;	
	else 
		bps_clk <= 1'b0;
end

endmodule

  

 

module Uart_Tx
(
input					clk,			//系统时钟 12MHz
input					rst_n,			//系统复位,低有效

output	reg				bps_en,			//发送时钟使能
input					bps_clk,		//发送时钟输入

input					tx_data_valid,	//发送数据有效脉冲
input			[7:0]	tx_data_in,		//要发送的数据
output	reg				uart_tx			//UART发送输出
);

reg				[3:0]	num;
reg				[9:0]	tx_data_r;	//融合了起始位和停止位的数据
//驱动发送数据操作
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		bps_en <= 1'b0;
		tx_data_r <= 10'd0;
	end else if(tx_data_valid && (!bps_en))begin	
		bps_en <= 1'b1;		//当检测到接收时钟使能信号的下降沿,表明接收完成,需要发送数据,使能发送时钟使能信号
		tx_data_r <= {1'b1,tx_data_in,1'b0};	
	end else if(num==4'd10) begin	
		bps_en <= 1'b0;		//一次UART发送需要10个时钟信号,然后结束
	end
end

//当处于工作状态中时,按照发送时钟的节拍发送数据
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		num <= 1'b0;
		uart_tx <= 1'b1;
	end else if(bps_en) begin
		if(bps_clk) begin
			num <= num + 1'b1;
			uart_tx <= tx_data_r[num];
		end else if(num>=4'd10) 
			num <= 4'd0;	
	end
end

endmodule

  

module Uart_Rx
(
input					clk,			//系统时钟 12MHz
input					rst_n,			//系统复位,低有效

output	reg				bps_en,			//接收时钟使能
input					bps_clk,		//接收时钟输入

input					uart_rx,		//UART接收输入
output	reg				rx_data_valid,	//接收数据有效脉冲
output	reg		[7:0]	rx_data_out		//接收到的数据
);	

reg	uart_rx0,uart_rx1,uart_rx2;	
//多级延时锁存去除亚稳态
always @ (posedge clk) begin
	uart_rx0 <= uart_rx;
	uart_rx1 <= uart_rx0;
	uart_rx2 <= uart_rx1;
end

//检测UART接收输入信号的下降沿
wire	neg_uart_rx = uart_rx2 & ~uart_rx1;	
		
reg				[3:0]	num;			
//接收时钟使能信号的控制
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n)
		bps_en <= 1'b0;
	else if(neg_uart_rx && (!bps_en))	//当空闲状态(bps_en为低电平)时检测到UART接收信号下降沿,进入工作状态(bps_en为高电平),控制时钟模块产生接收时钟
		bps_en <= 1'b1;		
	else if(num==4'd9)		            //当完成一次UART接收操作后,退出工作状态,恢复空闲状态
		bps_en <= 1'b0;			
end

reg				[7:0]	rx_data;
//当处于工作状态中时,按照接收时钟的节拍获取数据
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		num <= 4'd0;
		rx_data <= 8'd0;
	end else if(bps_en) begin	
		if(bps_clk) begin			
			num <= num + 1'b1;
			if(num<=4'd8) rx_data[num-1] <= uart_rx1; //先接受低位再接收高位,8位有效数据
		end else if(num == 4'd9) begin		          //完成一次UART接收操作后,将获取的数据输出
			num <= 4'd0;				
		end
	end else begin
		num <= 4'd0;
	end
end

//将接收的数据输出,同时控制输出有效信号产生脉冲
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		rx_data_out <= 8'd0;
		rx_data_valid <= 1'b0;
	end else if(num == 4'd9) begin	
		rx_data_out <= rx_data;
		rx_data_valid <= 1'b1;
	end else begin
		rx_data_out <= rx_data_out;
		rx_data_valid <= 1'b0;
	end
end

endmodule

  

 

module Uart_Bus #
(
parameter				BPS_PARA = 1250 	//12MHz时钟时参数1250对应9600的波特率
)
(
input					clk,			//系统时钟 12MHz
input					rst_n,			//系统复位,低有效

input					uart_rx,		//UART接收输入
output					rx_data_valid,	//接收数据有效脉冲
output			[7:0]	rx_data_out		//接收到的数据

//input					tx_data_valid,	//发送数据有效脉冲
//input			[7:0]	tx_data_in,		//要发送的数据
//output				uart_tx			//UART发送输出
);	
	
/////////////////////////////////UART接收功能模块例化////////////////////////////////////

wire					bps_en_rx,bps_clk_rx;

//UART接收波特率时钟控制模块 例化
Baud #
(
.BPS_PARA				(BPS_PARA		)
)
Baud_rx
(	
.clk					(clk			),	//系统时钟 12MHz
.rst_n					(rst_n			),	//系统复位,低有效
.bps_en					(bps_en_rx		),	//接收时钟使能
.bps_clk				(bps_clk_rx		)	//接收时钟输出
);

//UART接收数据模块 例化
Uart_Rx Uart_Rx_uut
(
.clk					(clk			),	//系统时钟 12MHz
.rst_n					(rst_n			),	//系统复位,低有效

.bps_en					(bps_en_rx		),	//接收时钟使能
.bps_clk				(bps_clk_rx		),	//接收时钟输入

.uart_rx				(uart_rx		),	//UART接收输入
.rx_data_valid			(rx_data_valid	),	//接收数据有效脉冲
.rx_data_out			(rx_data_out	)	//接收到的数据
);
	
/////////////////////////////////UART发送功能模块例化////////////////////////////////////
/*
wire					bps_en_tx,bps_clk_tx;

//UART发送波特率时钟控制模块 例化
Baud #
(
.BPS_PARA				(BPS_PARA		)
)
Baud_tx
(
.clk					(clk			),	//系统时钟 12MHz
.rst_n					(rst_n			),	//系统复位,低有效
.bps_en					(bps_en_tx		),	//发送时钟使能
.bps_clk				(bps_clk_tx		)	//发送时钟输出
);

//UART发送数据模块 例化
Uart_Tx Uart_Tx_uut
(
.clk					(clk			),	//系统时钟 12MHz
.rst_n					(rst_n			),	//系统复位,低有效

.bps_en					(bps_en_tx		),	//发送时钟使能
.bps_clk				(bps_clk_tx		),	//发送时钟输入

.tx_data_valid			(tx_data_valid	),	//发送数据有效脉冲
.tx_data_in				(tx_data_in		),	//要发送的数据
.uart_tx				(uart_tx		)	//UART发送输出
);
*/
endmodule

  

 

 

 

posted @ 2022-09-29 08:54  xiaoberber  阅读(71)  评论(0编辑  收藏  举报