文章目录

1、概述

2、串口发送驱动

3、任意字节发送的实现方法

4、仿真

4.1、单字节仿真

4.2、双字节仿真

4.3、5字节仿真

5、实测

5.1、单字节实测

5.2、双字节实测

5.3、5字节实测


1、概述

        在这篇文章中串口(UART)的FPGA实现(含源码工程),实现了基于FPGA的串口发送驱动。利用发送驱动可以实现 起始位1bit+数据位8bit+停止位1bit 共10bit的单字节传输。

        但是在实际应用过程中又经常需要一次性发送多个字节的数据。比如,一次发送一个位宽为【39:0】的数据。诚然,可以直接更改此文中的串口发送驱动,使其变成 起始位1bit+数据位40bit+停止位1bit 共42bit的多字节传输。这种方法理论上是可行的,因为UART协议并没有规定你一次要发送、接收多个少bit的数据,既然能发送8个bit,那同样能发送40个bit。

        但是很不幸,实际上基本行不通,因为通用的绝大部分上位机都不支持一次解析40bit的数据位(如果你自己写上位机就当我没说)。

        所以只能想点其他办法,比如:写个逻辑,多次调用8bit即单字节的串口发送驱动,40bit的数据就调用5次,也就是切割成5个 起始位1bit+数据位8bit+停止位1bit共10bit的单字节 分别发送过去就可以了。


2、串口发送驱动

        请参考:串口(UART)的FPGA实现(含源码工程),在此文详细介绍了串口的发送驱动。

        以下部分代码可以实现 1bit+数据位8bit+停止位1bit 共10bit的单字节传输,无奇偶校验。

 
// *******************************************************************************************************
// ** 作者 : 孤独的单刀                                                   			
// ** 邮箱 : zachary_wu93@163.com
// ** 博客 : https://blog.csdn.net/wuzhikaidetb 
// ** 日期 : 2022/07/31	
// ** 功能 : 1、基于FPGA的串口发送驱动模块;
//			  2、可设置波特率BPS、主时钟CLK_FRE;
//			  3、起始位1bit,数据位8bit,停止位1bit,无奇偶校验;                                           									                                                                          			
//			  4、每发送1个字节后拉高uart_tx_done一个周期,可用于后续发送多字节模块。                                           									                                                                          			
// *******************************************************************************************************	
 
module uart_tx
#(
	parameter	integer	BPS		= 9_600		,	//发送波特率
	parameter 	integer	CLK_FRE	= 50_000_000	//主时钟频率
)
(
//系统接口
	input 			sys_clk			,			//系统时钟
	input 			sys_rst_n		,			//系统复位,低电平有效
//用户接口	
	input	[7:0] 	uart_tx_data	,			//需要通过UART发送的数据,在uart_tx_en为高电平时有效
	input			uart_tx_en		,			//发送有效,当其为高电平时,代表此时需要发送的数据有效
//UART发送	
	output	reg		uart_tx_done	,			//成功发送1BYTE数据后拉高一个周期
	output 	reg		uart_txd					//UART发送数据线tx
);
 
 
 
//当发送使能信号到达时,寄存待发送的数据以免后续变化、丢失
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		uart_tx_data_reg <=8'd0;
	else if(uart_tx_en)							//要发送有效的数据
		uart_tx_data_reg <= uart_tx_data;		//寄存需要发送的数据			
	else 
		uart_tx_data_reg <= uart_tx_data_reg;
end		
//当发送使能信号到达时,进入发送过程
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		tx_state <=1'b0;	
	else if(uart_tx_en)												
		tx_state <= 1'b1;						//发送信号有效则进入发送过程
	//发送完了最后一个数据则退出发送过程		
	else if((bit_cnt == BITS_NUM - 1'b1) && (clk_cnt == BPS_CNT - 1'b1))		
		tx_state <= 1'b0;                                          		
	else 
		tx_state <= tx_state;	
end
 
//发送数据完毕后拉高发送完毕信号一个周期,指示一个字节发送完毕
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		uart_tx_done <=1'b0;
	//发送数据完毕后拉高发送完毕信号一个周期 		
	else if((bit_cnt == BITS_NUM - 1'b1) && (clk_cnt == BPS_CNT - 1'b1))	                                         	
		uart_tx_done <=1'b1;										
	else 
		uart_tx_done <=1'b0;
