FPGA实现简单的串口通信

1.根据功能需要设计模块,自上而下不断细化,确定端口、子模块、连线,最好就是画图出来,这里是设计的是把收到的串口数据重新发送出去

FPGA实现简单的串口通信_第1张图片

FPGA实现简单的串口通信_第2张图片

2.根据自己画的图,转换成verilo代码,并描述出来

//---------------------------------------------------------------------------
//--	文件名		:	Uart_Test_Top.v
//--	作者		:	LIZIYI
//--	描述		:	串口收发测试顶层文件
//--	修订历史	:	2018-7-23
//---------------------------------------------------------------------------
module	Uart_Test
(
	//输入端口
	RST,CLK,UART_RX,
	//输出端口
	UART_TX
);

//---------------------------------------------------------------------------
//--	外部端口声明
//---------------------------------------------------------------------------
input					RST;				//复位
input					CLK;				//时钟50M
input					UART_RX;			//串口接收
output				UART_TX;			//串口发送

//---------------------------------------------------------------------------
//--	内部端口声明
//---------------------------------------------------------------------------
wire		[7:0]		data;				//八位数据线
wire					tx_start;		//串口发送标志
wire					rx_bps_start;	//Rx波特率启动
wire					rx_bps_flag;	//Rx读取标志
wire					tx_bps_start;	//Tx波特率启动
wire					tx_bps_flag;	//Tx读取标志

//---------------------------------------------------------------------------
//--	逻辑功能实现	
//---------------------------------------------------------------------------
//例化RX波特率模块
Bps_Module			Rx_Bps_Module_Init
(
	.CLK				(CLK),
	.RST				(RST),
	.bps_start		(rx_bps_start),
	.bps_flag		(rx_bps_flag)
);

//例化TX波特率模块
Bps_Module			Tx_Bps_Module_Init
(
	.CLK				(CLK),
	.RST				(RST),
	.bps_start		(tx_bps_start),
	.bps_flag		(tx_bps_flag)
);

//例化Rx模块
Rx_Module			Rx_Module_Init
(
	.CLK				(CLK),
	.RST				(RST),
	.UART_RX			(UART_RX),
	.rx_bps_start	(rx_bps_start),
	.rx_bps_flag	(rx_bps_flag),
	.tx_start		(tx_start),
	.out_rx_data	(data)
);

//例化Tx模块
Tx_Module			Tx_Module_Init
(
	.CLK				(CLK),
	.RST				(RST),
	.UART_TX			(UART_TX),
	.tx_bps_start	(tx_bps_start),
	.tx_bps_flag	(tx_bps_flag),
	.tx_start		(tx_start),
	.out_tx_data	(data)
);

endmodule






//---------------------------------------------------------------------------
//--	文件名		:	Bps_Module.v
//--	作者		:	LIZIYI
//--	描述		:	串口波特率发生器,当bps_start 为1的时候计数
//--	修订历史	:	2018-7-23
//---------------------------------------------------------------------------

module	Bps_Module
(
	//输入端口
	CLK,RST,bps_start,
	//输出端口
	bps_flag	
);

//---------------------------------------------------------------------------
//--	外部端口声明
//---------------------------------------------------------------------------
input			CLK;						//50M时钟
input			RST;						//复位
input			bps_start;				//rx或者tx给波特率发生器的开始信号
output		bps_flag;				//返回给波特率发生器的数据位中间时刻的标志信号

//---------------------------------------------------------------------------
//--	内部端口声明
//---------------------------------------------------------------------------
reg	[8:0]		time_cnt;			//用来计时,每个比特
reg	[8:0]		time_cnt_n;
reg				bps_flag;			//用来判断是否到达每个比特的中间时刻
reg				bps_flag_n;

//设置定时器的时间   晶振为50Mhz  50M/115200=434
parameter	SET_TIME_ONEBit = 9'd434;		//每个比特需要计数434次
parameter	SET_TIME_HALFBit = 8'd217;		//半个比特就需要计数217次

//---------------------------------------------------------------------------
//--	逻辑功能实现	
//---------------------------------------------------------------------------
//time_cnt 实现计时
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		time_cnt <= 1'b0;
	else
		time_cnt <= time_cnt_n;
end


//自己写的代码
//always @ (*)
//begin
//	if(time_cnt == SET_TIME_ONEBit)
//		time_cnt_n = 1'b0;
//	else if(bps_start)
//		time_cnt_n = time_cnt + 1'b1;
//	else
//		time_cnt_n = time_cnt;
//end

