【FPGA】FPGA实现UART串口通信回环
创始人
2024-04-04 06:59:48
0

目录

  • 一、UART协议基础
  • 二、系统模块划分
  • 三、代码实现
    • 1、uart顶层设计模块
    • 2、uart_rx串口数据接收模块
    • 3、control控制模块
    • 4、uart_tx串口数据发送模块
  • 四、仿真
  • 五、上板验证
  • 六、踩坑事项

一、UART协议基础

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

二、系统模块划分

在这里插入图片描述
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_baudalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_baud <= 0 ;endelse if(add_cnt_baud)beginif(end_cnt_baud)begincnt_baud <= 0 ;end				else begin	    cnt_baud <= cnt_baud + 1 ;end 		    endendassign	add_cnt_baud =	rx_flag ;assign	end_cnt_baud =  add_cnt_baud && (cnt_baud == `BAUD - 1) ;//  cnt_bitalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bit <= 0 ;endelse if(add_cnt_bit)beginif(end_cnt_bit)begincnt_bit <= 0 ;end				else begin	    cnt_bit <= cnt_bit + 1 ;end 		    endendassign	add_cnt_bit = end_cnt_baud ;assign	end_cnt_bit = add_cnt_bit && (cnt_bit == 9 || dout_data[0] == 1'b1) ;       //  uart_rx_ralways @(posedge clk or negedge rst_n)beginif(!rst_n)beginuart_rx_r <= 0 ;endelse beginuart_rx_r <= {uart_rx_r[0],uart_rx} ;endend//  uart_rx下降沿检测assign  rx_nedge = ~uart_rx_r[0] & uart_rx_r[1] ;//  rx_flagalways @(posedge clk or negedge rst_n)beginif(!rst_n)beginrx_flag <= 1'b0 ;endelse if(rx_nedge)beginrx_flag <= 1'b1 ;endelse if(end_cnt_bit)beginrx_flag <= 1'b0 ;endend//  dout_dataalways @(posedge clk or negedge rst_n)beginif(!rst_n)begindout_data <= 0 ;endelse if(rx_flag & cnt_baud == 0)begindout_data[cnt_bit] <= uart_rx_r[0] ;endend//  输出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_rxinput   [7:0]       rx_din          ,input               rx_din_vld      ,//  uart_txinput               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_flagalways @(posedge clk or negedge rst_n)beginif(!rst_n)beginrd_flag <= 1'b0 ;endelse if(rdusedw > 4)beginrd_flag <= 1'b1 ;endelse if(rdempty)beginrd_flag <= 1'b0 ;endend//  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           ,//  controlinput   [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_baudalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_baud <= 0 ;endelse if(add_cnt_baud)beginif(end_cnt_baud)begincnt_baud <= 0 ;end				else begin	    cnt_baud <= cnt_baud + 1 ;end 		    endendassign	add_cnt_baud =	tx_flag ;assign	end_cnt_baud = add_cnt_baud && (cnt_baud == `BAUD - 1) ;//  cnt_bitalways @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bit <= 0 ;endelse if(add_cnt_bit)beginif(end_cnt_bit)begincnt_bit <= 0 ;end				else begin	    cnt_bit <= cnt_bit + 1 ;end 		    endendassign	add_cnt_bit = end_cnt_baud ;assign	end_cnt_bit = add_cnt_bit && (cnt_bit == 9) ;   //  tx_flagalways @(posedge clk or negedge rst_n)beginif(!rst_n)begintx_flag <= 1'b0 ;endelse if(tx_din_vld)begintx_flag <= 1'b1 ;endelse if(end_cnt_bit)begintx_flag <= 1'b0 ;endend//  vldalways @(posedge clk or negedge rst_n)beginif(!rst_n)beginvld <= 1'b0 ;endelse beginvld <= tx_din_vld ;endend//  tx_dataalways @(posedge clk or negedge rst_n)beginif(!rst_n)begintx_data <= 0 ;endelse if(vld)begintx_data <= {1'b1,tx_din,1'b0} ;     //      停止位 + 数据 + 起始位  低位在前发送endend//  doutalways @(posedge clk or negedge rst_n)beginif(!rst_n)begindout <= 1'b1 ;endelse if(tx_flag)begindout <= tx_data[cnt_bit] ;endend//  输出assign  uart_tx = dout ;assign  ready = ~tx_flag ;endmodule

四、仿真

仿真代码如下:

`timescale 1ns/1psmodule 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 begintb_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; endtask Send;input   [7:0]   send_data ;begindata = send_data ;data_vld = 1'b1 ;# CYCLE ;data_vld = 1'b0 ;// @(posedge ready)# (CYCLE*440*10) ;endendtaskendmodule

在这里插入图片描述
在这里插入图片描述

五、上板验证

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

在这里插入图片描述

六、踩坑事项

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

下载完成后解压安装,点击更新驱动程序→浏览电脑选择旧版本双击安装即可:
在这里插入图片描述

相关内容

热门资讯

吉利起诉欣旺达,理想汽车躺枪? 想象一下,我从你这里采购电池,还替你宣传,结果因为你的质量问题让大家质疑我,这是一种什么感受? 1...
獐子岛:近12个月新增累计诉讼... 12月29日,獐子岛(002069)发布公告,截止到公告披露日,公司及控股子公司在最近十二个月内累计...
政策迎重大调整!概念股集体飙涨... 12月29日,A股市场主要股指震荡走势,沪指收盘微涨0.04%,录得九连阳。从板块上来看,数字人民币...
福石控股累计诉讼仲裁1792万... 12月29日,福石控股(300071)发布公告,截至公告披露日前,公司及子公司在过去十二个月内的累计...
犯罪收益达14.6亿韩元,享有... 金建希利用总统夫人身份,收受大量财物,并广泛介入了各种人士安排,“甚至可以称得上是现代卖官卖职”,韩...
金评天下丨“长钱长投”制度环境... 金融投资报评论员 刘柯 中国人民银行于12月26日发布《中国金融稳定报告(2025)》(以下简称《金...
偷拿自己快递再退款不是“薅羊毛... 网购下单付款,待快递到站后秘密取走,再以“未收到货”申请退款,这样的行为看似钻了“空子”,实则已触犯...
全球瞭望丨美媒集体抨击特朗普政... 新华社洛杉矶12月28日电(记者黄恒)美国加利福尼亚州多家地方媒体28日集体刊登同一篇社论,抨击特朗...
一个假律师凭啥“拿捏”酒企? ... 打着“维权”的幌子,干着敲诈的勾当,事后还要签订“法律服务”合同……江苏宿迁一名假律师专门敲诈酒企,...