Verilog 实现 UART RX 接收器

 2023-09-05 阅读 67 评论 0

摘要:目录 1、简述 2、设计 3、实现 4、测试 1、简述 串口作为 CPU 最常使用的外设资源之一,常常出现在各种场合,既然最近在入坑 FPGA,那么先搞一个简单的串口接收机来玩玩; 串口相关的基本知识就不在这里重复议论了,参考我的另一篇文章《STM3

目录

1、简述

2、设计

3、实现

4、测试


 

1、简述

串口作为 CPU 最常使用的外设资源之一,常常出现在各种场合,既然最近在入坑 FPGA,那么先搞一个简单的串口接收机来玩玩;

串口相关的基本知识就不在这里重复议论了,参考我的另一篇文章《STM32F103ZET6 — USART》,总的来说,时序如下所示:

站在硬件的角度上来讲,要实现一个串口接收器,需要考虑一下几点内容:

1、串口通信,默认情况没有数据传送的时候,RX 线上空闲为高电平,出现起始位,线上会被拉低,那么首先考虑做一个下降沿检测器,来检测起始位;

2、发现起始位后,便需要进行线上数据的采样,采样的点,需要在数据的中心点,才能保证数据的稳定,那么就需要根据传送的波特率来计算采样的时间,并将数据采样到内部寄存器;

3、采样数据的个数,根据配置的数据位,校验位和停止位的 bit 数决定,那么就需要根据串口的配置,来对采样数据的个数进行计数,所以需要设计一个数据计时器;

 

2、设计

好了,简单的进行了需求分析和设计分解后,那么理想中的设计框图为:

1、PLL 接收来自外部的 25MHz 的晶振输入,将输出的时钟 clk 给 UART RX 模块,同时将时钟锁定的信号 Locked 接到 UART RX 的内部复位信号;

2、rx 信号直接接入到下降沿检测电路的输入,进行边沿检测,检测完成后,确定有起始位后,那么告诉波特率发生器,可以产生波特率信号;

3、波特率信号发生器根据输入的时钟和设置的波特率,进行计数,并在需要采样的点的地方,产生采样信号,供给下级电路;

4、状态机根据波特率的采样信号,来进行状态转换,从 IDLE 到 Sampling 状态,并在 Sampling 状态开始采样,并进行采样数据的计数;

5、当采样个数完成后,将数据并行的发送给后继的 FIFO,完成一帧数据的接收;

为了简化设计和仿真, 这里假设了波特率的 Counter 为 50(视具体波特率和输入时钟计算),8个数据位,没有校验位,1个停止位,并将采样后的数据直接以并行的形式输出;

 

3、实现

