前言
在上一篇文章《详解UART通信协议以及FPGA实现》我们实现了UART的通信,我们知道UART通信需要双方约定好波特率,如果想要更换波特率,则需要重新更改代码,重新编译,十分的不方便。所以有没有一种方案就能让通信双方不约定波特率,主机按照主机的波特率发送数据,从机自适应调整自己的波特率跟主机通信。在实际中可以采用特征值匹配的方法实现自适应波特率发生器。
一、特征值自适应原理
在双方开始通信前,主机通过串行接口以自己设定的通信波特率向从机发送 1 个字节的波特率校准信号0X55,从机测量每一个高与低电平的宽度,不算起始位和停止位,一共测量8个码元的宽度值W,最后再除以8得到一个码元的宽度bitwidth,再用测量的码元宽度与典型波特率的码元宽度进行比较,误差1%范围内就算匹配成功。
b i t w i d t h = W 8 bitwidth = \frac{W}{8} bitwidth=8W
二、整体结构框图
接收模块在rx线拉低时候,开始接收0X55的校准信号,同时计算每个高低电平的宽度,计算完成后,拉高auto_done信号和正确的波特率码元宽度值给tx模块,tx模块根据新的波特率进行发送。
三、接收模块
- 判断模块:由于典型波特率大部分都成倍数关系,因此码元宽度也成倍数关系,防止给计算模块造成误导,因此保险起见,记录上每个高低电平的宽度。否则如果只计算一个码元的宽度,很容易算错,例如以下情况:
设定系统时钟频率50M,如果主机以115200波特率发送(0X66)数据,如果只判断一个码元的长度,那么计算的值将会是868(波特率为57600),不符合设计要求。
因此我们设定一个bit宽度计数器,每隔一个沿开始,清空此计数器,如果次计数器超过了最大码元宽度值,表示此数据不是特征值0X55,调整失败。否者就一直累加8次,最后判断一个码元宽度是否在典型波特率的1%误差范围内。
典型波特率码元宽度值 | |||||
波特率 | 码元宽度 | ||||
1200 | CLK_FREQ/1200 | ||||
2400 | CLK_FREQ/2400 | ||||
4800 | CLK_FREQ/4800 | ||||
9600 | CLK_FREQ/9600 | ||||
19200 | CLK_FREQ/19200 | ||||
38400 | CLK_FREQ/38400 | ||||
57600 | CLK_FREQ/57600 | ||||
115200 | CLK_FREQ/115200 |
- 接收模块:与上文的rx模块基本上一致,只是接受数据前判断auto_done信号,如果信号拉高了,表示波特率更新完成,可以正常接收数据,然后调整自己的波特率计算值,准备接收数据。否者不会接收数据。
四、发送模块
与上文的rx模块基本上一致,只是接受数据前判断auto_done信号,如果信号拉高了,表示波特率更新完成,可以正常发送数据,然后调整自己的波特率计算值,准备发送数据。否者不会发送数据。代码如下:
`timescale 1ns / 1ps
module uart_tx
(
input clk ,
input rst_n ,
input [23:0] baud_cnt_max ,
input auto_done ,
input [7:0] tx_data , //发送数据
input tx_data_en , //发送数据有效信号
output reg tx
);
reg [7:0] tx_data_reg ;
reg [23:0] baud_cnt ;
reg [3:0] bit_cnt ;
reg bit_flag;
reg tx_flag ;
//将待发送的数据缓存起来
always @(posedge clk or negedge rst_n) begin
if