基于FPGA的UART串口接收模块设计.doc
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
UART串口接收模块设计
实验目标:实现FPGA接收其他设备通过UART协议发送过来的数据。
知识点:
1、URAT通信协议工业环境下数据接收实现。
2、In system sources and probes editor(ISSP)调试工具的使用。
UART发送端发送一个字节数据时序图:
对于其中的每一位进行采样,一般情况下每一位数据的中间点是最稳定的,因此一般应用中,
:
采集中间时刻时的数据即可,如下图所示
但是在工业应用中,往往有非常强的电磁干扰,只采样一次就作为该数据的电平判定,是不保险的,有可能恰好采集到被干扰的信号而导致结果出错,因此需要使用多次采样求概率的方式进行。
以下为改进型的单bit数据接收方式示意图:
12345678910111213141516
在这张图中,将每一位数据又平均分成了16小段,对于Bit_x这一位数据,考虑到数据在刚刚发生变化和即将发生变化的这一时期,数据极有可能不稳定的(用红色标出的两段),在这两个时间段采集数据,很有可能得到错误的结果,因此这两段时间的电平无效,采集时直接忽略。而中间这一时间段(用绿色标出),
数据本身是比较稳定的,一般都代表了正确的结果。但是也不排除该段数据受强电磁干扰而出现错误的电平脉冲,因此对这一段电平,进行多次采样,并求高低电平发生的概率,6次采集结果中,取出现次数多的电平作为采样结果。例如,采样6次的结果分别为1/1/1/1/0/1/,则取电平结果为1,若为0/0/1/0/0/0,,则取电平结果为0,当6次采样结果中1和0各占一半(各3次),则可判断当前通信线路环境非常恶劣,数据不具有可靠性。
串口发送模块包含两个主要组件:
1、起始位检测进程(低电平,下降沿)
2、波特率产生模块
3、数据接收模块
串口接收模块整体结构图:
波特率时钟计算:
Modelsim仿真图:
·在testbench文件中我们为设计输入了假定的信号,在仿真图中我们可以看到data_byte_r 在Rx_done标志位产生的时候成功的将仿真数据data_byte_t接收到其中。实现了串口接收数据的功能,其余各状态表现正常。
Rtl功能图
附录:源程序:
一,顶层功能代码
module uart_rx_top(Clk,Rst_n,Rs232_Rx);
input Clk;
input Rst_n;
input Rs232_Rx;
reg [7:0]data_rx_r;
wire [7:0]data_rx;
wire Rx_Done;
uart_byte_rx uart_byte_rx(
.Clk(Clk),
.Rst_n(Rst_n),
.baud_set(3'd0),
.Rs232_Rx(Rs232_Rx),
.data_byte(data_rx),
.Rx_Done(Rx_Done)
);
issp issp(
.probe(data_rx_r),
.source()
);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
data_rx_r <= 8'd0;
else if(Rx_Done)
data_rx_r <= data_rx;
else
data_rx_r <= data_rx_r; endmodule
二testbench仿真文件
`timescale 1ns/1ns
`define clk_period 20
module uart_byte_rx_tb;
reg Clk;
reg Rst_n;
reg Rs232_Rx;
wire [7:0]data_byte_r;
wire Rx_Done;
reg [7:0]data_byte_t;
reg send_en;
reg [2:0]baud_set;
wire Rs232_Tx;
wire Tx_Done;
wire uart_state;
uart_byte_rx uart_byte_rx(
.Clk(Clk),
.Rst_n(Rst_n),
.baud_set(baud_set),
.Rs232_Rx(Rs232_Tx),
.data_byte(data_byte_r),
.Rx_Done(Rx_Done)
);
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Rst_n(Rst_n),
.data_byte(data_byte_t),
.send_en(send_en),
.baud_set(baud_set),
.Rs232_Tx(Rs232_Tx),
.Tx_Done(Tx_Done),
.uart_state(uart_state)
);
initial Clk = 1;
always#(`clk_period/2)Clk = ~Clk;
initial begin
Rst_n = 1'b0;
data_byte_t = 8'd0;
send_en = 1'd0;
baud_set = 3'd4;
#(`clk_period*20 + 1 );
Rst_n = 1'b1;
#(`clk_period*50);
data_byte_t = 8'haa;
send_en = 1'd1;
#`clk_period;
send_en = 1'd0;
@(posedge Tx_Done)
#(`clk_period*5000);
data_byte_t = 8'h55;
send_en = 1'd1;
#`clk_period;
send_en = 1'd0;
@(posedge Tx_Done)
#(`clk_period*5000);
$stop;
end
endmodule