【FPGA】FPGA实现UART串口通信回环

这篇具有很好参考价值的文章主要介绍了【FPGA】FPGA实现UART串口通信回环。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、UART协议基础

关于UART协议的基础理论部分已经在上一篇文章中讲述,不再重复介绍。
UART通信协议
本文主要介绍如何使用Verlilog编程,通过FPGA实现UART串口通信回环工程。在本工程中所使用的系统时钟为50MHz,如果选择115200的波特率进行数据传输,那么传输1bit所用的时钟周期数就是50_000_000 / 115200。

二、系统模块划分

【FPGA】FPGA实现UART串口通信回环
uart模块: uart串口通信顶层设计模块,包含uart_tx、uart_rx、control模块。
uart_rx模块: UART串口数据接收模块,将上位机发送的串行数据接收后转换成并行数据发送给control模块。
control模块: UART控制模块,将接收到的并行数据存储到FIFO中,当读FIFO条件满足时输出。
uart_tx模块: UART串口数据发送模块,将从control读出的并行数据转换成串行数据发送给上位机。

三、代码实现

1、uart顶层设计模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.04                        
//  Design Name: uart    
//  Module Name: uart         
//  Target Device: Cyclone IV E (EP4CE6F17C8)             
//  Tool versions: Quartus Prime 18.1             
//  Description: UART串口通信顶层设计模块                               
//  **************************************************************           
module uart (
    input               clk             ,
    input               rst_n           ,

    input               uart_rxd        ,
    output              uart_txd         
);

    //  信号定义
    wire    [7:0]       rx_dout         ;
    wire                rx_dout_vld     ;
    wire    [7:0]       ctrl_dout       ;   
    wire                ctrl_dout_vld   ;
    wire                ready           ;

    //  模块例化
    uart_rx u_uart_rx (
        /*input               */.clk             (clk           ),
        /*input               */.rst_n           (rst_n         ),
        /*input               */.uart_rx         (uart_rxd      ),       //  接收到的串口数据
  
        /*output  [7:0]       */.rx_dout         (rx_dout       ),       //  串行数据转换成并行数据后输出给control模块
        /*output              */.rx_dout_vld     (rx_dout_vld   )
    );

    control u_control (
        /*input               */.clk             (clk           ),
        /*input               */.rst_n           (rst_n         ),
        /*//  uart_rx*/
        /*input   [7:0]       */.rx_din          (rx_dout       ),
        /*input               */.rx_din_vld      (rx_dout_vld   ),
        /*//  uart_tx*/
        /*input               */.ready           (ready         ),
        /*output  [7:0]       */.ctrl_dout       (ctrl_dout     ),
        /*output              */.ctrl_dout_vld   (ctrl_dout_vld )
    );

    uart_tx u_uart_tx (
        /*input               */.clk            (clk            ),
        /*input               */.rst_n          (rst_n          ),
        /*//  control*/
        /*input   [7:0]       */.tx_din         (ctrl_dout      ),
        /*input               */.tx_din_vld     (ctrl_dout_vld  ),
        /*output              */.ready          (ready          ),       //  给control模块的握手信号,表示可以接收数据进行发送 
        /*//  上位机*/
        /*output              */.uart_tx        (uart_txd       )
    );
    
endmodule


