FPGA串口接收、发送数据处理模块

该模块处理接收到的数据,并对数据拼接,解析成读写位,地址,写数据。对axi_master读回来的数据进行处理,分成4byte数据经过串口发送都上位机。
下面是该模块的顶层,包含两个子模块,接收处理模块、发送处理模块。

/***************************************************
*	Module Name		:	byte_matching	   
*	Engineer		:	Huangruigui
*	Target Device	:	
*	Tool versions	:	
*	Create Date		:
*	Revision		:	v1.0
*	Description		:  
**************************************************/
module	byte_matching #(
	parameter 	M_AXI_ADDR_WIDTH 		= 8'd32,
	parameter	M_AXI_DATA_WIDTH 		= 8'd32,
	parameter	RX_TOTAL_BYTE	 		= 8'd9,				//	串口接收到9byte数据开始工作	
	parameter	TX_TOTAL_BYTE			= 8'd4,				//	串口发送4byte数据给上位机
	parameter	WRITE_BIT				= 5'd1,				//	设置最高位1为写操作
	parameter	READ_BIT				= 5'd2
)(
	input	wire						sys_clk,
	input	wire						sys_rst_n,
	//	uart_rx
	input	wire						rx_done,
	input	wire [7:0]					rx_data,
	//	uart->axi_master
	output	wire						uart_write,
	output	wire [M_AXI_ADDR_WIDTH-1:0]	uart_write_addr,
	output	wire [M_AXI_DATA_WIDTH-1:0]	uart_write_data,
	output	wire 						uart_read,
	output	wire [M_AXI_ADDR_WIDTH-1:0]	uart_read_addr,
	input	wire						uart_tx_en,
	input	wire [M_AXI_DATA_WIDTH-1:0]	uart_tx_data,
	//	uart_tx
	output	wire						tx_en,
	output	wire [7:0]					tx_data,
	input	wire						tx_done
);

	rx_conduct #(
		.M_AXI_ADDR_WIDTH	(	M_AXI_ADDR_WIDTH),
		.M_AXI_DATA_WIDTH	(	M_AXI_DATA_WIDTH),
		.RX_TOTAL_BYTE		(	RX_TOTAL_BYTE	),
		.WRITE_BIT			(	WRITE_BIT		),
		.READ_BIT			(	READ_BIT		)
	)rx_conduct(
		.sys_clk			(	sys_clk			),
		.sys_rst_n			(	sys_rst_n		),
		.rx_done			(	rx_done			),
		.rx_data			(	rx_data			),
		.uart_write			(	uart_write		),
		.uart_write_addr	(	uart_write_addr	),
		.uart_write_data	(	uart_write_data	),
		.uart_read			(	uart_read		),
		.uart_read_addr		(	uart_read_addr	)
	);

	tx_conduct #(
		.M_AXI_ADDR_WIDTH	(	M_AXI_ADDR_WIDTH),
		.M_AXI_DATA_WIDTH	(	M_AXI_DATA_WIDTH),
		.TX_TOTAL_BYTE		(	TX_TOTAL_BYTE	)
	)tx_conduct(
		.sys_clk			(	sys_clk			),
		.sys_rst_n			(	sys_rst_n		),
		.uart_tx_en			(	uart_tx_en		),
		.uart_tx_data		(	uart_tx_data	),
		.tx_en				(	tx_en			),
		.tx_data			(	tx_data			),
		.tx_done			(	tx_done			)
	);

endmodule
//***************文件结束**************************

先给大家看下仿真时序
在这里插入图片描述

从图中,当发送的第一个字节是01,发送完一串数据后,uart_write会产生一个高脉冲,同时地址,数据总线出现要控制的数据。当发送的第一个字节是02,发送完一串数据后,uart_read会产生一个高脉冲。
使能一次uart_tx_en,串口在发送完4次数据后,tx_en信号不在使能。
符合预期效果。
下面对接收模块进行编写

