RS-232 Receiver

news/2024/10/22 11:29:59/

上篇博文讲到了RS-232 Transmitter,这篇博文讲RS-232 Receiver.

如下Receiver示意图:

我们的实现是这样的:

该模块在RxD线路上组装数据。
当接收到一个字节时,它出现在“数据”总线上。 一旦收到完整的字节,“data_ready”就会被置位一个时钟。
请注意,“data”仅在“data_ready”被声明时有效。 剩下的时间,不要使用它,因为新的数据可能会混乱。

过采样


异步接收器必须以某种方式与输入信号同步(它通常无法访问发送器使用的时钟)。

为了确定新数据字节何时到来,我们通过以波特率频率的倍数对信号进行过采样来寻找“开始”位。
一旦检测到“开始”位,我们就以已知的波特率对线路进行采样,以获取数据位。
接收器通常以波特率的16倍对输入信号进行过采样。 我们在这里使用了8次......对于115200个波特,它的采样率为921600Hz。

假设我们有一个“Baud8Tick”信号,每秒有效921600次。

既然是要产生这样的波特率,我们给出波特率产生代码(RS232 波特率时钟产生方法?):

module BaudGen #(parameter Clkfrequency = 25000_000,parameter Baud = 115200,parameter Oversampling = 8,parameter Ratio = Clkfrequency/(Baud*Oversampling),parameter AddWidth = 16,parameter Inc = (1<<AddWidth)/Ratio)
(input clk,input enable,output BaudTick);reg [AddWidth:0] acc = 0;always@(posedge clk) beginif(enable) beginacc <= acc[AddWidth - 1 : 0] + Inc;endelse beginacc <= Inc;endendassign BaudTick = acc[AddWidth];endmodule

测试代码:

`timescale 1ns / 1ps
module BaudGen_tb;reg clk;reg enable;wire BaudTick;initial beginclk = 0;forever#20 clk = ~clk;endinitial enable = 1;BaudGen Baud8Gen(.clk(clk),.enable(1),.BaudTick(BaudTick));endmodule

之前,产生115200波特率的仿真图中,8点几usBaudTick有效一个时钟,如今,要产生8倍波特率,所以按理说,BaudTick应该1点几us有效一次,发现确实如此。

使用此波特率时钟,可以达到过采样的目的。

其他模块设计设计


首先,输入的“RxD”信号与我们的时钟没有关系。
我们使用两个D触发器对其进行过采样,并将其与我们的时钟域同步。

 

reg [1:0] RxD_sync;
always @(posedge clk) if(Baud8Tick) RxD_sync <= {RxD_sync[0], RxD};

紧接着我们过滤数据,因此RxD线上的短尖峰不会让起始位出错。

reg [1:0] RxD_cnt;
reg RxD_bit;

always @(posedge clk)
if(Baud8Tick)
begin
  if(RxD_sync[1] && RxD_cnt!=2'b11) RxD_cnt <= RxD_cnt + 1;
  else 
  if(~RxD_sync[1] && RxD_cnt!=2'b00) RxD_cnt <= RxD_cnt - 1;

  if(RxD_cnt==2'b00) RxD_bit <= 0;
  else
  if(RxD_cnt==2'b11) RxD_bit <= 1;
end

一旦检测到“开始”,状态机允许我们检查接收到的每个位。

reg [3:0] state;

always @(posedge clk)
if(Baud8Tick)
case(state)
  4'b0000: if(~RxD_bit) state <= 4'b1000; // start bit found?
  4'b1000: if(next_bit) state <= 4'b1001; // bit 0
  4'b1001: if(next_bit) state <= 4'b1010; // bit 1
  4'b1010: if(next_bit) state <= 4'b1011; // bit 2
  4'b1011: if(next_bit) state <= 4'b1100; // bit 3
  4'b1100: if(next_bit) state <= 4'b1101; // bit 4
  4'b1101: if(next_bit) state <= 4'b1110; // bit 5
  4'b1110: if(next_bit) state <= 4'b1111; // bit 6
  4'b1111: if(next_bit) state <= 4'b0001; // bit 7
  4'b0001: if(next_bit) state <= 4'b0000; // stop bit
  default: state <= 4'b0000;
endcase

请注意,我们使用了“next_bit”信号,从一个位到另一个位。(如何过采样的时钟是波特率的16倍可以这么写)

reg [2:0] bit_spacing;

always @(posedge clk)
if(state==0)
  bit_spacing <= 0;
else
if(Baud8Tick)
  bit_spacing <= bit_spacing + 1;

wire next_bit = (bit_spacing==7);

Finally a shift register collects the data bits as they come.

reg [7:0] RxD_data;
always @(posedge clk) if(Baud8Tick && next_bit && state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]};

上面的解析是参考链接的原作者的意思(https://www.fpga4fun.com/SerialInterface4.html),最后人家还提供了总体代码,但是由于我的水平还没达到那么水准,所以阅读起来比较困难,所以改成了自己的版本并仿真测试。

接收器的Verilog描述为:

`timescale 1ns / 1ps
//
// Engineer: Reborn Lee
// Create Date: 2019/05/26 21:02:29
// Module Name: asy_receiver
//module asy_receiver(input clk,input RxD,//The module assembles data from the RxD line as it comes.output reg [7:0] RxD_data,output reg RxD_data_ready //As a byte is being received, it appears on the "data" bus. Once a complete byte has been received, "data_ready" is asserted for one clock.);parameter Clkfrequency = 25000000; // 25MHzparameter Baud = 115200;parameter Oversampling = 8;  // needs to be a power of 2// we oversample the RxD line at a fixed rate to capture each RxD data bit at the "right" time// 8 times oversampling by default, use 16 for higher quality receptionreg [3:0] RxD_state = 0;wire OversamplingTick; //过采样时钟BaudGen  #(.Clkfrequency(Clkfrequency),.Baud(Baud),.Oversampling(Oversampling))U_Baud8Gen(.clk(clk),.enable(1'b1),.BaudTick(OversamplingTick));/* 	wire RxD_bit = RxD;wire sampleNow = 1'b1;  // receive one bit per clock cycle */// synchronize RxD to our clk domainreg [1:0] RxD_sync = 2'b11;always @(posedge clk) if(OversamplingTick) RxD_sync <= {RxD_sync[0], RxD};// and filter itreg [1:0] Filter_cnt = 2'b11;reg RxD_bit = 1'b1;always @(posedge clk)if(OversamplingTick) beginif(RxD_sync[1]==1'b1 && Filter_cnt!=2'b11) Filter_cnt <= Filter_cnt + 1'd1;else if(RxD_sync[1]==1'b0 && Filter_cnt!=2'b00) Filter_cnt <= Filter_cnt - 1'd1;if(Filter_cnt==2'b11) RxD_bit <= 1'b1;elseif(Filter_cnt==2'b00) RxD_bit <= 1'b0;end// and decide when is the good time to sample the RxD linefunction integer log2(input integer v); //定义一个函数用于求Oversampling的位数begin log2=0; while(v>>log2) log2=log2+1; end endfunctionparameter l2o = log2(Oversampling);reg [l2o-2:0] OversamplingCnt = 0;always @(posedge clk) if(OversamplingTick) OversamplingCnt <= (RxD_state==0) ? 1'd0 : OversamplingCnt + 1'd1;wire sampleNow = OversamplingTick && (OversamplingCnt==Oversampling/2-1);// now we can accumulate the RxD bits in a shift-registeralways @(posedge clk)case(RxD_state)4'b0000: if(~RxD_bit) beginRxD_state <= 4'b0001;  // start bit found?//RxD_state <= 4'b1000;end4'b0001: if(sampleNow) RxD_state <= 4'b1000;  // sync start bit to sampleNow4'b1000: if(sampleNow) RxD_state <= 4'b1001;  // bit 04'b1001: if(sampleNow) RxD_state <= 4'b1010;  // bit 14'b1010: if(sampleNow) RxD_state <= 4'b1011;  // bit 24'b1011: if(sampleNow) RxD_state <= 4'b1100;  // bit 34'b1100: if(sampleNow) RxD_state <= 4'b1101;  // bit 44'b1101: if(sampleNow) RxD_state <= 4'b1110;  // bit 54'b1110: if(sampleNow) RxD_state <= 4'b1111;  // bit 64'b1111: if(sampleNow) RxD_state <= 4'b0010;  // bit 74'b0010: if(sampleNow) RxD_state <= 4'b0000;  // stop bitdefault: RxD_state <= 4'b0000;endcasealways @(posedge clk)if(sampleNow && RxD_state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]};always @(posedge clk) beginRxD_data_ready <= (sampleNow && RxD_state==4'b0010 && RxD_bit);  // make sure a stop bit is receivedendendmodule

测试文件为:

`timescale 1ns / 1psmodule asy_receiver_tb();reg clk;reg RxD;wire RxD_data_ready;wire [7 : 0] RxD_data;  // data received, valid only (for one clock cycle) when RxD_data_ready is assertedparameter DATA0 = 10'b1101001010; //从低位开始发送
//	parameter DATA1 = 10'b1010011010;reg [9:0] data_in;integer i;initial beginclk = 0;forever #20 clk = ~clk;endinitial begindata_in = DATA0;for(i = 0; i < 9; i = i + 1) begin#8700	RxD = data_in[i];end#26100for(i = 0; i < 9; i = i + 1) begin#8700	RxD = data_in[i];end//#10000 $stop;endasy_receiver u0(.clk(clk),.RxD(RxD),.RxD_data_ready(RxD_data_ready),.RxD_data(RxD_data));endmodule

仿真波形:

没有认真分析代码,也许会看的眼花缭乱,但是我们仍可以从中看出一些信息:

例如RxD_data_ready有效的时刻,代表着此时我们接受的数据可以使用了。

稍微放大:

从这个仿真波形我们可以看出,我们的RxD_bit,我们采样也是采样的这个信号,它是RxD同步且滤波后的输出。

就到这里吧。

下一篇博文,还要讲讲如何联合用这些模块。

参考链接:博文中已给出


http://www.ppmy.cn/news/174878.html

相关文章

RS-232、RS-485、RS-422通信接口标准介绍

目录 前言&#xff1a; RS-232&#xff08;全双工&#xff09; 1.1 RS-232接口介绍&#xff1a; 1.2 RS-232信号转换芯片介绍&#xff1a; 1.3 接口电子特性&#xff1a; 1.4 通讯距离长短&#xff1a; 1.5 能否支持多点通讯&#xff1a; RS-485&#xff08;半双工两线…

RS232

RS-232是现在主流的串行通信接口之一&#xff1a; &#xff08;1&#xff09;接口的信号电平值较高&#xff0c;易损坏接口电路的芯片。RS232接口任何一条信号线的电压均为负逻辑关系。即&#xff1a;逻辑“1”为-5—-15V&#xff1b;逻辑“0”&#xff1a;5—15V&#xff0c;噪…

RS232RS485基本简介

下文是我自己对于RS485以及RS232的理解与记录&#xff0c;在习得新知识后会继续更新&#xff0c;文章如有错误之处&#xff0c;还望读者指正交流 一.RS232以及RS485应运而生的背景 1.在谈论正文之前我们先说一下UART,它的全称为通用异步串行接口&#xff0c;如果是芯片与芯片之…

【RS-422与RS-485】RS-422与RS-485串行接口标准

RS-232串行接口标准 目前RS-232是PC机与通信工业中应用最广泛的一种串行接口。RS-232被定义为一种在低速率串行通讯中增加通讯距离的单端标准。RS-232采取不平衡传输方式&#xff0c;即所谓单端通讯。 由于其发送电平与接收电平的差仅为2V至3V左右&#xff0c;所以其共模抑制能…

RS2323 RS485

RS232 硬件直接对接&#xff0c;程序完全来自于USART由sp3232将TTL电平转化为RS232的标准电平实际应用中需要注意RS232对于2脚和3脚的直连或交叉接&#xff0c;现成的RS232当然不会有这个问题&#xff0c;但是自己DIY的时候要注意防止接反&#xff08;如图3 图4&#xff09; R…

RS232 RS422 RS 485

RS232特点&#xff1a; RS-232是现在主流的串行通信接口之一。由于RS232接口标准出现较早&#xff0c;难免有不足之处&#xff0c;主要有以下四点&#xff1a; &#xff08;1&#xff09;接口的信号电平值较高&#xff0c;易损坏接口电路的芯片。RS232接口任何一条信号线的电压…

RS232,484,422区别

RS232,484,422区别 1、RS-232-C RS-232-C是美国电子工业协会EIA&#xff08;Electronic Industry Association&#xff09;制定的一种串行物理接口标准。RS是英文“推荐标准”的缩写&#xff0c;232为标识号&#xff0c;C表示修改次数。它的全名是"数据终端设备&#xf…

RS-232(or RS-485)、ch340(or cp2102)的关系

一、首先要知道几点&#xff1a; 1.PC是RS-232电平&#xff08;简称232&#xff09;&#xff0c;单片机是TTL电平&#xff0c;两者是不兼容的&#xff1b; 2.另外&#xff0c;老台式机可能会有DB9串口&#xff0c;但那输出的是232电平信号&#xff0c;所以不能直接与MCU相连&am…