目录

1、理论介绍

2、架构设计

3、代码设计

一、发送模块代码

二、接收代码设计

三、顶层模块设计

四、测试代码

4、仿真实验


1、理论介绍

uart:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是一种串行的收发方式,由于没有时钟,因此需要双方约定好传输的速率,以及起始和停止,为了保证数据的可靠传输,还需要使用校验位。uart协议如图

图1 uart协议

在协议未开始传输时,物理层通路上电平为高,起始位将电平拉低,意为着传输开始,这边使用大端传输方式 ,即先传输高字节数据,8位数据位传输完成后,使用奇偶校验位进行校验(是一种验错方式,但是不能纠错),最后传输1位/1.5位/2位停止位。

以前总是想着通信协议应该是有一个统一结构标准的,这里我先斗胆这样定义,如果有问题随时改正,这里先定义物理层和链路层:

物理层:主要任务为确定与传输媒体的接口有关的一些特性

机械特性:指明接口所用接线器的形状和尺寸、引脚数目和排列、固定和锁定装置等。

电气特性:指明在接口电缆的各条线上出现的电压范围、阻抗匹配、传输速率等。

功能特性:指明物理接口上各条信号线的功能分配和确切定义。

过程特性:指明对于不同功能的各种可能事件的出现顺序(理解为建立物理连接、维持和交换信息)。

数据链路层:将来源于物理层的数据进行可靠的传输。如何可靠的传输,就是协议里面具体规定的内容,以帧为单位进行传输。

这里理解的uart协议,是一个没有定义物理层,只定义了协议层的协议,因此我们可以使单端线,RS232,RS485或者其他接口传输,不同的接口也就造成了传输距离和速率的区别,可以根据自己的需要自由的选择接口。

2、架构设计

在编写代码之前是需要先构建模块框图的,先分析一下uart需要哪些模块,这是一个异步全双工的协议,因此需要一个发送模块和一个接收模块,分别在各自模块内部实现波特率的生成,以及数据收发,模块以及其信号如下:

图2 发送模块

图3 接收模块

在完成顶层模块框图划分后,需要对各个模块分析,发送模块内部主要电路原理图如图4所示,接收模块内部主要电路框图如图5所示。根据设计的电路框图开始编写程序。

图4 发送模块内部主要电路图

图5 接收模块内部主要电路图

3、代码设计

一、发送模块代码