end
//进入发送过程后,启动时钟计数器与发送个数bit计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		clk_cnt <= 32'd0;
		bit_cnt <= 4'd0;
	end
	else if(tx_state) begin										//在发送状态
		if(clk_cnt < BPS_CNT - 1'd1)begin						//一个bit数据没有发送完
			clk_cnt <= clk_cnt + 1'b1;							//时钟计数器+1
			bit_cnt <= bit_cnt;									//bit计数器不变
		end					
		else begin												//一个bit数据发送完了	
			clk_cnt <= 32'd0;									//清空时钟计数器,重新开始计时
			bit_cnt <= bit_cnt+1'b1;							//bit计数器+1,表示发送完了一个bit的数据
		end					
	end					
	else begin													//不在发送状态
		clk_cnt <= 32'd0;                   					//清零
		bit_cnt <= 4'd0;                    					//清零
	end
end
endmodule 



3、任意字节发送的实现方法

        串口发送驱动模块的对外端口如下:

    

        其中uart_tx_done信号是关键。当一个字节的数据被按约定的串口协议发送出去后,该信号就会拉高一个时钟周期,表示一次传输结束。

        可以在发送完一个字节后,将该信号作为发送下一个字节的使能信号,直到所有的字节都被发送完毕。

        但是有一个需要注意的问题:第一个字节的发送使能是无法参考信号 uart_tx_done,那么第一个信号何时发送?同样的,在任意字节发送模块设计一个对外信号:uart_bytes_en,只有当该信号有效时才发起一次传输,同时该信号还可以作为第一个字节的发送使能信号,如下:

        总结一下,多字节的发送逻辑:

  • 1、用户传递多字节发送使能+多字节数据
  • 2、根据多字节发送使能发送最低字节(最低8bit),作为第一次发送的单字节
  • 3、根据单字节发送完毕指示信号,开始发送第二个单字节,即多字节的次低byte
  • 4、所有单字节均被发送完毕后,拉高uart_bytes_done,表示一次多字节发送结束 

        

        部分代码如下:

 
// *******************************************************************************************************************
// ** 作者 : 孤独的单刀                                                   			
// ** 邮箱 : zachary_wu93@163.com
// ** 博客 : https://blog.csdn.net/wuzhikaidetb 
// ** 日期 : 2022/07/31	
// ** 功能 : 1、基于FPGA的串口多字节发送模块;
//			  2、可设置一次发送的字节数、波特率BPS、主时钟CLK_FRE;
//			  3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);                                           									                                                                          			
//			  4、每发送1次多字节后拉高指示信号一个周期,指示一次多字节发送结束;
//			  5、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。                                          									                                                                          			
// *******************************************************************************************************************	
 
module uart_bytes_tx
#(
	parameter	integer	BYTES 	 = 4			,				//发送字节数,单字节8bit
	parameter	integer	BPS		 = 9_600		,				//发送波特率
	parameter 	integer	CLK_FRE	 = 50_000_000					//输入时钟频率
)
(
//系统接口
	input 							sys_clk			,			//系统时钟
	input 							sys_rst_n		,			//系统复位,低电平有效
//用户接口	
	input	[(BYTES * 8 - 1):0] 	uart_bytes_data	,			//需要通过UART发送的多字节数据,在uart_bytes_en为高电平时有效
	input							uart_bytes_en	,			//发送有效,当其为高电平时,代表此时需要发送的数据有效
//UART发送	
	output							uart_bytes_done	,			//成功发送完所有字节数据后拉高1个时钟周期
	output 							uart_txd					//UART发送数据线tx
);
 
 
//对端口赋值
assign uart_bytes_done = uart_bytes_done_reg;
 
 
//当发送使能信号到达时,寄存待发送的多字节数据以免后续变化、丢失
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		uart_bytes_data_reg <= 0;
	else if(uart_bytes_en && ~work_en)							//要发送有效的数据,且并未处于发送状态
		uart_bytes_data_reg <= uart_bytes_data;					//寄存需要发送的数据			
	else if(uart_sing_done)										
		uart_bytes_data_reg <= uart_bytes_data_reg >> 8;		//发送完一个数据后,把多字节数据右移8bit
	else 
		uart_bytes_data_reg <= uart_bytes_data_reg;