2、uart_rx串口数据接收模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.04                        
//  Design Name: uart    
//  Module Name: uart_rx         
//  Target Device: Cyclone IV E (EP4CE6F17C8)             
//  Tool versions: Quartus Prime 18.1             
//  Description: UART串口通信数据接收模块                               
//  **************************************************************     
`include "param.v"      
module uart_rx (
    input               clk             ,
    input               rst_n           ,
    input               uart_rx         ,       //  接收到的串口数据

    output  [7:0]       rx_dout         ,       //  串行数据转换成并行数据后输出给control模块
    output              rx_dout_vld     
);

    //  参数定义

    //  信号定义
    reg     [19:0]      cnt_baud        ;       //      波特率计数器
    wire                add_cnt_baud    ;
    wire                end_cnt_baud    ; 

    reg     [3:0]       cnt_bit         ;       //      bit计数器
    wire                add_cnt_bit     ;
    wire                end_cnt_bit     ;

    reg                 rx_flag         ;       //  开始接收数据标志
    reg     [1:0]       uart_rx_r       ;       //  uart_rx同步打拍
    wire                rx_nedge        ;       //  uart_rx下降沿

    reg     [9:0]       dout_data       ;

    //  cnt_baud
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_baud <= 0 ;
        end
        else if(add_cnt_baud)begin
            if(end_cnt_baud)begin
                cnt_baud <= 0 ;
            end				
            else begin	    
                cnt_baud <= cnt_baud + 1 ;
            end 		    
        end
    end
    assign	add_cnt_baud =	rx_flag ;
    assign	end_cnt_baud =  add_cnt_baud && (cnt_baud == `BAUD - 1) ;

    //  cnt_bit
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bit <= 0 ;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 0 ;
            end				
            else begin	    
                cnt_bit <= cnt_bit + 1 ;
            end 		    
        end
    end
    assign	add_cnt_bit = end_cnt_baud ;
    assign	end_cnt_bit = add_cnt_bit && (cnt_bit == 9 || dout_data[0] == 1'b1) ;       

    //  uart_rx_r
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            uart_rx_r <= 0 ;
        end
        else begin
            uart_rx_r <= {uart_rx_r[0],uart_rx} ;
        end
    end

    //  uart_rx下降沿检测
    assign  rx_nedge = ~uart_rx_r[0] & uart_rx_r[1] ;

    //  rx_flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rx_flag <= 1'b0 ;
        end
        else if(rx_nedge)begin
            rx_flag <= 1'b1 ;
        end
        else if(end_cnt_bit)begin
            rx_flag <= 1'b0 ;
        end
    end

    //  dout_data
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            dout_data <= 0 ;
        end
        else if(rx_flag & cnt_baud == 0)begin
            dout_data[cnt_bit] <= uart_rx_r[0] ;
        end
    end

    //  输出
    assign  rx_dout = dout_data[8:1] ;
    assign  rx_dout_vld = end_cnt_bit && dout_data[0] == 1'b0 ;

endmodule

3、control控制模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.04                        
//  Design Name: uart    
//  Module Name: control         
//  Target Device: Cyclone IV E (EP4CE6F17C8)             
//  Tool versions: Quartus Prime 18.1             
//  Description: UART串口通信控制模块                               
//  **************************************************************     
`include "param.v"      
module control (
    input               clk             ,
    input               rst_n           ,
    //  uart_rx
    input   [7:0]       rx_din          ,
    input               rx_din_vld      ,
    //  uart_tx
    input               ready           ,
    output  [7:0]       ctrl_dout       ,
    output              ctrl_dout_vld   
);

    //  参数定义

    //  信号定义
    wire                rdreq           ;
    wire                wrreq           ;
    wire    [7:0]       fifo_q          ;
    wire                rdempty         ;
    wire    [2:0]       rdusedw         ;
    wire                wrfull          ;
    wire    [2:0]       wrusedw         ;

    reg                 rd_flag         ;       //  fifo可读标志

    //  rd_flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rd_flag <= 1'b0 ;
        end
        else if(rdusedw > 4)begin
            rd_flag <= 1'b1 ;
        end
        else if(rdempty)begin
            rd_flag <= 1'b0 ;
        end
    end

    //  fifo例化
    fifo	fifo_inst (
	    .aclr       ( ~rst_n        ),
	    .data       ( rx_din        ),
	    .rdclk      ( clk           ),
	    .rdreq      ( rdreq         ),
	    .wrclk      ( clk           ),
	    .wrreq      ( wrreq         ),

	    .q          ( fifo_q        ),
	    .rdempty    ( rdempty       ),
	    .rdusedw    ( rdusedw       ),
	    .wrfull     ( wrfull        ),
	    .wrusedw    ( wrusedw       )
	);

    assign  wrreq = ~wrfull && rx_din_vld ;
    assign  rdreq = rd_flag && ready ;

    //  输出
    assign  ctrl_dout = fifo_q ;
    assign  ctrl_dout_vld = rdreq ;
    
endmodule

4、uart_tx串口数据发送模块

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.04                        
//  Design Name: uart    
//  Module Name: uart_tx         
//  Target Device: Cyclone IV E (EP4CE6F17C8)             
//  Tool versions: Quartus Prime 18.1             
//  Description: UART串口通信数据发送模块模块                               
//  **************************************************************     
`include "param.v"  
module uart_tx (
    input               clk             ,
    input               rst_n           ,
    //  control
    input   [7:0]       tx_din          ,
    input               tx_din_vld      ,
    output              ready           ,       //  给control模块的握手信号,表示可以接收数据进行发送 
    //  上位机
    output              uart_tx         
);
    
    //  参数定义

    //  信号定义
    reg     [19:0]      cnt_baud        ;       //  波特率计数器
    wire                add_cnt_baud    ;
    wire                end_cnt_baud    ; 

    reg     [3:0]       cnt_bit         ;       //  bit计数器
    wire                add_cnt_bit     ;
    wire                end_cnt_bit     ;

    reg                 tx_flag         ;       //  数据传输标志

    reg     [9:0]       tx_data         ;       //  寄存将要发送的数据
    reg                 dout            ;       //  并行数据转串行数据发送

    reg                 vld             ;


    //  cnt_baud
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_baud <= 0 ;
        end
        else if(add_cnt_baud)begin
            if(end_cnt_baud)begin
                cnt_baud <= 0 ;
            end				
            else begin	    
                cnt_baud <= cnt_baud + 1 ;
            end 		    
        end
    end
    assign	add_cnt_baud =	tx_flag ;
    assign	end_cnt_baud = add_cnt_baud && (cnt_baud == `BAUD - 1) ;

    //  cnt_bit
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bit <= 0 ;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 0 ;
            end				
            else begin	    
                cnt_bit <= cnt_bit + 1 ;
            end 		    
        end
    end
    assign	add_cnt_bit = end_cnt_baud ;
    assign	end_cnt_bit = add_cnt_bit && (cnt_bit == 9) ;   
    
    //  tx_flag
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            tx_flag <= 1'b0 ;
        end
        else if(tx_din_vld)begin
            tx_flag <= 1'b1 ;
        end
        else if(end_cnt_bit)begin
            tx_flag <= 1'b0 ;
        end
    end

    //  vld
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            vld <= 1'b0 ;
        end
        else begin
            vld <= tx_din_vld ;
        end
    end

    //  tx_data
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            tx_data <= 0 ;
        end
        else if(vld)begin
            tx_data <= {1'b1,tx_din,1'b0} ;     //      停止位 + 数据 + 起始位  低位在前发送
        end
    end

    //  dout
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            dout <= 1'b1 ;
        end
        else if(tx_flag)begin
            dout <= tx_data[cnt_bit] ;
        end
    end

    //  输出
    assign  uart_tx = dout ;
    assign  ready = ~tx_flag ;


endmodule

四、仿真

仿真代码如下:

`timescale 1ns/1ps

module uart_tb ();

    reg             tb_clk              ;
    reg             tb_rst_n            ;
    reg     [7:0]   data                ;
    reg             data_vld            ;

    wire            ready               ;
    wire            tx_data             ;
    wire            uart_txd            ;

    wire    [7:0]   rx_dout             ;
    wire            rx_dout_vld         ;

    //  模块例化
    uart_tx uart_tx_pc (        //  模拟上位机发送数据
        /*input               */.clk            (tb_clk         ),
        /*input               */.rst_n          (tb_rst_n       ),
        /*//  control*/
        /*input   [7:0]       */.tx_din         (data           ),
        /*input               */.tx_din_vld     (data_vld       ),
        /*output              */.ready          (ready          ),       //  给control模块的握手信号,表示可以接收数据进行发送 
        /*//  上位机*/
        /*output              */.uart_tx        (tx_data        )
    );

    uart u_uart (
        /*input               */.clk             (tb_clk        ),
        /*input               */.rst_n           (tb_rst_n      ),
 
        /*input               */.uart_rxd        (tx_data       ),
        /*output              */.uart_txd        (uart_txd      )
    );

    //  参数定义
    parameter   CYCLE = 20 ;

    always  #(CYCLE / 2) tb_clk = ~tb_clk ;     //  50M时钟

    initial begin
        tb_clk   = 1'b1;
        tb_rst_n = 1'b1;
        data = 0;
        data_vld = 1'b0;

        # (CYCLE * 2);
        tb_rst_n = 1'b0;
        # (CYCLE * 2);
        # 2;
        tb_rst_n = 1'b1;
        # (CYCLE * 10);

        Send(8'hf9);
        Send(8'h99);
        Send(8'hAE);
        Send(8'hBC);
        Send(8'h55);
        Send(8'hE1);

        # (CYCLE * 100);
        $stop; 
    end

    task Send;
        input   [7:0]   send_data ;
        begin
            data = send_data ;
            data_vld = 1'b1 ;
            # CYCLE ;
            data_vld = 1'b0 ;
            // @(posedge ready)
            # (CYCLE*440*10) ;
        end
    endtask
    
endmodule

【FPGA】FPGA实现UART串口通信回环
【FPGA】FPGA实现UART串口通信回环

五、上板验证

这里通过串口调试助手来与FPGA进行串口通信测试,可以看见通过串口收发数据正确。

【FPGA】FPGA实现UART串口通信回环

六、踩坑事项

在调试串口的时候发现设备管理器中串口无法识别,显示PL2303HXA自2012已停产,请联系供应商,如下图:
【FPGA】FPGA实现UART串口通信回环
这时需要下载一个旧版本的驱动,下载链接如下:
链接:https://pan.baidu.com/s/1FTtfgc2k2fw-9Ck1_tRbRQ
提取码:7kf2

下载完成后解压安装,点击更新驱动程序→浏览电脑选择旧版本双击安装即可:
【FPGA】FPGA实现UART串口通信回环文章来源地址https://www.toymoban.com/news/detail-454299.html

到了这里,关于【FPGA】FPGA实现UART串口通信回环的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 详解UART通信协议以及FPGA实现

      从《浅谈UART,TTL,RS-232,RS-485的区别》这篇文章,我们知道了UART是一种串行、异步、全双工的通信协议,属于协议层;传输过程一般采用RS-232,RS-485电平标准,将所需传输的数据一位接一位地传输;整体传输框架如下:   串口通信由发送端和接收端构成,两根信号线

    2024年04月28日
    浏览(39)
  • FPGA入门 —— FPGA UART 串口通信

    UART 通用异步收发传输器( Universal Asynchronous Receiver/Transmitter) ,通常称作 UART。 UART 是一种通用的数据通信协议,也是异步串行通信口(串口)的总称,它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。 它包括了ch340、 RS232、

    2024年02月09日
    浏览(46)
  • FPGA-结合协议时序实现UART收发器(五):串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive

    串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive,功能实现。 对照代码,串口发送模块UART_TOP实现功能包括: PLL锁相环,实现稳定系统输入时钟功能 UART_FIFO,数据先进先出,实现数据缓存功能,防止出现数据错乱 w_clk_rst = ~w_system_pll_locked;保证复位电平是先高位再地位 r_use

    2024年02月08日
    浏览(88)
  • UART串口通信协议

    串行通信分为两种方式: 同步串行通信 和 异步串行通信 。 同步串行通信需要通信双方在同一时钟的控制下,同步传输数据。 异步串行通信是指通信双方使用各自的时钟控制数据的发送和接收过程。 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART)是一种 全双

    2024年02月03日
    浏览(38)
  • 【FPGA】UART串口通信---基于FIFO

    我们在上一章完成了UART串口通信的收发模块,这一章我们将FIFO引入进来,使用FIFO进行缓存数据,来连接串口通信的收发模块 FIFO即First In First Out,是一种先进先出数据存储、缓冲器,我们知道一般的存储器是用外部的读写地址来进行读写,而FIFO这种存储器的结构并不需要外

    2023年04月14日
    浏览(84)
  • FPGA协议篇:UART通信及Verilog最易懂实现方式/通用于任何工程/带握手信号 ----UART_TX

            UART(Universal Asynchronous Receiver/Transmitter)是一种通用的 异步收发传输协议 ,用于在计算机系统和外部设备之间进行串行数据传输。UART 协议定义了数据的传输格式和通信规则,使得不同设备之间能够进行可靠的数据交换。 首先先把设计代码放到这里: UART_TX完整代

    2024年03月27日
    浏览(52)
  • FPGA 串口通信(uart)初探篇(含源代码)

    一、UART 串口通信,说实话是日常生活中很常见的一种9针型的主机和显示屏之间的通信模式。本次博客,只为自己复盘相关知识,初学者,错误较多,请多指教。所以本文参考(一)FPGA之串口通信(UART)_fpga uart-CSDN博客 而编著的。 FPGA是一种可编程的逻辑器件,用于各种数字电

    2024年04月14日
    浏览(34)
  • 【FPGA协议篇】UART通信及其verilog实现(代码采用传参实现模块通用性,适用于快速开发)

    ​ 即通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种 串行、异步、全双工 的通信协议。特点是通信线路简单,适用于远距离通信,但传输速度慢。 数据传输速率:波特率(单位:baud,波特) 常见波特率有:1200、2400、4800、19200、38400、57600等,最常用的是9600和11520

    2024年02月05日
    浏览(50)
  • 串口通信协议--UART、RS-232、RS-485、RS-422

    近期学习了单片机及数电相关知识,故决定系统地学习一些通信协议。手边书本仅介绍了串口低速接口的相关协议。 串行通信 是指通过使用一条数据线(需要地线或控制线),将数据一位一位地一次传输,每一位数据占据一个固定的时间长度。 特点 :抗干扰,节省数据线,

    2024年02月05日
    浏览(63)
  • FPGA开发基础篇之一(接口篇)UART串口

    写在前面 从本文开始,将连载fpga开发基础知识,将这几年浅显的fpga开发经验整理出来,一是梳理一下这几年给别人做fpga的经历,同时也是分享给大家,也希望大牛批评指正。 一、UART串口通信基本概念 串口通信是非常基本且应用十分广泛的低速通信接口,无论是在dsp、单片

    2024年02月02日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包