/***************************************
#
#           Filename:tx.v
#
#           Developer:annotater
#           Description:---
#           CreatTime:2021-08-09 23:00:12
#
***************************************/
module tx(
input clk_200m,
input sys_rst,
input[7:0] tx_data,
input oe,
output tx,
output reg tx_done
);localparam BAUD = 115200;
localparam DIV_NUM = 200000000/BAUD;
localparam IDLE = 3'b001;
localparam PRE  = 3'b010;
localparam SEND = 3'b100;reg[2:0] cstate,nstate;//定义当前状态和次态
reg[11:0] cout;//波特率分频计数
reg[3:0] shift_num;//移位次数
reg[10:0] tx_data_pre;//需要发送的一帧数据
wire baud_pdg;//波特率上升沿
wire baud_ndg;//波特率下降沿//buad generater
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)begincout <= 12'b0;endelse if(cout == DIV_NUM-1'b1)begincout <= 12'b0;endelse if(cstate == SEND)begincout <= cout + 1'b1;end
end
assign baud_pdg = (cout == DIV_NUM >> 1'b1 )?1'b1:1'b0;
assign baud_ndg = (cout == DIV_NUM -  1'b1 )?1'b1:1'b0;//shift
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)begintx_data_pre[10:0] <= 11'b1111_1111_11;shift_num <= 4'd0;endelse if(cstate == PRE)begintx_data_pre[10:0] <= {1'b0,tx_data,(^tx_data),1'b1};endelse if(shift_num == 4'd10 && baud_ndg)begintx_data_pre[10:0] <= 11'b1111_1111_11;shift_num <= 4'd0;endelse if(baud_ndg)begintx_data_pre[10:0] <= {tx_data_pre[9:0],1'b1};shift_num <= shift_num + 1'b1;endend //state machine
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)begincstate <= IDLE;endelse begincstate <= nstate;end
end
always@(*)begincase(cstate)//synthesis full_caseIDLE:nstate = (oe)?PRE:IDLE;PRE :nstate = SEND;SEND:nstate = (shift_num == 4'd10 && baud_ndg)?IDLE:SEND;endcase
end
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)begintx_done <= 1'b0;endelse begincase(cstate)IDLE:tx_done <= 1'b0;PRE :;SEND:beginif(shift_num == 4'd10 && baud_ndg)tx_done <= 1'b1;else tx_done <= 1'b0;endendcaseend
end
assign tx = (cstate == SEND)?tx_data_pre[10]:1'b1;
endmodule

二、接收代码设计

/***************************************
#
#           Filename:rx.v
#
#           Developer:annotater
#           Description:---
#           CreatTime:2021-08-10 17:44:59
#
***************************************/
module rx(
input clk_200m,
input sys_rst,
input rx,output reg[7:0] rx_data,
output reg rx_done
);localparam BAUD = 115200;
localparam DIV_NUM = 200000000/BAUD;
localparam IDLE = 2'b01;
localparam RECE = 2'b10;reg[1:0] cstate,nstate;//定义当前状态和次态
reg[11:0] cout;//波特率分频计数
reg[3:0] shift_num;//移位次数
reg[10:0] rx_data_rec;//接收一帧数据
reg[1:0] rx_d;//同步器,用来消除亚稳态和检测下降沿
wire baud_pdg;//波特率上升沿
wire baud_ndg;//波特率下降沿
wire rx_ndg;//起始位下降沿
wire rx_error;//起始位接收错误
//buad generater
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)begincout <= 12'b0;endelse if(cout == DIV_NUM - 1'b1 )begincout <= 12'b0;endelse if(cstate == RECE)begincout <= cout + 1'b1;end
end
assign baud_pdg = (cout == DIV_NUM >> 1'b1 )?1'b1:1'b0;
assign baud_ndg = (cout == DIV_NUM -  1'b1 )?1'b1:1'b0;//同步器
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)beginrx_d <= 2'b11;endelse beginrx_d <= {rx_d[0],rx};end
end
assign rx_ndg = rx_d[1] & ~(rx_d[0]);assign rx_error = (baud_pdg&&(cstate == RECE)&&rx&&(shift_num == 4'b0000));//判断起始位是否检测错误//shift
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)beginrx_data_rec[10:0] <= 11'b0;endelse if(baud_pdg)beginrx_data_rec[10:0] <= {rx_data_rec[9:0],rx};end
end
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)shift_num <= 0;else if(shift_num == 10 && baud_ndg)shift_num <= 0;else if(baud_ndg)shift_num <= shift_num + 1;
end
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)rx_data <= 8'd0;else if(rx_done && ~(^rx_data_rec[9:1]))rx_data <= rx_data_rec[9:2];
end//state machinealways@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)begincstate <= IDLE;endelse begincstate <= nstate;end
end
always@(*)begincase(cstate)//synthesis full_caseIDLE:nstate = (rx_ndg)?RECE:IDLE;RECE:nstate = (shift_num == 4'd10 && baud_ndg || rx_error)?IDLE:RECE;endcase
end
always@(posedge clk_200m or posedge sys_rst)beginif(sys_rst)beginrx_done <= 1'b0;endelse begincase(cstate)IDLE:rx_done <= 1'b0;RECE:beginif(shift_num == 4'd10 && baud_ndg)rx_done <= 1'b1;else rx_done <= 1'b0;endendcaseend
end
endmodule

三、顶层模块设计

顶层模块中需注意避免胶连逻辑(glue logic)。

/***************************************
#
#           Filename:uart_top.v
#
#           Developer:annotater
#           Description:---
#           CreatTime:2021-08-10 18:15:58
#
***************************************/
module uart_top(
input clk_200m,
input sys_rst,input rx,
input [7:0] tx_data,
input oe,output [7:0] rx_data,
output tx,
output rx_done,
output tx_done
);rx U_RX(.clk_200m  ( clk_200m  ), //i.sys_rst   ( sys_rst   ), //i.rx        ( rx        ), //i.rx_data   ( rx_data   ), //o.rx_done   ( rx_done   )  //o
);tx U_TX(.clk_200m  ( clk_200m  ), //i.sys_rst   ( sys_rst   ), //i.tx_data   ( tx_data   ), //i.oe        ( oe        ), //i.tx        ( tx        ), //o.tx_done   ( tx_done   )  //o
);endmodule

四、测试代码

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/08/10 18:21:32
// Design Name:
// Module Name: tb_uart_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module tb_uart_top();
reg      clk_200m    ;
reg      sys_rst     ;
reg      rx          ;
reg[7:0] tx_data     ;
reg      oe          ;
wire[7:0] rx_data     ;
wire      tx          ;
wire      rx_done     ;
wire      tx_done     ;
initial begin
clk_200m = 0;
sys_rst = 1;
rx = 0;
tx_data= 0;
oe = 0;
#100 sys_rst = 0;
forever #2.5 clk_200m = ~clk_200m;
end
initial begin
#200 tx_data = 8'b1010_1010;
#10 oe = 1;
#10 oe = 0;#200000 tx_data = 8'b0101_0101;
#10 oe = 1;
#10 oe = 0;
end
uart_top U_UART_TOP(.clk_200m  ( clk_200m  ), //i.sys_rst   ( sys_rst   ), //i.rx        ( 0         ), //i.tx_data   ( tx_data   ), //i.oe        ( oe        ), //i.rx_data   (           ), //o.tx        ( tx        ), //o.rx_done   (           ), //o.tx_done   ( tx_done   )  //o
);uart_top U_UART_TOP2(.clk_200m  ( clk_200m  ), //i.sys_rst   ( sys_rst   ), //i.rx        ( tx        ), //i.tx_data   ( 0         ), //i.oe        ( 0         ), //i.rx_data   ( rx_data   ), //o.tx        (           ), //o.rx_done   ( rx_done   ), //o.tx_done   (           )  //o
);endmodule

4、仿真实验

设计代码首先要进行功能仿真验证其功能,功能验证后进行综合,综合是一个将RTL代码转换为门级网表的过程,不同的元件库会综合出不同的门级网表,因此有时候会出现一种库综合通过,另一种库综合不通过的现象,这里直接观察综合后仿真。

仿真文件里面写的仿真过程为在两个时刻分别由一个串口发送AA和55数据,并由另一个串口接收,可以看到,仿真结果没有问题,其中一个bit占用时间8.7us左右。

图6 综合后仿真

基于verilog的uart协议实现相关推荐

  1. verilog基础---uart协议解析

    UART协议详解 UART(Universal Asynchronous Receiver/Transmitter)是一种异步全双工串行通信协议,由Tx和Rx两根数据线组成,因为没有参考时钟信号,所以 ...

  2. 2.3 基于FPGA的UART协议实现(一)串口信号定义和接线方法-5针串口-9针串口-全功能串口

      通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART.它将要传输的资料在串行通信与并行通信之间加以转换.作为把并行输入信号 ...

  3. 基于FPGA的UART接口协议设计

    一.PC终端概述 PC终端,Personal Computer 智能终端,通俗的讲,就是利用电脑GUI界面控制我们的外部硬件电路. 因此设计到了PC与外部硬件电路的通信接口.对于台式电脑.个人笔记本, ...

  4. 基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结

    基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结 uart通信协议简单理解为串转并和并转串的两个模块.同时必须保证数据的正确性.且输入输出端为串行. 此次实现uar ...

  5. 基于 FPGA 的以太网回环测试verilog实现UDP协议

    基于 FPGA 的以太网回环测试verilog实现UDP协议 verilog实现UDP协议: 该 设计使用 UDP 协议,首先通过串口助手接收 PC 发送的 UDP 数据包,然后提取其中的数据部分并使 ...

  6. 基于FPGA实现uart串口模块(Verilog)--------发送模块及整合

    基于FPGA实现uart串口模块(Verilog)--------发送模块及整合 当接收模块接收到数据后,需要重新发送形成回环验证模块正确性.思路和结束模块有一点点的小差异.接收模块最终输出的是一个并 ...

  7. 几种常用通信协议:IIC协议、SPI协议、UART协议

    通信可以形象的比喻成两个人讲话:1.你说的别人得能听懂:双方约定信号的协议.2.你的语速别人得能接受:双方满足时序要求. 一.IIC协议: 2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一 ...

  8. 基于FPGA的UART全双工数据控制器

    引言: UART串行通讯协议是一种经典通讯协议,尽管在当前,它的通讯传输速度已经不能满足高数据量传输场景,但在传统的工业应用中还十分普遍广泛.在网上,一般所见到的可应用于FPGA设计的UART接口都遗 ...

  9. 基于 FPGA 的 UART 控制器设计(VHDL)(下)

    今天给大侠带来基于FPGA的 UART 控制器设计(VHDL)(下),由于篇幅较长,分三篇.今天带来第三篇,下篇,使用 FPGA 实现 UART.话不多说,上货. 之前有关于 Veriliog HDL ...

  10. 基于FPGA的UART接口设计

    一.顶层设计思路: UART即通用异步收发传输接口(Universal Asynchronous Receiver/Transmitter),简称串口,是一种常用的通信接口,其协议原理就不赘述了,不了 ...

最新文章

  1. SCOM 2012知识分享-21:无代理管理
  2. torch.flatten()函数
  3. 站长工具|百度搜索框提示功能
  4. Java黑皮书课后题第5章:*5.44(计算机体系结构:比特级的操作)一个short型值用16位比特存储。编写程序,提示用户输入一个short型的整数,然后显示这个整数的16比特形式,下面是运行示例
  5. angular jwt_Angular5 JWT身份验证(Spring Boot安全性)
  6. 从SQL Server生成文档
  7. C语言getchar函数
  8. python实用库_python常用库
  9. CDH ecosystem components
  10. python列表与集合
  11. 常用技术指标与四大交易理论
  12. XNA中的中文输入(一)
  13. 如何部署Java_web项目到云服务器上
  14. 手机端和wap端页面的自适应技术方案
  15. 图形化UDP发包小工具
  16. JAVA声明圆锥体类,实现Area和Volume接口,计算表面积和体积,按体积比较大小
  17. 樊登读书会掌控读后感_《掌控谈话》读后感1500字
  18. 十年互联网 十个风云人物
  19. 柬埔寨招聘中文计算机,柬埔寨ll中文老师1000美金+招聘机会来啦,快来围观!!!...
  20. InnoDB Persistent Statistics问题

热门文章

  1. 快速排序(快排)——C语言实现
  2. 深圳市城中村有哪些,在哪里?请知道的朋友告知,谢谢了!
  3. 滚动截屏苹果_苹果超好用的长截图软件—滚动截屏免费分享!
  4. Theano框架学习
  5. java ip地址定位,Java根据IP地址定位位置
  6. OpenLayers叠加天地图矢量、影像、注记
  7. java smali_Android逆向——smali复杂类解析
  8. Web渗透测试工程师:入门知识
  9. pano2vr怎么制作漫游_Pano2VR如何制作全景图?全景图如何添加热点?
  10. 如何在电脑上下载抖音视频