end	
 
//当发送使能信号到达时,进入工作状态
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		work_en <= 1'b0;
	else if(uart_bytes_en && ~work_en)							//要发送有效的数据且未处于工作状态
		work_en <= 1'b1;										//进入发送状态			
	else if(uart_sing_done && byte_cnt == BYTES - 1)			//发送完了最后一个字节的数据
		work_en <= 1'b0;										//发送完毕,退出工作状态	
	else 		
		work_en <= work_en;		
end			
		
//在工作状态对发送的数据个数进行计数		
always @(posedge sys_clk or negedge sys_rst_n)begin		
	if(!sys_rst_n)		
		byte_cnt <= 0;		
	else if(work_en)begin										//处于发送状态则需要对发送的字节个数计数
		if(uart_sing_done && byte_cnt == BYTES - 1)				//计数到了最大值则清零
			byte_cnt <= 0;										
		else if(uart_sing_done)									//发送完一个单字节则计数器+1
			byte_cnt <= byte_cnt + 1'b1;						
		else		
			byte_cnt <= byte_cnt;			
	end		
	else														//不处于发送状态则清零
		byte_cnt <= 0;	
end
 
//打拍凑时序·~·
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		uart_sing_done_reg <= 0;
	else 
		uart_sing_done_reg <= uart_sing_done;	
end
	
//发送单个字节的数据
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		uart_sing_data <= 8'd0;
	else if(uart_bytes_en && ~work_en)						//进入工作状态后马上发送第一个数据
		uart_sing_data <= uart_bytes_data[7:0];				//发送最低字节
	else if(uart_sing_done_reg)								//发送完一个字节则发送另一个字节
		uart_sing_data <= uart_bytes_data_reg[7:0];			//先右移8bit,然后取低8bit
	else
		uart_sing_data <= uart_sing_data;					//保持稳定
end
//发送单个字节的数据使能
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		uart_sing_en <= 1'b0;
	else if(uart_bytes_en && ~work_en)						//进入工作状态后马上发送第一个数据
		uart_sing_en <= 1'b1;		
	else if(uart_sing_done_reg && work_en)					//发送完一个字节则发送另一个字节
		uart_sing_en <= 1'b1;		
	else		
		uart_sing_en <= 1'b0;								//其他时候则为0
end
//例化发送驱动模块
uart_tx #(
	.BPS			(BPS			),		
	.CLK_FRE		(CLK_FRE		)		
)	
uart_tx_inst(	
	.sys_clk		(sys_clk		),			
	.sys_rst_n		(sys_rst_n		),
	
	.uart_tx_data	(uart_sing_data	),			
	.uart_tx_en		(uart_sing_en	),
	.uart_tx_done	(uart_sing_done	),
	.uart_txd		(uart_txd		)	
);
endmodule 



4、仿真

        使用该模块发送数据3次,观测发送结果是否符合UART协议要求。分别使用单字节(8位)、双字节(16位)、5字节(40位)进行测试。


4.1、单字节仿真

        TB如下:

