串口发送模块uart_tx详解

1. 原理介绍

本文是学习小梅哥串口模块教程后的整理总结。

用于数据接收与发送的常用通信协议: UART(通用异步收发传输器)、I2C(集成电路总线)、USB2.0/3.0(通用串行总线)、SPI(串行外围总线)、Ethernet(以太网) 等。

串行通信是指利用一条传输线将资料一位位地顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合。

异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的。

这里讲解基于RS232接口标准规范的uart_tx异串口发送模块
发送并行数据,转为串行数据送入上位机orPC等。
UART 是异步串行通信的总称。而** RS232、 RS449、 RS423、 RS422
和 RS485 等,是对应各种异步串行通信口的接口标准和总线标准,它们具体规定了通
信口的
电气特性、传输速率、连接特性和接口的机械特性**等内容。

RS232的 DB9 接口的针脚定义

串口发送模块uart_tx详解_第1张图片
具体每个针脚的功能不再赘述,这里重点研究uart的传输时序图

2. UART串口发送数据的传输时序

需要设置数据位数、波特率、奇偶校验类型和停止位数

数据位( Data bits)

该参数定义单个 UART 数据传输在开始到停止期间发送的数据位数。 可选择为: 5、 6、 7 或者 8(默认)

波特率( Baud)

是指从一设备发到另一设备的波特率,即每秒钟可以通信数据**比特(bit)**个数。 典型的波特率有 300, 1200, 2400, 9600, 19200, 115200 等,单位bit/s,也即是bps。一般通信两端设备都要设为相同的波特率,有些设备也可设置为自动检测波特率。

奇偶校验类型( Parity Type)

是用来验证数据的正确性。如果用户选择数据长度为 8 位,是因为没有多余的比特可被用来作为奇偶校验位,因此就叫做“无奇偶校验( Non)”。此处不再赘述。

停止位( Stop bits):

在每个字节的数据位发送完成之后,发送停止位,来标志着一次数据传输完成,同时用来帮助接受信号方硬件重同步。 可选择为: 1( 默认)、 1.5 或者 2 位。
在 RS-232 标准中, 最常用的配置是 8N1(即8数据位+无奇偶校验+1停止位), 其发送一个字节时序图如图
串口发送模块uart_tx详解_第2张图片
一个完整的字节包括1位起始位、8 位数据位、1位停止即总共10位数据来算,要想完整的实现这10位数据的发送,就需要11个波特率时钟脉冲, 第1个脉冲标记一次传输的起始, 第 11 个脉冲标记一次传输的结束。
BPS_CLK 信号的第一个上升沿到来时,字节发送模块开始发送起始位,接下来的 2 到 9 个上升沿, 发送 8 个数据位,第 10 个上升沿到第 11 个上升沿为停止位的发送。

也可以采用在每个起始位之前添加一位传 “1’b1” 的位,用来为START_BIT的最初变化显示为下降。,以便串口接收模块识别下降沿,开始接收数据。这样也就不用在最后再添加第11个脉冲来标记传输结束了。

3.模块设计

串口发送模块uart_tx详解_第3张图片
串口发送模块uart_tx详解_第4张图片
串口发送模块uart_tx详解_第5张图片

(1)波特率时钟模块

串口发送模块uart_tx详解_第6张图片

波特率计数值bps_DR计算原理:串口发送模块uart_tx详解_第7张图片

以9600bps为例:bps_DR=[(10^9 ns)/(9600bps*20ns)]-1=5207(9600bps的分频计数最大值)

波特率时钟及计数模块代码
//baud_set
reg [15:0] bps_DR;//分频计数最大值
reg bps_clk;	//波特率时钟
reg [15:0]div_cnt;//分频计数器
reg [15:0]bps_DR;//分频计数最大值
reg [3:0]bps_cnt;//波特率时钟计数器
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
	bps_DR <= 16'd5207;
else
	begin
		case(baud_set)//之后要为baudset 设置LUT查找表
		0:bps_DR <= 16'd5207; //9600bps
		1:bps_DR <= 16'd2603; //19200bps
		2:bps_DR <= 16'd1301; //38400bps
		3:bps_DR <= 16'd867;  //57600bps
		4:bps_DR <= 16'd433;  //115200bps
		default:bps_DR <= 16'd5207;//默认为9600bps
		endcase
	end
	