/***************************************************
*	Module Name		:	rx_conduct	   
*	Engineer		:	Huangruigui
*	Target Device	:	
*	Tool versions	:	
*	Create Date		:
*	Revision		:	v1.0
*	Description		:  
**************************************************/
module rx_conduct #(
	parameter 	M_AXI_ADDR_WIDTH 		= 8'd32,
	parameter	M_AXI_DATA_WIDTH 		= 8'd32,
	parameter	RX_TOTAL_BYTE	 		= 8'd9,				//	串口接收到9byte数据开始工作	
	parameter	WRITE_BIT				= 5'd1,				//	设置最高位1为写操作
	parameter	READ_BIT				= 5'd2				//	设置最高位2为读操作
)(
	input	wire						sys_clk,
	input	wire						sys_rst_n,
	//	uart_rx
	input	wire						rx_done,
	input	wire [7:0]					rx_data,
	//	uart->axi_master
	output	reg							uart_write,
	output	reg [M_AXI_ADDR_WIDTH-1:0]	uart_write_addr,
	output	reg	[M_AXI_DATA_WIDTH-1:0]	uart_write_data,
	output	reg	 						uart_read,
	output	reg [M_AXI_ADDR_WIDTH-1:0]	uart_read_addr
);

	//	parameter define
	localparam	HIGH_RW_ADDR = RX_TOTAL_BYTE*8-1,
				LOW_RW_ADDR  = RX_TOTAL_BYTE*8-8;
	localparam	HIGH_ADDR	 = (RX_TOTAL_BYTE-1)*8-1,
				LOW_ADDR	 = (RX_TOTAL_BYTE-5)*8;
	localparam	HIGH_DATA	 = (RX_TOTAL_BYTE-5)*8-1;
	
	//	reg define
	reg	[5:0]					rx_done_cnt;	//	数据接收完成计数器
	reg	[RX_TOTAL_BYTE*8-1:0]	uart_rx_data;	//	串口接收到一帧数据
	
	//	wire define
	wire 						one_frame_done;			//	一帧数据接收完成
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
		begin	
			uart_write_addr <= 0;
			uart_read_addr <= 0;
			uart_write_data <= 0;
		end 
		else if(uart_write)
		begin
			uart_write_addr <= uart_rx_data[HIGH_ADDR:LOW_ADDR];
			uart_write_data <= uart_rx_data[HIGH_DATA:0];
		end 
		else if(uart_read)
			uart_read_addr <= uart_rx_data[HIGH_ADDR:LOW_ADDR];
		else 
		begin
			uart_write_addr <= uart_write_addr;
			uart_read_addr <= uart_read_addr;
			uart_write_data <= uart_write_data;
		end 
	end 	
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
			rx_done_cnt <= 6'd0;
		else if(rx_done_cnt >= RX_TOTAL_BYTE)
			rx_done_cnt <= 6'd0;
		else if(rx_done)
			rx_done_cnt <= rx_done_cnt + 1'b1;
	end 
	
	assign	one_frame_done = (rx_done_cnt == RX_TOTAL_BYTE);
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
			uart_rx_data <= {(RX_TOTAL_BYTE*8-1){1'b0}};
		else if(rx_done)
			uart_rx_data <= {uart_rx_data[(RX_TOTAL_BYTE-1)*8-1:0],rx_data};
	end	
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
		begin
			uart_write <= 0;
			uart_read <= 0;
		end 
		else if(one_frame_done)
		begin
			if(uart_rx_data[HIGH_RW_ADDR:LOW_RW_ADDR] == WRITE_BIT)
				uart_write <= 1;
			if(uart_rx_data[HIGH_RW_ADDR:LOW_RW_ADDR] == READ_BIT)
				uart_read  <= 1;
		end 
		else
		begin
			uart_write <= 0;
			uart_read <= 0;
		end 
	end 

endmodule
//*************文件结束***************************

接着对发送模块进行处理

/***************************************************
*	Module Name		:	tx_conduct	   
*	Engineer		:	Huangruigui
*	Target Device	:	
*	Tool versions	:	
*	Create Date		:
*	Revision		:	v1.0
*	Description		:  
**************************************************/
/***************************************************
*	Module Name		:	tx_conduct	   
*	Engineer		:	Huangruigui
*	Target Device	:	
*	Tool versions	:	
*	Create Date		:
*	Revision		:	v1.0
*	Description		:  
**************************************************/
module tx_conduct #(
	parameter 	M_AXI_ADDR_WIDTH 		= 8'd32,
	parameter	M_AXI_DATA_WIDTH 		= 8'd32,
	parameter	TX_TOTAL_BYTE			= 8'd4				//	串口发送4byte数据给上位机
)(
	input	wire						sys_clk,
	input	wire						sys_rst_n,
	input	wire						uart_tx_en,
	input	wire [M_AXI_DATA_WIDTH-1:0]	uart_tx_data,
	//	uart_tx
	output	reg							tx_en,
	output	reg	 [7:0]					tx_data,
	input	wire						tx_done	
);

	//	parameter define
	localparam	HIGH_ADDR = TX_TOTAL_BYTE*8-1,
				LOW_ADDR  = (TX_TOTAL_BYTE-1)*8;

	//	reg define
	reg	[4:0]					tx_en_cnt;
	reg							tx_done_t;
	reg	[M_AXI_DATA_WIDTH-1:0]	uart_tx_data_t;
	
	//	wrie define
	wire						uart_tx_done;
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
			tx_en_cnt <= 5'd0;
		else if(tx_en_cnt == TX_TOTAL_BYTE)
			tx_en_cnt <= 5'd0;
		else if(tx_done)
			tx_en_cnt <= tx_en_cnt + 1'b1;
	end 
	
	assign	uart_tx_done = (tx_en_cnt == TX_TOTAL_BYTE);
	
	always@(posedge sys_clk)					//	对tx_done打一拍
		tx_done_t <= tx_done;
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
		begin
			tx_en <= 0;
		end 
		else if(uart_tx_en) 
			tx_en <= 1;
		else if(tx_done_t)
		begin
			if(uart_tx_done)
				tx_en <= 0;
			else 
				tx_en <= 1;
		end 
		else
			tx_en <= 0;
	end 
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
			uart_tx_data_t <= 0;
		else if(uart_tx_en)
			uart_tx_data_t <= uart_tx_data;
		else if(uart_tx_done)
			uart_tx_data_t <= 0;
		else if(tx_done)
			uart_tx_data_t <= uart_tx_data_t << 8;
	end 

	/*
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
			tx_data <= 0;
		else 
		begin
			case(tx_done_cnt)
				0:tx_data <= uart_tx_data_t[31:24];
				1:tx_data <= uart_tx_data_t[23:16];
				2:tx_data <= uart_tx_data_t[15:8];
				3:tx_data <= uart_tx_data_t[7:0];
				default:tx_data <= tx_data;
			endcase
		end 
	end 
	*/
	
	always@(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)
			tx_data <= 0;
		else if(tx_en)			
			tx_data <= uart_tx_data_t[HIGH_ADDR:LOW_ADDR];
	end 

endmodule
//********************文件结束***********************

在这个发送模块中,我用的是每次发送完,对要发送的数据左移8位,下一次发送高8位的数据,这样做的好处是可以拓展模块发送的数据而不用修改代码,如果是用case语句的话,会出现穷举现象,不能很好的适配。
仿真测试文件

/***************************************************
*	Module Name		:	uart2axi_master_logic_tb	   
*	Engineer		:	Huangruigui
*	Target Device	:	
*	Tool versions	:	
*	Create Date		:
*	Revision		:	v1.0
*	Description		:  
**************************************************/
`timescale 1ns/1ns
module	uart2axi_master_logic_tb;

	//	parameter define
	parameter 	M_AXI_ADDR_WIDTH 		= 8'd32;
	parameter	M_AXI_DATA_WIDTH 		= 8'd32;
	parameter	BAUD_SET		 		= 16'd10416;		//	波特率设置,默认9600
	parameter	RX_TOTAL_BYTE	 		= 8'd9;				//	串口接收到9byte数据开始工作	
	parameter	TX_TOTAL_BYTE			= 8'd4;				//	串口发送4byte数据给上位机
	parameter	WRITE_BIT				= 5'd1;				//	设置最高位1为写操作
	parameter	READ_BIT				= 5'd2;

	reg			sys_clk;
	reg			sys_rst_n;
	reg			tx_en;
	reg	[7:0]	tx_data;
	reg								uart_tx_en      ;
	reg	 [M_AXI_DATA_WIDTH-1:0]		uart_tx_data	;

	wire							tx_done			;
	wire							uart_tx			;
	wire							uart_write      ;
	wire [M_AXI_ADDR_WIDTH-1:0]		uart_write_addr ;
	wire [M_AXI_DATA_WIDTH-1:0]		uart_write_data	;
	wire							uart_read       ;
	wire [M_AXI_ADDR_WIDTH-1:0]		uart_read_addr  ;
	wire							uart_rx        	;

	initial sys_clk = 1;
	always #5 sys_clk = ~sys_clk;
	
	initial begin
		sys_rst_n = 0;
		tx_en = 0;
		tx_data = 0;
		uart_tx_en = 0;
		uart_tx_data = 0;
		#201;
		sys_rst_n = 1;
		#20;
		@(posedge sys_clk)
		#100;
		tx_data = 0;				//	测试写操作
		repeat(9)
		begin
			tx_en = 1;
			tx_data = tx_data + 1;
			#10;
			tx_en = 0;
			wait(tx_done);
			#100;
		end 
		#100;
		if(uart_write_addr == 32'h02030405)
			$display("test success");
		else
			$display("test fail");
		#1000;
		
		tx_data = 1;				//	测试读操作
		repeat(9)
		begin
			tx_en = 1;
			tx_data = tx_data + 1;
			#10;
			tx_en = 0;
			wait(tx_done);
			#100;
		end 
		if(uart_read_addr == 32'h03040506)
			$display("test success");
		else
			$display("test fail");
		#1000;
		
		uart_tx_en = 1;
		uart_tx_data = 32'h12345678;
		#10;
		uart_tx_en = 0;
		wait(uart2axi_master_logic.byte_matching.tx_conduct.uart_tx_done);
		#1000;
		
		$stop;
	end 

uart_tx_logic #(
	.BAUD_SET			(	BAUD_SET		)
)uart_tx_logic(	
	.sys_clk			(	sys_clk			),
	.sys_rst_n			(	sys_rst_n		),
	.tx_en				(	tx_en			),
	.tx_data			(	tx_data			),
	.tx_done			(	tx_done			),		
	.uart_tx			(	uart_tx			)
);

uart2axi_master_logic #(
	.M_AXI_ADDR_WIDTH 		(	M_AXI_ADDR_WIDTH	),	
	.M_AXI_DATA_WIDTH 		(	M_AXI_DATA_WIDTH	),	
	.BAUD_SET		 		(	BAUD_SET			),			//	波特率设置,默认9600
	.RX_TOTAL_BYTE	 		(	RX_TOTAL_BYTE		),			//	串口接收到9byte数据开始工作	
	.TX_TOTAL_BYTE			(	TX_TOTAL_BYTE		),			//	串口发送4byte数据给上位机
	.WRITE_BIT				(	WRITE_BIT			),			//	设置最高位1为写操作
	.READ_BIT				(	READ_BIT			)	
)uart2axi_master_logic(
	.sys_clk				(	sys_clk				),
	.sys_rst_n              (   sys_rst_n           ),
	.uart_write             (   uart_write          ),
	.uart_write_addr        (   uart_write_addr     ),
	.uart_write_data		(	uart_write_data		),
	.uart_read              (   uart_read           ),
	.uart_read_addr         (   uart_read_addr      ),
	.uart_tx_en             (   uart_tx_en          ),
	.uart_tx_data	        (   uart_tx_data	    ),
	.uart_rx                (   uart_tx             ),
	.uart_tx                (   uart_rx        		)
);

endmodule
//*****************文件结束*************************

今晚终于把这个模块搞定啦,各位小伙伴可以放心食用了,明天把axi_master接口搞好,整个工程就算7788了。
//分割线*
在写主机接口的时候,发现一个问题,我串口读写地址有了,但是写数据呢?原来是疏忽大意了,忘记把写数据传过来,后面我写好了,也验证好了。大家这次可以放心使用啦嘿嘿。有什么错误或者有不懂的欢迎大家评论区留言哈

  • 13
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值