//例程的代码
always @ (*)
begin
	if((time_cnt == SET_TIME_ONEBit) || (!bps_start))   //当计满一位比特的时候,或者还没有收到开始信号的时候,计数值就为0
		time_cnt_n = 1'b0;
	else
		time_cnt_n = time_cnt + 1'b1;			//别的时候就+1	
end






//---------------------------------------------------------------------------
//--	文件名		:	Rx_Module.v
//--	作者		:	LIZIYI
//--	描述		:	串口RX模块
//--	修订历史	:	2018-7-23
//---------------------------------------------------------------------------

module	Rx_Module
(
	//输入端口
	CLK,RST,UART_RX,rx_bps_flag,
	//输出端口
	rx_bps_start,tx_start,out_rx_data
);

//---------------------------------------------------------------------------
//--	外部端口声明
//---------------------------------------------------------------------------
input						CLK;						//50M时钟
input						RST;						//复位
input						UART_RX;					//串口RX接收端
input						rx_bps_flag;			//收到来自波特率发生器,每比特中间时刻的标志
output					rx_bps_start;			//给波特率发生器发送的开始信号
output					tx_start;				//给tx模块发送的,串口发送信号
output	[7:0]			out_rx_data;			//收到的每帧串口数据,并行储存在这个端口

//---------------------------------------------------------------------------
//--	内部端口声明
//---------------------------------------------------------------------------
reg	[1:0]		detect_reg;						//检测RX跳变
wire	[1:0]		detect_reg_n;
reg				negedge_reg;					//判断跳变是否为下降沿
reg				negedge_reg_n;
reg	[7:0]		shift_reg;						//移位寄存器,把Rx的信号读取进来,因为串口先发送的信号为低位,把刚读到信号放在移位寄存器的最高位,然后往低位移动
reg	[7:0]		shift_reg_n;
reg	[3:0]		bit_cnt;							//记录接收到的bit位
reg	[3:0]		bit_cnt_n;
reg	[7:0]		out_rx_data;					//收到的每帧串口数据,并行储存在这个reg
reg	[7:0]		out_rx_data_n;


//---------------------------------------------------------------------------
//--	逻辑功能实现	
//---------------------------------------------------------------------------
//detect_reg
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		detect_reg <= 1'b0;
	else
		detect_reg	<= detect_reg_n;
end

assign detect_reg_n = {detect_reg[0],UART_RX};		//detect_reg[0]就是上一时刻的rx状态


//negedge_reg
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		negedge_reg <= 1'b0;
	else
		negedge_reg <= negedge_reg_n;
end