`timescale 1ns/1ns	//定义时间刻度
 
 
module tb_uart_bytes_tx();
 
localparam	integer	BYTES    = 1			;		//一次发送的字节个数
 
localparam	integer	BPS 	 = 230400		;		//波特率
localparam	integer	CLK_FRE  = 50_000_000	;		//系统频率50M
 
reg 						sys_clk			;		//系统时钟
reg 						sys_rst_n		;		//系统复位,低电平有效	
reg	[(BYTES * 8 - 1):0] 	uart_bytes_data	;		//需要通过UART发送的多字节数据,在uart_bytes_en为高电平时有效
reg							uart_bytes_en	;		//发送有效,当其为高电平时,代表此时需要发送的数据有效
wire						uart_bytes_done	;		//成功发送完所有BYTE数据后拉高1个时钟周期
wire 						uart_txd		;		//UART发送数据线
 
initial begin	
	sys_clk <=1'b0;	
	sys_rst_n <=1'b0;
	uart_bytes_en <=1'b0;
	uart_bytes_data <= 0;
	#80 											//系统开始工作
	sys_rst_n <=1'b1;	
//*******************************************************************************		
//第1次发送随机数据
	#90 												//发送1次随机的多字节数据
		uart_bytes_en <=1'b1;	
		uart_bytes_data <= {$random};					//生成随机数据
	#20 
		uart_bytes_en <=1'b0;	
	wait(uart_bytes_done);								//等待其发送完
//*******************************************************************************		
//*******************************************************************************			
//第2次发送随机数据
	#20 
		uart_bytes_en <=1'b1;	
		uart_bytes_data <= {$random};					//发送1次随机的多字节数据
	#20 
		uart_bytes_en <=1'b0;	
	wait(uart_bytes_done);								//等待其发送完
//*******************************************************************************		
//第3次发送随机数据	
	#20 
		uart_bytes_en <=1'b1;	
		uart_bytes_data <= {$random};					//发送1次随机的多字节数据
	#20 
		uart_bytes_en <=1'b0;	
	wait(uart_bytes_done);								//等待其发送完
//*******************************************************************************		
	#1000 $finish();			//结束仿真
end
 
always #10 sys_clk=~sys_clk;	//设置主时钟,20ns,50M
 
//例化多字节发送模块
uart_bytes_tx #(
	.BYTES				(BYTES				),
	.BPS				(BPS				),		
	.CLK_FRE			(CLK_FRE			)		
)			
uart_bytes_tx_inst(			
	.sys_clk			(sys_clk			),			
	.sys_rst_n			(sys_rst_n			),
		
	.uart_bytes_data	(uart_bytes_data	),			
	.uart_bytes_en		(uart_bytes_en		),
	
	.uart_bytes_done	(uart_bytes_done	),
	.uart_txd			(uart_txd			)	
);
endmodule 

        仿真结果如下:

  • 该模块调用了3次,分别发送数据8'h24,8'h81,8'h09
  • 串口发送驱动发送了同样的3个数据8'h24,8'h81,8'h09
  • 以第一次发送8'h24为例,此时串口发送线TX上的数据分别为0(起始位) --0--0--1--0--0--1--0--0--1(停止位),根据数据低位在前,高位在后的原则,即8'b00100100,也就是8'h24

4.2、双字节仿真

        TB基本不用修改,仅仅把BYTES这个参数改成2就行。仿真结果如下:

  • 该模块调用了3次,分别发送数据16'h3524,16'h5e81,16'hd609
  • 串口发送驱动发送了6个数据8'h24,8'h358'h81,8'h5e8'h09,8'hd6
  • 根据先发低字节后发高字节的原则,将3个双字节拆成了6个单字节分别发送

4.3、5字节仿真

        TB基本不用修改,仅仅把BYTES这个参数改成5就行。仿真结果如下:

        您照着上面的逻辑看看就行,我就不啰嗦了。


5、实测

        下板实测的话,需要写个顶层模块来例化这个任意字节的串口发送模块。在顶层模块,设置成每1s拉高一次发送信号,同时将要发送的数据+1。


5.1、单字节实测

        顶层模块如下:

 
// *******************************************************************************************************************
// ** 作者 : 孤独的单刀                                                   			
// ** 邮箱 : zachary_wu93@163.com
// ** 博客 : https://blog.csdn.net/wuzhikaidetb 
// ** 日期 : 2022/07/31	
// ** 功能 : 1、对基于FPGA的串口多字节发送模块进行测试的模块;
//			  2、设置好一次发送的字节数、波特率、主时钟频率;
//			  3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);                                           									                                                                          			
//			  4、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。                                          									                                                                          			
// *******************************************************************************************************************	
 
 
module uart_bytes_tx_test(
//系统接口
	input 				sys_clk			,					//主时钟
	input 				sys_rst_n		,	                //低电平有效的复位信号
//UART发送线	
	output  			uart_txd							//UART发送线
);
 
localparam	integer		BYTES 	 = 1			;			//发送的字节数,单字节8bit
localparam	integer		BPS		 = 115200		;			//发送波特率
localparam 	integer		CLK_FRE	 = 50_000_000	;			//输入时钟频率
localparam	integer		CNT_MAX  = 50_000_000  	;			//发送时间间隔,1秒
 
reg		[31:0]			cnt_time; 
reg						uart_bytes_en;						//发送使能,当其为高电平时,代表此时需要发送数据		
reg		[BYTES*8-1 :0] 	uart_bytes_data;					//需要通过UART发送的数据,在uart_bytes_en为高电平时有效
 
//1s计数模块,每隔1s发送一个数据和拉高发送使能信号一次,数据从初始值开始递增1
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		cnt_time <= 'd0;
		uart_bytes_en <= 1'd0;
		uart_bytes_data <= 'h12;							//初始数据
	end
	else if(cnt_time == (CNT_MAX - 1'b1))begin
		cnt_time <= 'd0;
		uart_bytes_en <= 1'd1;								//拉高发送使能
		uart_bytes_data <= uart_bytes_data + 1'd1;			//发送数据累加1
	end
	else begin
		cnt_time <= cnt_time + 1'd1;
		uart_bytes_en <= 1'd0;
		uart_bytes_data <= uart_bytes_data; 
	end
end
//例化串口多字节发送模块
uart_bytes_tx
#(
	.BYTES 	 			(BYTES 				),				
	.BPS				(BPS				),				
	.CLK_FRE			(CLK_FRE			)				
)		
uart_bytes_tx_inst		
(		
		
	.sys_clk			(sys_clk			),			
	.sys_rst_n			(sys_rst_n			),				                                    
	.uart_bytes_data	(uart_bytes_data	),			
	.uart_bytes_en		(uart_bytes_en		),			                                   
	.uart_bytes_done	(					),			
	.uart_txd			(uart_txd			)			
);
endmodule

        初始值设定为8'h13,这样上位机每1s就可以接收一个数据,其值分别为8'h13、8'h14、8'h15、8'h16、8'h17·····,上位机接收到的数据如下:

        测试结果与预期一致。


5.2、双字节实测

        顶层模块如下:

 
// *******************************************************************************************************************
// ** 作者 : 孤独的单刀                                                   			
// ** 邮箱 : zachary_wu93@163.com
// ** 博客 : https://blog.csdn.net/wuzhikaidetb 
// ** 日期 : 2022/07/31	
// ** 功能 : 1、对基于FPGA的串口多字节发送模块进行测试的模块;
//			  2、设置好一次发送的字节数、波特率、主时钟频率;
//			  3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);                                           									                                                                          			
//			  4、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。                                          									                                                                          			
// *******************************************************************************************************************	
 
 
module uart_bytes_tx_test(
//系统接口
	input 				sys_clk			,					//主时钟
	input 				sys_rst_n		,	                //低电平有效的复位信号
//UART发送线	
	output  			uart_txd							//UART发送线
);
 
localparam	integer		BYTES 	 = 2			;			//发送的字节数,单字节8bit
localparam	integer		BPS		 = 115200		;			//发送波特率
localparam 	integer		CLK_FRE	 = 50_000_000	;			//输入时钟频率
localparam	integer		CNT_MAX  = 50_000_000  	;			//发送时间间隔,1秒
 
reg		[31:0]			cnt_time; 
reg						uart_bytes_en;						//发送使能,当其为高电平时,代表此时需要发送数据		
reg		[BYTES*8-1 :0] 	uart_bytes_data;					//需要通过UART发送的数据,在uart_bytes_en为高电平时有效
 
//1s计数模块,每隔1s发送一个数据和拉高发送使能信号一次,数据从初始值开始递增1
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		cnt_time <= 'd0;
		uart_bytes_en <= 1'd0;
		uart_bytes_data <= 'h3412;							//初始数据
	end
	else if(cnt_time == (CNT_MAX - 1'b1))begin
		cnt_time <= 'd0;
		uart_bytes_en <= 1'd1;								//拉高发送使能
		uart_bytes_data <= uart_bytes_data + 1'd1;			//发送数据累加1
	end
	else begin
		cnt_time <= cnt_time + 1'd1;
		uart_bytes_en <= 1'd0;
		uart_bytes_data <= uart_bytes_data; 
	end
end
//例化串口多字节发送模块
uart_bytes_tx
#(
	.BYTES 	 			(BYTES 				),				
	.BPS				(BPS				),				
	.CLK_FRE			(CLK_FRE			)				
)		
uart_bytes_tx_inst		
(		
		
	.sys_clk			(sys_clk			),			
	.sys_rst_n			(sys_rst_n			),				                                    
	.uart_bytes_data	(uart_bytes_data	),			
	.uart_bytes_en		(uart_bytes_en		),			                                   
	.uart_bytes_done	(					),			
	.uart_txd			(uart_txd			)			
);
endmodule

        初始值设定为16'h3413,这样上位机每1s就可以接收一个数据,其值分别为8'h13、8'h348'h14、8'h348'h15、8'h34·····,上位机接收到的数据如下:

        

        测试结果与预期一致。


5.3、5字节实测

        顶层模块如下:

 
// *******************************************************************************************************************
// ** 作者 : 孤独的单刀                                                   			
// ** 邮箱 : zachary_wu93@163.com
// ** 博客 : https://blog.csdn.net/wuzhikaidetb 
// ** 日期 : 2022/07/31	
// ** 功能 : 1、对基于FPGA的串口多字节发送模块进行测试的模块;
//			  2、设置好一次发送的字节数、波特率、主时钟频率;
//			  3、UART协议设置为起始位1bit,数据位8bit,停止位1bit,无奇偶校验(不可在端口更改,只能更改发送驱动源码);                                           									                                                                          			
//			  4、数据发送顺序,先发送低字节、再发送高字节。如:发送16’h12_34,先发送单字节8'h34,再发送单字节8'h12。                                          									                                                                          			
// *******************************************************************************************************************	
 
 
module uart_bytes_tx_test(
//系统接口
	input 				sys_clk			,					//主时钟
	input 				sys_rst_n		,	                //低电平有效的复位信号
//UART发送线	
	output  			uart_txd							//UART发送线
);
 
localparam	integer		BYTES 	 = 5			;			//发送的字节数,单字节8bit
localparam	integer		BPS		 = 115200		;			//发送波特率
localparam 	integer		CLK_FRE	 = 50_000_000	;			//输入时钟频率
localparam	integer		CNT_MAX  = 50_000_000  	;			//发送时间间隔,1秒
 
reg		[31:0]			cnt_time; 
reg						uart_bytes_en;						//发送使能,当其为高电平时,代表此时需要发送数据		
reg		[BYTES*8-1 :0] 	uart_bytes_data;					//需要通过UART发送的数据,在uart_bytes_en为高电平时有效
 
//1s计数模块,每隔1s发送一个数据和拉高发送使能信号一次,数据从初始值开始递增1
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)begin
		cnt_time <= 'd0;
		uart_bytes_en <= 1'd0;
		uart_bytes_data <= 40'h9a_78_56_34_12;				//初始数据
	end
	else if(cnt_time == (CNT_MAX - 1'b1))begin
		cnt_time <= 'd0;
		uart_bytes_en <= 1'd1;								//拉高发送使能
		uart_bytes_data <= uart_bytes_data + 1'd1;			//发送数据累加1
	end
	else begin
		cnt_time <= cnt_time + 1'd1;
		uart_bytes_en <= 1'd0;
		uart_bytes_data <= uart_bytes_data; 
	end
end
//例化串口多字节发送模块
uart_bytes_tx
#(
	.BYTES 	 			(BYTES 				),				
	.BPS				(BPS				),				
	.CLK_FRE			(CLK_FRE			)				
)		
uart_bytes_tx_inst		
(		
		
	.sys_clk			(sys_clk			),			
	.sys_rst_n			(sys_rst_n			),				                                    
	.uart_bytes_data	(uart_bytes_data	),			
	.uart_bytes_en		(uart_bytes_en		),			                                   
	.uart_bytes_done	(					),			
	.uart_txd			(uart_txd			)			
);
endmodule


        初始值设定为40'h9a78563413,这样上位机每1s就可以接收一个数据,其值分别为8'h13、8'h34、8'h56、8'h78、8'h9a、8'h14、8'h34、8'h56、8'h78、8'h9a、·····,上位机接收到的数据如下:

        测试结果与预期一致。

        如果需要完整的工程文件请点这里工程文件下载


  • 博客主页:wuzhikai.blog.csdn.net
  • 本文由 孤独的单刀 原创,首发于CSDN平台
  • 您有任何问题,都可以在评论区和我交流!
  • 创作不易,您的支持是我持续更新的最大动力!如果本文对您有帮助,还请多多点赞、评论