verilog_串口实现

verilog_串口实现
概述: 先了解串口的基础知识:
串口是怎样传数据的
什么是波特率,波特率怎么计算

说明: 通过Verilog编写串口,通过逻辑分析仪串口模块的对接来进一步了解串口的应用。


1.什么是波特率,波特率怎么计算

概述:
  ☆简而言之,串口传输的波特率即为每秒钟传输二进制的位数。
  ☆脱离枯燥乏味的文字描述,我们用波形和数字来看看波特率是什么吧☟。
  ☆说明:系统时钟50M,波特率115200。

1.1基础知识:

系统时钟-50M 时钟周期 1 50 1 0 6 {{\rm{1}} \over {{\rm{50*1}}{{\rm{0}}^{\rm{6}}}}}
假设1个时钟周期可以计数1次(其实FPGA就是这样) 50M时钟1s计数50 000 000个
系统时钟-50M 计1个数需要 1 50 1 0 6 {{\rm{1}} \over {{\rm{50*1}}{{\rm{0}}^{\rm{6}}}}} s
波特率-115200 1s传输二进制的位数115200bit
波特率-115200 传输1bit需要 1/115200s=8.68us
50M系统时钟------波特率为115200 传输1bit需要计数 ( 50 1 0 6 / 115200 ) = 434 ({\rm{50*1}}{{\rm{0}}^{\rm{6}}}/{\rm{115200}}) = 434

以上重点是推导出50M系统时钟—波特率为115200条件下传输1bit需要计数个数为434。

1.2串口传输格式

●我们通常用的串口传输格式为:1bit起始位+8bit数据位+1bit停止位(无奇偶校验位),如下图所示:
在这里插入图片描述
所以传输1Byte数据串口需要传输10bit数据。上面计算得传输1Bit需要的时间为8.68us,则传输1Byte需要时间为8.68*10=86.8us。

1.3深入理解波特率

由基础知识知50M系统时钟—波特率为115200条件下传输1bit需要计数个数为434。那么1Byte(串口传输格式为:1bit起始位+8bit数据位+1bit停止位)是不是循环计数10次434就可以传输完毕。
直接上图:图中描述了1Byte数据传输的示意图,重点都在图里!!!。
在这里插入图片描述
✍什么时候去采样串口线上的数据呢?
  ★观察上图,Buad_Flag信号(通道2)表示了传输1Bit传输的间隔,每遇到1个Buad_Flag=1的信号,数据线上切换1次数据,所以两个Buad_Flag=1之间的数据是稳定的数据,根据抽样定理是不是应该在两个Buad_Flag=1信号的中间去采样数据呢,其实就是在1bit数据持续期间的中间点采样,才能得到最稳定的数据。见下图,重点都在图里!!!
  在这里插入图片描述
  ★图中序号①-⑩分别为10bit数据的采样点,采样点处提取数据为1010_1010(0xAA)。

★★★至此,从下往上再看一遍,就明白了我们所熟悉的波特率(115200/9600/…)怎么来的。

2.串口是怎样传输数据的

➹通过逻辑分析仪捕捉串口传输的数据来了解串口传输数据的实质。
  
  串行接口简称为串口,串行接口 (Serial Interface)是指数据一位一位地顺序传送。实现双向通信就需要一对传输线,即TX与RX线。
电路连接方式:
  串口如果要实现双向传输,则设备1与设备2,TX与RX要交叉相连。
在这里插入图片描述

2.1串口数据解析

利用电脑端的串口助手通过CH340串口模块将数据0x55发送出去,并通过逻辑分析仪来捕捉数据。下图为串口发送的数据,是以十六进制(hex)形式发送的。
在这里插入图片描述
逻辑分析仪捕捉数据:
在这里插入图片描述
我们看到逻辑分析仪成功将数据0x55捕捉到。接下来看串口的数据构成是怎样的。
查阅资料,串口传输一帧数据如下图所示:
在这里插入图片描述
所谓串口的一帧数据即串行的发送一次数据(比如0x55(0101_0101))时TX数据线上的电平变化。由上图可知串口一帧数据的构成为:起始位(1bit)+数据(8bit)+奇偶校验位+停止位(1bit),8bit数据传输的方式为先低位(LSB)再高位(MSB)即通过(D0_D1_D2_D3_D4_D5_D6_D7)的顺序将数据依次放置在TX数据线上。我们再看我们所用的串口助手:
在这里插入图片描述
我们的设置为传输数据位为8bit,检验位为0bit即没有校验位,停止位为1bit。所以我们串口一帧数据的构成为:起始位(1bit)+数据(8bit)+停止位(1bit),所以串口一帧数据的传输单位为10bit,平时我们所说的串口传输单位为1Byte即8bit是指传输的有效数据,即起始位(1bit)+数据(8bit)+停止位(1bit)中的8bit数据,那为什么要多此一举的在收尾处各加1bit的数据呢,其实是为了接收设备能去正确的接收到8bit的有效数据,起始位相当于一帧数据的帧头,停止位相当于一帧数据的帧尾。

2.2起始位与停止位

起始位: 数据线TX由高电平变为低电平。
停止位: 数据线TX由低电平变为高电平。
起始位和停止位作用:
  如果接收设备检测到数据线由高电平变为低电平,就是接收到了来自发送设备的起始信号,表示开始数据的传输。如果接收设备检测到数据线由低电平变为高电平,就是接收到了来自发送设备的停止信号,表示一帧数据的结束,通过以上特点接收设备就可以将中间的8bit有效数据解析出来,这样就完成了一帧数据的传输。
