基于verilog的uart协议实现
目录
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协议实现相关推荐
- verilog基础---uart协议解析
UART协议详解 UART(Universal Asynchronous Receiver/Transmitter)是一种异步全双工串行通信协议,由Tx和Rx两根数据线组成,因为没有参考时钟信号,所以 ...
- 2.3 基于FPGA的UART协议实现(一)串口信号定义和接线方法-5针串口-9针串口-全功能串口
通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART.它将要传输的资料在串行通信与并行通信之间加以转换.作为把并行输入信号 ...
- 基于FPGA的UART接口协议设计
一.PC终端概述 PC终端,Personal Computer 智能终端,通俗的讲,就是利用电脑GUI界面控制我们的外部硬件电路. 因此设计到了PC与外部硬件电路的通信接口.对于台式电脑.个人笔记本, ...
- 基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结
基于FPGA实现uart串口模块(Verilog)--------接收模块及思路总结 uart通信协议简单理解为串转并和并转串的两个模块.同时必须保证数据的正确性.且输入输出端为串行. 此次实现uar ...
- 基于 FPGA 的以太网回环测试verilog实现UDP协议
基于 FPGA 的以太网回环测试verilog实现UDP协议 verilog实现UDP协议: 该 设计使用 UDP 协议,首先通过串口助手接收 PC 发送的 UDP 数据包,然后提取其中的数据部分并使 ...
- 基于FPGA实现uart串口模块(Verilog)--------发送模块及整合
基于FPGA实现uart串口模块(Verilog)--------发送模块及整合 当接收模块接收到数据后,需要重新发送形成回环验证模块正确性.思路和结束模块有一点点的小差异.接收模块最终输出的是一个并 ...
- 几种常用通信协议:IIC协议、SPI协议、UART协议
通信可以形象的比喻成两个人讲话:1.你说的别人得能听懂:双方约定信号的协议.2.你的语速别人得能接受:双方满足时序要求. 一.IIC协议: 2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一 ...
- 基于FPGA的UART全双工数据控制器
引言: UART串行通讯协议是一种经典通讯协议,尽管在当前,它的通讯传输速度已经不能满足高数据量传输场景,但在传统的工业应用中还十分普遍广泛.在网上,一般所见到的可应用于FPGA设计的UART接口都遗 ...
- 基于 FPGA 的 UART 控制器设计(VHDL)(下)
今天给大侠带来基于FPGA的 UART 控制器设计(VHDL)(下),由于篇幅较长,分三篇.今天带来第三篇,下篇,使用 FPGA 实现 UART.话不多说,上货. 之前有关于 Veriliog HDL ...
- 基于FPGA的UART接口设计
一.顶层设计思路: UART即通用异步收发传输接口(Universal Asynchronous Receiver/Transmitter),简称串口,是一种常用的通信接口,其协议原理就不赘述了,不了 ...
最新文章
- SCOM 2012知识分享-21:无代理管理
- torch.flatten()函数
- 站长工具|百度搜索框提示功能
- Java黑皮书课后题第5章:*5.44(计算机体系结构:比特级的操作)一个short型值用16位比特存储。编写程序,提示用户输入一个short型的整数,然后显示这个整数的16比特形式,下面是运行示例
- angular jwt_Angular5 JWT身份验证(Spring Boot安全性)
- 从SQL Server生成文档
- C语言getchar函数
- python实用库_python常用库
- CDH ecosystem components
- python列表与集合
- 常用技术指标与四大交易理论
- XNA中的中文输入(一)
- 如何部署Java_web项目到云服务器上
- 手机端和wap端页面的自适应技术方案
- 图形化UDP发包小工具
- JAVA声明圆锥体类,实现Area和Volume接口,计算表面积和体积,按体积比较大小
- 樊登读书会掌控读后感_《掌控谈话》读后感1500字
- 十年互联网 十个风云人物
- 柬埔寨招聘中文计算机,柬埔寨ll中文老师1000美金+招聘机会来啦,快来围观!!!...
- InnoDB Persistent Statistics问题