//counter
always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		div_cnt <= 16'd0;
	else if(uart_state)begin
		if(div_cnt == bps_DR)
			div_cnt <= 16'd0;
		else
			div_cnt <= div_cnt + 1'b1;
	end
	else
		div_cnt <= 16'd0;
	
// bps_clk gen
always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_clk <= 1'b0;
	else if(div_cnt == 16'd1)
		bps_clk <= 1'b1;
	else
		bps_clk <= 1'b0;

然后对baudset设置一个查找表LUT
串口发送模块uart_tx详解_第8张图片

(2)数据位数计数器模块

串口发送模块uart_tx详解_第9张图片```


//bps counter,对每个字节数据传输位数进行计数,1~11位
always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)	
		bps_cnt <= 4'd0;
	else if(bps_cnt == 4'd11)
		bps_cnt <= 4'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else
		bps_cnt <= bps_cnt;
(3) 传输一个字节结束标志Tx_Done 模块
output reg Tx_Done;
always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Tx_Done <= 1'b0;
	else if(bps_cnt == 4'd11)
		Tx_Done <= 1'b1;
	else
		Tx_Done <= 1'b0;
(4) 数据发送模块

由低位到高位依次发送,由10-1MUX构成;

根据 bps_cnt 的值来确定数据传输的状态。 不同的波特率时钟计数值时,有不同的传输数据对应。

1’b1;
START_BIT;(1’b0)
r_data_byte[0];
r_data_byte[1];
r_data_byte[2];
r_data_byte[3];
r_data_byte[4];
r_data_byte[5];
r_data_byte[6];
r_data_byte[7];
STOP_BIT;(1’b1)


localparam START_BIT = 1'b0;
localparam STOP_BIT  = 1'b1;
always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Rs232_Tx <= 1'b1;
	else begin
		case(bps_cnt)
			0:Rs232_Tx <= 1'b1;
			1:Rs232_Tx <= START_BIT;
			2:Rs232_Tx <= r_data_byte[0];
			3:Rs232_Tx <= r_data_byte[1];
			4:Rs232_Tx <= r_data_byte[2];
			5:Rs232_Tx <= r_data_byte[3];
			6:Rs232_Tx <= r_data_byte[4];
			7:Rs232_Tx <= r_data_byte[5];
			8:Rs232_Tx <= r_data_byte[6];
			9:Rs232_Tx <= r_data_byte[7];
			10:Rs232_Tx <= STOP_BIT;
			default:Rs232_Tx <= 1'b1;
		endcase
	end
(5)异步数据同步化模块(一级寄存)

由于 RS232 是一个异步的收发器, 因此为了保证发送的数据在时钟到来的时候是稳定的,这里也需要对输入数据进行寄存.可以一级也可以两级,这里一级就足够了


reg [7:0]r_data_byte;
always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		r_data_byte <= 8'd0;
	else if(send_en)
		r_data_byte <= data_byte;
	else
		r_data_byte <= r_data_byte;
(6) uart_state状态标志 模块
output reg uart_state;
always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		uart_state <= 1'b0;
	else if(send_en)
		uart_state <= 1'b1;
	else if(bps_cnt == 4'd11)
		uart_state <= 1'b0;
	else
		uart_state <= uart_state;

仿真部分

将所有数据变化与系统时钟错开 1ns,是为了能更清楚看到输入输出数据与时钟的时序关系.
根据需要,生成复位信号、使能信号send_en、待传输数据。

initial begin
		Rst_n = 1'b0;
		data_byte = 8'd0;
		send_en = 1'd0;
		baud_set = 3'd4;
		#(`clk_period*20 + 1 )
		Rst_n = 1'b1;
		#(`clk_period*50);
	
		data_byte = 8'haa;
		send_en = 1'd1;
		#`clk_period;
		send_en = 1'd0;
	
		@(posedge Tx_Done)
	
		#(`clk_period*5000);
	
		data_byte = 8'h55;
		send_en = 1'd1;
		#`clk_period;
		send_en = 1'd0;
	
		@(posedge Tx_Done)
	
		#(`clk_period*5000);
	
		$stop;	
	end

在这里插入图片描述
串口发送模块uart_tx详解_第10张图片

你可能感兴趣的:(FPGA)