解析逻辑分析仪捕捉的数据
  由以上分析知串口传输一帧数据构成:起始位(1bit)+数据(8bit)+停止位(1bit)。
解析逻辑分析仪获取的数据:
在这里插入图片描述
通道一:TX数据线
通道二:数据解析
通过通道一可以观察出一帧数据的格式确实为:起始位(1bit)+数据(8bit)+停止位(1bit)。中间8bit数据是通过(D0-D7:1010_1010)的顺序发送的,通过接收设备解析(高字节_低字节)为(D7-D0:0101_0101)即0x55。以上就为串口一帧数据的传输。
------所谓的波特率-----
进一步观察逻辑分析仪:
在这里插入图片描述
由标号①和②知1bit数据的传输时间为8.667us,那传输速率不就是 1 8.667 10 6 {1 \over {8.667*{{10}^{ - 6}}}} 其实就是115200bit/s。再看看我们串口助手设置的波特率就为115200,这样是不是明白波特率是什么了,其实不就是1s传输115200bit数据。
在这里插入图片描述

3.verilog串口的实现

经过上面的分析我们要明白:
● (1)在时钟为50M时,波特率设置为115200时,发送1bit数据,需要计数个数为434(时间为8.68us)。
● (2)串口传输一字节数据的数据格式为:起始位(1bit)+数据(8bit)+停止位(1bit)。
● (3)串口传输数据:先发送低位,后发送高位。
● (4)串口数据线在空闲时默认为高电平。

3.1 verilog实现代码:

实现波特率在115200下串口的发送,发送数据为0xc5(0101_1011),则串口发送数据的格式如下图所示:
在这里插入图片描述
代码:

//Terry-M
//-------
//波特率115200 传输1bit需要计数434
//_起始位_8bit数据_停止位_
//-------
module uart
(
	//输入
	input CLK_50M,			//系统时钟
	input RST_N,			//复位
	//输出
	output reg tx_flag,		//为了理解所引出的信号(在该信号置位的时候,串口TX数据线切换数据)
	output reg uart_tx		//串口TX引脚
);

//产生波特率所需要的计数
parameter 	cnt_max			= 9'd434;
parameter 	cnt_half		= 9'd217;
parameter 	tx_data			= 8'h5b;			//0101_1011
reg[8:0] 	bps_cnt;

//起始信号和停止信号
parameter start_signal = 1'b0;
parameter stop_signal  = 1'b1;

//状态机,传输10bit的状态
reg[7:0]  tx_state;
parameter tx_start	= 8'b0111_1111;
parameter tx_d0		= 8'b0000_0001;
parameter tx_d1		= 8'b0000_0010;
parameter tx_d2		= 8'b0000_0100;
parameter tx_d3		= 8'b0000_1000;
parameter tx_d4		= 8'b0001_0000;
parameter tx_d5		= 8'b0010_0000;
parameter tx_d6		= 8'b0100_0000;
parameter tx_d7		= 8'b1000_0000;
parameter tx_stop		= 8'b1111_1110;



//产生波特率,tx_flag=1为数据发送点
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
		bps_cnt <= 9'd0;
	else if(bps_cnt == cnt_max)
		bps_cnt <= 9'd0;
	else
		bps_cnt <= bps_cnt + 9'd1;
end

always@(bps_cnt)
begin
	if(bps_cnt == cnt_half)
		tx_flag <= 1'b1;
	else
		tx_flag <= 1'b0;
end

//发送数据 先发送低位再发送高位
always@(posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)
	begin
		uart_tx <= 1'b1;
		tx_state <= tx_start;
	end
	else if(tx_flag == 1)															//数据切换点
	begin
		case(tx_state)
		tx_start: begin uart_tx <= start_signal; tx_state <=tx_d0;end				//起始位
			tx_d0: begin uart_tx <= tx_data[0]; tx_state <=tx_d1;end					//D7
			tx_d1: begin uart_tx <= tx_data[1]; tx_state <=tx_d2;end					//D6
			tx_d2: begin uart_tx <= tx_data[2]; tx_state <=tx_d3;end					//D5
			tx_d3: begin uart_tx <= tx_data[3]; tx_state <=tx_d4;end					//D4
			tx_d4: begin uart_tx <= tx_data[4]; tx_state <=tx_d5;end					//D3
			tx_d5: begin uart_tx <= tx_data[5]; tx_state <=tx_d6;end					//D2
			tx_d6: begin uart_tx <= tx_data[6]; tx_state <=tx_d7;end					//D1
			tx_d7: begin uart_tx <= tx_data[7]; tx_state <=tx_stop;end				//停止位
			tx_stop: begin uart_tx <= 1'b1; tx_state <=tx_start; end
			default: uart_tx <= start_signal;
		endcase
	end
	else
		uart_tx <= uart_tx;
end

endmodule

3.2 SignalTap Ⅱ对FPGA内部信号进行逻辑分析

借助SignalTap Ⅱ软件对FPGA内置逻辑分析等如下:
在这里插入图片描述

3.3 通过逻辑分析仪解析数据校验数据

将FPGA的TX引脚接至逻辑分析仪获取以下波形:
在这里插入图片描述
逻辑分析仪解析数据为0x5B,数据正确。

3.4 与串口模块对接

通过FPGA的TX引脚连接CH340模块RX引脚,电脑串口助手接收数据如下:
在这里插入图片描述
接收数据为0x5B,数据正确。

★★★如有错误,欢迎指导!

猜你喜欢

转载自blog.csdn.net/qq_40147893/article/details/108303263