1.原理
在同步通信中,双方使用频率一致的时钟,在传输的过程中,时钟伴随这数据一起传输。发送方和接收方使用的时钟都是由主机提供的。UART接收方并不知道数据什么时候会到达,所以双方收发都需要各自的时钟。所以不需要发送时钟,发送方发送的时间可以不均匀,接收方在数据的起始位和停止位之间实现数据的同步。
因为数据收发都有独立的端口,所以可以实现全双工通信。
RS232很多传感器芯片或CPU都带有串口功能,方便调试,只有两条数据线,节约IO接口。
携带信息的传输单元叫码元。串口的位宽是1bit,每次只发送1bit数据,所以码元就表示一个2进制数。(就是说一个符号需要用几位二进制数表示)也就是1位。每秒钟通过信号传输的码元称为码元的传输速率,就是波特率。写作Baud,单位Bps(波特每秒)
每秒钟通信信道传输的信息量称为位传输速率简称比特率。单位是bps(每秒比特数)。比特率=波特率*每个调制单位对应的二进制数。比如9600波特率,9600*1=9600bps
串口发送或接收1bit数据的时间称为波特。比如9600Bps,波特就等于1/9600s。如果系统时钟是50MHZ,时钟周期是20ns,在9600波特率下,一个波特等于多少个时钟周期呢?一个波特=1s*10^9ns/9600/20=5208。就是5208个系统时钟周期,就是每个比特数据之间的间隔,或者每比特的一个数据,要在50MHZ时钟下保持5208个时钟周期。起始位和停止位的时间都是5208时钟周期。
异步的RX信号必须同步在系统时钟下,可以通过打一拍解决,但是打一拍之后仍然不能直接用于有效信号的提取,因为异步信号打一拍会引入新的问题就是亚稳态。
以上是信号同步的框图
以上是正确的
建立时间是指:在时钟上升沿以前,输入的数据要维持一段时间的稳定状态,数据稳定不变的最小时间称为建立时间。
保持时间:触发器时钟上升沿信号到来之后,在一段时间内数据也要稳定不变,数据稳定不变的最小时间称为保持时间。
由图可知建立时间与保持时间是不稳定的,是不满足条件的。
从寄存器时钟上升沿以后到开始出现震荡的位置,这段时间叫做寄存器延迟。就是上升沿采集到RX信号之后到Q端口寄存器输出之前,寄存器内部有一个延迟时间,这个时间就叫做寄存器延迟。
Q端口输出不稳定数据的这一段时间称为决断时间。
(一)亚稳态产生的原因可能包括以下几点:
- 建立时间和保持时间违规:触发器在设计时都有特定的建立时间和保持时间。建立时间是指数据信号必须在时钟上升沿到来之前的一段时间内稳定;保持时间是指数据信号必须在时钟上升沿到来之后的一段时间内保持稳定。如果这些时间要求没有得到满足,触发器可能无法正确采样到数据,从而进入亚稳态。
- 时钟漂移和抖动:在实际电路中,时钟信号可能会因为多种原因(如温度变化、电源波动等)而出现漂移或抖动,这可能导致触发器的时钟边沿与数据信号的到达时间不匹配,从而产生亚稳态。
- 信号传播延迟:在数字电路中,信号从源到目的地的传播会有一定的延迟。如果这个延迟足够长,以至于信号在时钟周期内无法稳定到达,那么接收该信号的触发器可能会进入亚稳态。
- 异步信号处理:在处理异步信号时,尤其是跨时钟域的信号传输,如果没有适当的同步措施,很容易因为时钟域之间的不一致而导致亚稳态的产生。
- 系统时钟频率过高:当系统时钟频率提高时,留给数据信号稳定的时间窗口会变小,增加了违反建立时间和保持时间的风险,从而提高了亚稳态发生的概率。
- 电磁干扰:外部的电磁干扰也可能导致信号在传输过程中产生毛刺或者不稳定,进而引起亚稳态。
- 电源噪声:电源线路上的噪声也可能影响触发器的正常工作,尤其是在高速或高密度集成电路中,电源噪声对亚稳态的影响更为显著。
- 温度效应:温度的变化会影响半导体材料的特性,包括阈值电压和载流子迁移率,这些变化可能导致触发器的工作状态受到影响,从而产生亚稳态
(二)亚稳态的危害可能包括以下几点:
亚稳态的危害很大,如果后面是组合逻辑,那么亚稳态是消除不了的,会一直抖动。
- 逻辑误判:由于亚稳态导致触发器的输出无法预测,可能会被后续的逻辑电路错误地识别为0或1,从而引发逻辑错误。
- 毛刺产生:亚稳态可能导致输出信号出现毛刺,这些短暂的信号波动可能会被后续的逻辑电路捕捉到,引起不必要的逻辑动作或者故障。
- 系统故障:亚稳态的输出在稳定之前可能是振荡或固定的某一电压值,这些不稳定的信号传播到后续的逻辑电路中,可能会导致整个系统的故障。
- 传播性:亚稳态不仅影响单个触发器,还可能导致整个系统中的其他部分也进入亚稳态,这种连锁反应会严重影响系统的可靠性和稳定性。
- 性能下降:亚稳态会使得触发器的输出保持在不稳定状态较长时间,这会影响到电路的性能,尤其是在高速数字系统中,这种延迟可能会导致系统性能显著下降。
(三)消除亚稳态可以采取以下措施:
- 降低系统时钟频率:通过减少时钟频率,可以增加每个时钟周期的时间,从而给数据信号提供更多的时间来稳定,减少亚稳态的发生概率。
- 使用反应更快的触发器:选择边沿变化快、响应时间短的触发器,可以加快信号的采样和稳定过程,减少亚稳态的可能性。
- 引入同步机制:对于跨时钟域的信号,可以使用双寄存器同步(两个连续的触发器)来对异步信号进行同步处理,这有助于防止亚稳态传播到后续的逻辑电路中。
- 改善时钟质量:提高时钟信号的质量,确保时钟信号的边沿变化快速且清晰,有助于触发器正确采样数据信号,减少亚稳态的风险。
- 采用FIFO缓冲设计:在跨时钟域的数据通信中使用先进先出(FIFO)缓冲区,可以暂存数据直到目标时钟域准备好接收,从而避免亚稳态的产生。
- 复位电路的处理:对复位电路采用异步复位、同步释放的方式处理,可以确保在复位过程中不会因为亚稳态而导致不确定的行为。
注意:单比特信号从高速时钟域同步到低速时钟域,使用打拍的方式会出现数据的漏采。所以往往使用脉冲同步或者握手信号的方式实行数据的同步。多比特信号进行跨时钟域的处理一般要进行格雷码的编码,然后进行打拍处理,或者使用fifo,ram来进行数据的同步。
打了3拍。第一拍是为了同步到系统时钟下,后两拍是为了减小亚稳态的影响。
发送1bit数据需要5208个时钟周期。
2.1 uart_rx.v
module uart_rx
#(
parameter UART_BPS= 'd9600,
parameter CLK_FREQ= 'd50_000_000
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output reg [7:0] po_data ,
output reg po_flag
);
parameter BAUD_CNT_MAX=CLK_FREQ/UART_BPS;
reg rx_reg1;
reg rx_reg2;
reg rx_reg3;
reg start_flag;
reg work_en;
reg [15:0] baud_cnt;//13位要写成16位提高兼容性,更低波特率时计数位宽有所增加
reg bit_flag;
reg [3:0] bit_cnt;
reg [7:0]rx_data;
reg rx_flag;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
begin
rx_reg1<=1'b1;
rx_reg2<=1'b1;
rx_reg3<=1'b1;
end
else
begin
rx_reg1<=rx;
rx_reg2<=rx_reg1;
rx_reg3<=rx_reg2;
end
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
start_flag<=1'b0;
else if((rx_reg3==1'b1)&&(rx_reg2==1'b0)&&(work_en==1'b0))//注意使能信号为低电平,因为如果只有前两个条件在数据传输过程中也可能会有下降沿,此时就会又拉高一个起始信号
start_flag<=1'b1;
else
start_flag<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
work_en<=1'b0;
else if((bit_cnt==4'd8)&&(bit_flag==1'b1)) //这里我没有考虑到bit_flag为高电平的条件
work_en<=1'b0;
else if(start_flag==1'b1)
work_en<=1'b1;
else
work_en<=work_en;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
baud_cnt<=16'd0;
else if((baud_cnt==BAUD_CNT_MAX-1'b1)||(work_en==1'b0))
baud_cnt<=16'd0;
else if(work_en==1'b1)
baud_cnt<=baud_cnt+1'b1;
else
baud_cnt<=baud_cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
bit_flag<=1'b0;
else if(baud_cnt==BAUD_CNT_MAX/2-1) //5208/2=2604
bit_flag<=1'b1;
else
bit_flag<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
bit_cnt<=4'd0;
else if((bit_cnt==4'd8)&&(bit_flag==1'b1)) //这里我没有想到bit_flag==1'b1的条件
bit_cnt<=4'd0;
else if(bit_flag==1'b1)
bit_cnt<=bit_cnt+1'b1;
else
bit_cnt<=bit_cnt;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rx_data<=8'd0;
else if((bit_cnt>=4'd1)&&(bit_cnt<=4'd8)&&(bit_flag==1'b1)) //没有想到bit_flag==1'b1的条件
rx_data<={rx_reg3,rx_data[7:1]}; //这里每来一位,rx_data就向右移动一位,所以先传递的应该是低位。Uart传输数据时先传送字符的低位,后传送字符的高位。即低位(LSB)在前,高位(MSB)在后。
else
rx_data<=rx_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rx_flag<=1'b0;
else if ((bit_cnt==4'd8)&&(bit_flag==1'b1)) //没有想到bit_flag==1'b1的条件
rx_flag<= 1'b1;
else
rx_flag<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
po_data<=8'd0;
else if(rx_flag==1'b1)
po_data<=rx_data;
else
po_data<=8'd0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
po_flag<=1'b0;
else
po_flag<=rx_flag; //这里我原来也写错了
endmodule