always @ (*)
begin
	if(detect_reg == 2'b10)									//如果为下降沿,置一
		negedge_reg_n = 1'b1;
	else if(bit_cnt == 4'd9)								//如果读取数据(读取了开始信号和八位数据)就置0
		negedge_reg_n = 1'b0;
	else
		negedge_reg_n = negedge_reg;
end

assign rx_bps_start = negedge_reg;						//当读取到下降沿的时候波特率开始信号置一
assign tx_start = !negedge_reg;							//当读取完了八位数据位,tx才发送

//bit_cnt
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		bit_cnt <= 1'b0;
	else
		bit_cnt <= bit_cnt_n;
end

always @ (*)
begin
	if(negedge_reg && rx_bps_flag)						//每次读到中间时刻标志,位数+1
		bit_cnt_n = bit_cnt + 1'b1;
	else if(bit_cnt == 4'd9)								//计满9次归0
		bit_cnt_n = 1'b0;
	else
		bit_cnt_n = bit_cnt;
end


//shift_reg
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		shift_reg <= 1'b0;
	else
		shift_reg <= shift_reg_n;
end

always @ (*)
begin
	if(rx_bps_flag)
		shift_reg_n = {UART_RX,shift_reg[7:1]};  //移位寄存器,把Rx的信号读取进来,因为串口先发送的信号为低位,把刚读到信号放在移位寄存器的最高位,然后往低位移动
	else
		shift_reg_n = shift_reg;
end

//out_rx_data
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		out_rx_data <= 1'b0;
	else
		out_rx_data <= out_rx_data_n;
end

always @ (*)
begin
	if(bit_cnt == 4'd9)								//当读取玩数据的时候,就把数据存储这个寄存器里
		out_rx_data_n = shift_reg;
	else
		out_rx_data_n = out_rx_data;
end
	
endmodule





//---------------------------------------------------------------------------
//--	文件名		:	Tx_Module.v
//--	作者		:	LIZIYI
//--	描述		:	串口Tx部分
//--	修订历史	:	2018-7-23
//---------------------------------------------------------------------------

module	Tx_Module
(
	//输入端口
	CLK,RST,tx_bps_flag,tx_start,out_tx_data,
	//输出端口
	UART_TX,tx_bps_start
);

//---------------------------------------------------------------------------
//--	外部端口声明
//---------------------------------------------------------------------------
input				CLK;								//50M时钟
input				RST;								//复位
input				tx_bps_flag;					//波特率发生器发送给tx的每bit中间时刻
input 			tx_start;						//rx接收数据完毕,给tx发送的信号
input	 [7:0]	out_tx_data;					//需要发送的数据
output			UART_TX;							//串口tx接口
output			tx_bps_start;					//tx给波特率发生器发送的开始信号


//---------------------------------------------------------------------------
//--	内部端口声明
//---------------------------------------------------------------------------
reg	[1:0]		detect_reg;						//检测跳变
wire	[1:0]		detect_reg_n;
reg				posedge_reg;					//判断跳变是否为上升沿
reg				posedge_reg_n;
reg	[7:0]		tx_temp_data;					//将要发送的数据存储在这个寄存器
reg	[7:0]		tx_temp_data_n;
reg				UART_TX;							//串口tx
reg				UART_TX_N;
reg	[3:0]		bit_cnt;							//记录发送的bit位
reg	[3:0]		bit_cnt_n;


//---------------------------------------------------------------------------
//--	逻辑功能实现	
//---------------------------------------------------------------------------
//detect_reg
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		detect_reg <= 1'b0;
	else
		detect_reg <= detect_reg_n;
end

assign detect_reg_n = {detect_reg[0],tx_start};    //detect_reg[0]就是上一时刻的rx状态

//posedge_reg
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		posedge_reg <= 1'b0;
	else
		posedge_reg <= posedge_reg_n;
end

always @ (*)
begin
	if(detect_reg == 2'b01)				//如果为上升沿置一
		posedge_reg_n = 1'b1;
	else if(bit_cnt == 4'd10)			//如果发送完成(起始位,8位数据位,停止位)置零
		posedge_reg_n = 1'b0;
	else
		posedge_reg_n = posedge_reg;
end


assign tx_bps_start = posedge_reg;		//如果读取到上升沿,给波特率发送器发送开始信号


//tx_temp_data
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		tx_temp_data <= 1'b0;
	else
		tx_temp_data <= tx_temp_data_n;
end

always @ (*)
begin
	if(posedge_reg)
		tx_temp_data_n =	out_tx_data;		//读取到上升沿那么保存要发送的数据
	else
		tx_temp_data_n = tx_temp_data;
end

//bit_cnt
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		bit_cnt = 1'b0;
	else
		bit_cnt = bit_cnt_n;
end

always @ (*)
begin
	if(posedge_reg && tx_bps_flag)			//记录发送的位数,每到一比特加一
		bit_cnt_n = bit_cnt + 1'b1;
	else if(bit_cnt == 4'd10)					//发送完了一帧数据归0
		bit_cnt_n = 1'b0;
	else
		bit_cnt_n = bit_cnt;
end

//UART_TX
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		UART_TX = 1'b1;
	else
		UART_TX = UART_TX_N;
end

always @ (*)
begin
	if(posedge_reg)
		case(bit_cnt)
		4'd0: UART_TX_N = 1'b0;								//起始位拉低
		4'd1: UART_TX_N = tx_temp_data[0];				//八位数据位
		4'd2: UART_TX_N = tx_temp_data[1];
		4'd3: UART_TX_N = tx_temp_data[2];
		4'd4: UART_TX_N = tx_temp_data[3];
		4'd5: UART_TX_N = tx_temp_data[4];
		4'd6: UART_TX_N = tx_temp_data[5];
		4'd7: UART_TX_N = tx_temp_data[6];
		4'd8: UART_TX_N = tx_temp_data[7];
		4'd9: UART_TX_N = 1'b1;								//停止位拉高
		default UART_TX_N = 1'b1;
		endcase
	else
		UART_TX_N = UART_TX;
end

endmodule

3.编译,分配管脚,下载验证,并查错修改,有条件还可以仿真

4.RTLFPGA实现简单的串口通信_第3张图片

FPGA实现简单的串口通信_第4张图片

FPGA实现简单的串口通信_第5张图片

FPGA实现简单的串口通信_第6张图片

你可能感兴趣的:(FPGA,Verilog)