Verilog 源码设计如下(0 warning,0 error):

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    22:27:09 12/04/2019 
// Design Name: 
// Module Name:    uart_rx 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module uart_rx(input clk,input rst_n,input rx,output reg [9:0] data_out);// State Machine Definationparameter IDLE = 2'b01;parameter SAMP = 2'b10;// UART Configure Definationparameter START_BIT = 1;parameter DATA_BIT  = 8;parameter STOP_BIT  = 1;parameter PARI_BIT  = 0;parameter RECV_BIT  = START_BIT + DATA_BIT + STOP_BIT + PARI_BIT;// Negedge Detection Filterreg [3:0] data_in;
always @ (posedge clk or negedge rst_n)if (!rst_n) begindata_in[0] <= 1'b0;data_in[1] <= 1'b0;data_in[2] <= 1'b0;data_in[3] <= 1'b0;endelse begindata_in[0] <= rx;data_in[1] <= data_in[0];data_in[2] <= data_in[1];data_in[3] <= data_in[2];endwire rx_neg = data_in[3] & data_in[2] & (~data_in[1]) & (~data_in[0]);reg [1:0] current_state, next_state;// Current State To Next Statealways @ (posedge clk or negedge rst_n)if(!rst_n)current_state <= IDLE;elsecurrent_state <= next_state;// Statereg sample_finish;always @ (current_state or sample_finish or rx_neg)beginnext_state = 2'bx;case(current_state)IDLE : beginif (rx_neg) next_state = SAMP;else        next_state = IDLE;endSAMP : beginif (sample_finish) next_state = IDLE;else               next_state = SAMP;enddefault : next_state = IDLE;endcaseendreg [3:0] recv_cnt;reg sample_en;reg [RECV_BIT - 1 : 0] data_temp;always @ (posedge clk or negedge rst_n)if (!rst_n) begindata_out  <= 10'bx;data_temp <= 10'bx;sample_finish <= 1'b0;sample_en <= 1'b0;recv_cnt <= 4'b0;endelse begincase (next_state)IDLE : begin//data_out  <= 10'bx;data_temp <= 10'bx;sample_finish <= 1'b0;sample_en <= 1'b0;recv_cnt <= 4'b0;endSAMP : beginif (recv_cnt == RECV_BIT) begindata_out  <= data_temp;data_temp <= 10'bx;sample_finish <= 1'b1;sample_en <= 1'b0;recv_cnt  <= 4'b0;endelse beginsample_en <= 1'b1;if (baud_clk) begindata_out <= data_out;data_temp[recv_cnt] <= rx;sample_finish <= 1'b0;recv_cnt <= recv_cnt + 1'b1;endelse begindata_out <= data_out;data_temp <= data_temp;sample_finish <= sample_finish;recv_cnt <= recv_cnt;endendenddefault: begindata_out <= 10'bx;sample_finish <= 1'b0;sample_en <= 1'b0;endendcaseend// Sample Counter Signal Generatorparameter BAUD_MAX   = 50;reg [5:0] baud_cnt;always @ (posedge clk or negedge rst_n)if (!rst_n) beginbaud_cnt <= 6'd0;endelse beginif (sample_en) beginif (baud_cnt == BAUD_MAX - 1) baud_cnt <= 6'd0;else baud_cnt <= baud_cnt + 1'b1;endelse baud_cnt <= 6'd0;end// Sample Clock Signal Generatorparameter BAUD_CNT_H = (BAUD_MAX / 2);wire baud_clk = (baud_cnt == BAUD_CNT_H) ? (1'b1) : (1'b0);
endmodule

 

4、测试

测试的 testbench 为:

`timescale 1ns / 1ps// Company: 
// Engineer:
//
// Create Date:   14:03:06 12/05/2019
// Design Name:   uart_rx
// Module Name:   D:/Xlinx_ISE_Projects/testbench/uart_rx_tb.v
// Project Name:  test
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: uart_rx
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// module uart_rx_tb;// Inputsreg clk;reg rst_n;reg rx;// Outputswire [9:0] data_out;// Instantiate the Unit Under Test (UUT)uart_rx uut (.clk(clk), .rst_n(rst_n), .rx(rx), .data_out(data_out));
always #1 clk = ~clk;initial begin// Initialize Inputsclk = 0;rst_n = 0;rx = 1;// Wait 100 ns for global reset to finish#20;// Add stimulus hererst_n = 1;#20;// Generate Start bit#50 rx = 1'b0;// 8 data bits#100 rx = 1'b1;#100 rx = 1'b0;#100 rx = 1'b1;#100 rx = 1'b0;#100 rx = 1'b1;#100 rx = 1'b0;#100 rx = 1'b1;#100 rx = 1'b0;// Generate Stop bit#100 rx = 1'b1;#600;#100 rx = 1'b0;#100 rx = 1'b0;#100 rx = 1'b1;#100 rx = 1'b0;#100 rx = 1'b1;#100 rx = 1'b1;#100 rx = 1'b0;#100 rx = 1'b1;endendmodule

输出的波形为:

后一段为:

采样点为红色,均在数据中间,黄色为采样完成的信号;

 

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/126.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息