串口通信发送的verilog及调试

  • 前言
  • 1、UART(通用异步收发传输器)
    • 1.1UART基本介绍
    • 1.2UART关键参数
    • 1.3UART时序图
  • 2、基于FPGA的串口(UART)发送实验
  • 3、代码实现步骤分析
    • 3.1 端口声明
    • 3.2 波特率时钟生成
    • 3.3 数据输出模块设计
  • 4、代码实现总结
    • 4.1 设计文件
    • 4.2 仿真文件
    • 4.3 仿真结果
  • 5、注意事项总结

前言

如果不看分析步骤,需要了解代码,可以直接跳到第四节。

1、UART(通用异步收发传输器)

1.1UART基本介绍

RS232 通信接口标准,通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART)是一种异步收发传输器,其在数据发送时将并行数据转换成串行数据来传输,在数据接收时将接收到的串行数据转换成并行数据,可以实现全双工传输和接收。

UART 是异步串行通信的总称(UART 是一种协议)。而 RS232、RS449、RS423、RS422 和 RS485 等,是对应各种异步串行通信口的接口标准和总线标准,它们规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。若系统存在多个 UART接口,则可分别称为 COM1、COM2 等。

RS-232 是美国电子工业联盟(EIA)制定的串行数据通信的接口标准,原始编号全称是 EIA-RS-232(简称 232,RS232),被广泛用于计算机串行接口外设连接。
DB9 接口的针脚定义如图:



通常使用RXD、TXD、GND这三个信号

1.2UART关键参数

UART 通信在使用前需要做多项设置,最常见的设置包括数据位数、波特率大小、奇偶校验类型和停止位数。

数据位(Data bits):该参数定义单个 UART 数据传输在开始到停止期间发送的数据位数。可选择为:5、6、7 或者 8(默认)

波特率(Baud):是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数。典型的波特率有 300, 1200, 2400, 9600, 19200, 115200 等。一般通信两端设备都要设为相同的波特率,但有些设备也可设置为自动检测波特率。通俗的说,就是一个数据的高电平/低电平持续的时间,是一个最基本的时间单位。
  串口全部都是使用的二进制,所以波特率就是比特率。

奇偶校验类型(Parity Type):是用来验证数据的正确性。奇偶校验一般不使用,如果使用,则既可以做奇校验(Odd)也可以做偶校验(Even)。在偶校验中,因为奇偶校验位会被相应的置 1 或 0(一般是最高位或最低位),所以数据会被改变以使得所有传送的数位(含字符的各数位和校验位)中“1”的个数为偶数;在奇校验中,所有传送的数位(含字符的各数位和校验位)中“1”的个数为奇数。奇偶校验可以用于接受方检查传输是否发送生错误,如果某一字节中“1”的个数发生了错误,那么这个字节在传输中一定有错误发生。如果奇偶校验是正确的,那么要么没有发生错误,要么发生了偶数个的错误。如果用户选择数据长度为 8 位,则因为没有多余的比特可被用来作为奇偶校验位,因此就叫做“无奇偶校验(Non)”。

停止位(Stop bits):在每个字节的数据位发送完成之后,发送停止位,来标志着一次数据传输完成,同时用来帮助接受信号方硬件重同步。可选择为:1(默认)、1.5 或者 2 位。

1.3UART时序图

在 RS-232 标准中,最常用的配置是 8N1(即八个数据位、无奇偶校验、一个停止位),其发送一个字节时序图如图:

按照一个完整的字节包括一位起始位、8 位数据位、一位停止位即总共十位数据来算, 要想完整的实现这十位数据的发送,就需要 11 个波特率时钟脉冲,第 1 个脉冲标记一次传输的起始,第 11 个脉冲标记一次传输的结束。

bps_clk的电平宽度是一个系统时钟周期,如:50MHz,是20ns;bps_clk高电平时,uart_tx的值更新一位。

如果波特率是9600,传输一位的时间为104.1666……ns
1s=1109ns;109ns / 9600 =104,166.666……ns=104.1666……us
如果波特率是115200,传输一位的时间为8,680.555……ns
1s=1
109ns;109ns / 115200 =8,680.555n……ns=8.680……us

2、基于FPGA的串口(UART)发送实验

1、串口通信模块设计的目的是用来发送数据的,因此需要有一个数据输入端口θ
2、串口通信,支持不同的波特率,所以需要有一个波特率设置端口。
3、串口通信的本质就是将8位的并行数据通过一根信号线.在不同的时刻传输并行数据的不同位,通过多个时刻,最终将8位并行数据全部传出。
4、串口通信以1位的低电平标志串行传输的开始,待8位数据传输完成之后,再以1位的高电平标志传输的结束。
5、控制信号,控制并转串模块什么开始工作。什么时候一个数据发送完成?须有一个发送开始信号,以及一个发送完成信号。


并转串图示

串口发送模块(手绘版)

串口发送模块整体框图

3、代码实现步骤分析

3.1 端口声明

module uart_byte_tx(clk,reset_n, data,send_en,baud_set,uart_tx,tx_done   );input clk;//模块全局时钟 50MHz    input reset_n;//模块全局复位信号input [7:0]data;//待传输 8bit 数input send_en;//发送使能信号input [2:0]baud_set;//baud set 波特率设置,支持 5 种,baud set为 3 位output uart_tx;//串口发送信号输出output tx_done;//发送结束信号,一个时钟周期高电平endmodule

3.2 波特率时钟生成

在波特率时钟生成模块中,计数器需要的计数值与波特率之间的关系如下表所示,其中系统时钟周期为System_clk_period,这里为 20ns(因为是50MHz)。如果接入到该模块的时钟频率为其他值,需要根据具体的频率值修改该参数。典型的波特率有 300, 1200, 2400, 9600(波特率一般都大于9600), 19200, 115200 等。

波特率为300,对应时间3333333ns最小时间单元:3333333ns/20ns(即时钟频率50HZ)=16666次(2进制18位)
波特率为9600,对应时间104167ns最小时间单元:104167ns/20ns(即时钟频率50HZ)=5208次(2进制13位)
波特率为115200,对应时间8680ns最小时间单元:8680ns/20ns(即时钟频率50HZ)=434次=2’b110110010(9位)

计数器由波特率(波特率一般都大于9600)决定

//生成一个时钟计数器reg [17:0]div_cnt;always@(posedge clk or negedge reset_n)if(!reset_n)div_cnt<=0;else if(div_cnt==bps_DR-1)//bps_DR由波特率决定div_cnt<=0;elsediv_cnt<=div_cnt + 1'b1;

增加一个send_en来控制,将上面代码修改为下面代码

//生成一个时钟计数器reg [17:0]div_cnt;always@(posedge clk or negedge reset_n)beginif(!reset_n)div_cnt<=0;else if(send_en)beginif(div_cnt==bps_DR-1)//bps_DR由波特率决定div_cnt<=0;elsediv_cnt<=div_cnt + 1'b1;endelsediv_cnt<=0;end

波特率的设置

//波特率的设置
//baud_set = 0 就让波特率 = 9600 ;
//baud_set = 1 就让波特率 = 19200 ;
//baud_set = 2 就让波特率 = 38400 ;
//baud_set = 3 就让波特率 = 57600 ;
//baud_set = 4 就让波特率 = 115200 ;   reg [17:0]bps_DR;//波特率寄存器,因为要和div_cnt做比较,所以也是[17:0]always@(*)beginif(!reset_n)bps_DR <= 1000000000/9600/20;else begincase(baud_set)//使用组合逻辑来写,常量可以计算出来,FPGA保留整数,不存在除不尽的状态0:bps_DR <= 1000000000/9600/20;//0:bps_DR <= 16'd5208;1:bps_DR <= 1000000000/19200/20;2:bps_DR <= 1000000000/38400/20;3:bps_DR <= 1000000000/57600/20;4:bps_DR <= 1000000000/115200/20;default:bps_DR <= 1000000000/9600/20;               endcaseendend

3.3 数据输出模块设计

通过对波特率时钟进行计数,来确定数据发送的循环状态10个信号需要11个点来确定,参照1.3时序图所示

//数据发生的循环状态,共10个信号
//计数器计数11位,二进制用4位来表示reg [3:0]bps_cnt;always@(posedge clk or negedge reset_n)beginif(!reset_n)bps_cnt<=0;else if(bps_cnt==bps_DR-1)begin//bps_cnt== 4'd11if(bps_cnt==11)bps_cnt<=0;elsebps_cnt<=bps_cnt + 1'b1;   end end

修改由bps_clk来控制的代码

//分析后,bps_cnt也受send_en控制
//数据发生的循环状态,共10个信号
//计数器计数11位,二进制用4位来表示wire bps_clk;assign bps_clk=(div_cnt==1);reg [3:0]bps_cnt;always@(posedge clk or negedge reset_n)beginif(!reset_n)bps_cnt<=0;else if(send_en)beginif(bps_clk)beginif(bps_cnt==10)bps_cnt<=0;elsebps_cnt<=bps_cnt + 1'b1;   endend elsebps_cnt<=0;end

数据传输状态控制模块设计
还有一个十选一多路器 ,作用是根据 bps_cnt 的值来确定数据传输的状态。如1.3时序图所示,在不同的波特率时钟计数值时,有对应的传输数据。

    always@(posedge clk or negedge reset_n)beginif(!reset_n)beginuart_tx<=1'b0;tx_done<=1'b0;endelse begincase(bps_cnt) 0:begin uart_tx<=1'b0;tx_done<=1'b0;end1:uart_tx<=data[0];2:uart_tx<=data[1];3:uart_tx<=data[2];4:uart_tx<=data[3];5:uart_tx<=data[4];6:uart_tx<=data[5];7:uart_tx<=data[6];8:uart_tx<=data[7];9:uart_tx<=1'b1;//此处确保stop是持续一个脉冲10:begin uart_tx<=1'b1;tx_done<=1'b1;enddefault:uart_tx<=1'b1;endcase

添加使能端控制

//让send_en控制div_cntreg [17:0]div_cnt;always@(posedge clk or negedge reset_n)beginif(!reset_n)div_cnt<=0;else if(send_en)beginif(div_cnt==bps_DR-1)//bps_DR由波特率决定div_cnt<=0;elsediv_cnt<=div_cnt + 1'b1;endelsediv_cnt<=0;end

目前,基本功能可以实现了

4、代码实现总结

4.1 设计文件

整合第3步的所有代码,形成下面设计文件。

`timescale 1ns / 1ps
module uart_byte_tx(clk,reset_n, data,send_en,baud_set,uart_tx,tx_done   );input clk;//模块全局时钟 50MHz    input reset_n;//模块全局复位信号input [7:0]data;//待传输 8bit 数input send_en;//发送使能信号input [2:0]baud_set;//baud set 波特率设置,支持5种,baud set 为3位output reg uart_tx;//串口发送信号输出output reg tx_done;//发送结束信号,一个时钟周期高电平//波特率的设置
//baud_set = 0 就让波特率 = 9600 ;
//baud_set = 1 就让波特率 = 19200 ;
//baud_set = 2 就让波特率 = 38400 ;
//baud_set = 3 就让波特率 = 57600 ;
//baud_set = 4 就让波特率 = 115200 ;   reg [17:0]bps_DR;//波特率寄存器,因为要和div_cnt做比较,所以也是[17:0]always@(*)beginif(!reset_n)bps_DR <= 1000000000/9600/20;else begincase(baud_set)//使用组合逻辑来写,常量可以计算出来,FPGA保留整数,不存在除不尽的状态0:bps_DR <= 1000000000/9600/20;//0:bps_DR <= 16'd5208;1:bps_DR <= 1000000000/19200/20;2:bps_DR <= 1000000000/38400/20;3:bps_DR <= 1000000000/57600/20;4:bps_DR <= 1000000000/115200/20;default:bps_DR <= 1000000000/9600/20;               endcaseendend//让send_en控制div_cnt                                                    reg [17:0]div_cnt;always@(posedge clk or negedge reset_n)beginif(!reset_n)div_cnt<=0;else if(send_en)beginif(div_cnt==bps_DR-1)//bps_DR由波特率决定div_cnt<=0;elsediv_cnt<=div_cnt + 1'b1;endelsediv_cnt<=0;end    wire bps_clk;assign bps_clk=(div_cnt==1);
//分析后,bps_cnt也受send_en控制
//数据发生的循环状态,共10个信号
//计数器计数11位,二进制用4位来表示reg [3:0]bps_cnt;always@(posedge clk or negedge reset_n)beginif(!reset_n)bps_cnt<=0;else if(send_en)begin//          if(bps_cnt==1)beginif(bps_clk)beginif(bps_cnt==10)bps_cnt<=0;elsebps_cnt<=bps_cnt + 1'b1;   endend elsebps_cnt<=0;end    always@(posedge clk or negedge reset_n)beginif(!reset_n)beginuart_tx<=1'b0;tx_done<=1'b0;endelse begincase(bps_cnt) 0:begin uart_tx<=1'b0;tx_done<=1'b0;end1:uart_tx<=data[0];2:uart_tx<=data[1];3:uart_tx<=data[2];4:uart_tx<=data[3];5:uart_tx<=data[4];6:uart_tx<=data[5];7:uart_tx<=data[6];8:uart_tx<=data[7];9:uart_tx<=1'b1;//此处确保stop是持续一个脉冲10:begin uart_tx<=1'b1;tx_done<=1'b1;enddefault:uart_tx<=1'b1;endcaseendend   endmodule

4.2 仿真文件

写仿真文件快捷方法:
1.复制端口声明,例化连接,ctrl可以实现列编辑,在端口名前加点。
2.复制输入端口,直接将input替换成reg。在vivado中,单击鼠标右键,选择replace in files,可以选择设计文件/仿真文件的替换 。

`timescale 1ns / 1ps
module uart_byte_tx_tb(    );reg clk;  reg reset_n;reg [7:0]data;reg send_en;reg [2:0]baud_set;wire uart_tx;wire tx_done;uart_byte_tx uart_byte_tx_inst(.clk(clk),.reset_n(reset_n), .data(data),.send_en(send_en),.baud_set(baud_set),.uart_tx(uart_tx),.tx_done(tx_done)  );initial clk=1;always #10 clk=~clk;//20ns一个周期//对输入进行赋值initial begin     reset_n=0;   data=0; send_en=0;   baud_set=4;//115200速度快,仿真时间短#201reset_n=1;#100data=8'h57; send_en=1;   #20@(posedge tx_done)//死循环,一直等待TX_done的到来,再执行下一语句send_en=0; #20000 data=8'h75; send_en=1;   #20@(posedge tx_done)#20000 send_en=0;   $stop; end    endmodule

testbench的新语法 @(posedge TX_done),死循环,一直等待TX_done的到来,再执行下一语句

4.3 仿真结果

每一个时间单位是115200,数据完成了串转并。

5、注意事项总结

  1. if…else 嵌套,一定要用begin…end来区分。
  2. 仿真中,testbench的新语法 @(posedge TX_done),死循环,一直等待TX_done的到来,再执行下一语句

小梅哥Xilinx FPGA学习笔记10——串口通信发送相关推荐

  1. 小梅哥Xilinx FPGA学习笔记2——三八译码器

    三八译码器 〇.功能介绍 1.功能描述 2.真值表 一.代码编写 1.设计文件 2.激励文件 3.仿真图 二.总结 三.课后作业 1.设计文件 2.激励文件 3.仿真图 〇.功能介绍 1.功能描述 译 ...

  2. 小梅哥Xilinx FPGA学习笔记1——二选一多路器

    二选一多路器 〇.功能介绍 1.功能描述 2.原理图 一.代码编写 1.设计文件 2.激励文件 3.仿真图 二.总结 〇.功能介绍 1.功能描述 sl为控制信号,a,b为两个输入信号,out为输出信号 ...

  3. 【K210】K210学习笔记五——串口通信

    [K210]K210学习笔记五--串口通信 前言 K210如何进行串口通信 K210串口配置 K210串口发送相关定义 K210串口接收相关定义 K210串口发送接收测试 完整源码 前言 本人大四学生 ...

  4. FPGA学习笔记_UART串口协议_串口接收端设计

    FPGA学习笔记 1. UART串口协议以及串口接收端设计 1 原理图 2 Verilog 代码 3 Modelsim仿真 4. FPGA板级验证 1.1 串口协议接收端设计 目标:FPGA接收其他设 ...

  5. xilinx fpga学习笔记2

    第二章:Xilinx FPGA的结构和分类 目前主流的FPGA都采用基于SRAM工艺的查找表结构,也有一些军品和宇航级FPGA采用Flash或者熔丝与反熔丝工艺的查找表结构. 1.查找表的结构和功能 ...

  6. 51单片机学习笔记-6串口通信

    6 串口通信 [toc] 注:笔记主要参考B站江科大自化协教学视频"51单片机入门教程-2020版 程序全程纯手打 从零开始入门". 注:工程及代码文件放在了本人的Github仓库 ...

  7. 51单片机学习笔记(串口通信 LED点阵屏 DS1302)

    四.串口通信 1.基本概念 通信中最重要的两个方面: 信息表示和解析方法: 信息的传输方法. 通信双方事先需要约定好信息的表示方法和解析方法,做到一致,否则信息不能有效传递. 信号的传输方法是指经过编 ...

  8. C51单片机学习笔记之串口通信

    简介 串口通信就是单片机和pc之间的一种通信方式. 通信方式:并行,串行,同步,异步(最常用的) 传输方向:单工,半双工(不同时间),全双工 基本结构 ​ 相关寄存器 SCON串口控制寄存器(主要用方 ...

  9. Arduino学习笔记⑥ 硬件串口通信

    文章目录 1.前言 2.常用串口函数 2.1 begin -- 启用串口 2.2 end -- 停用串口 2.3 print.println.printF -- 打印输出数据 2.4 read -- ...

  10. 嵌入式学习笔记7——串口通信

    并行通信和串行通信的区别: 并行通信通常是将数据字节的各位用多条数据线同时进行传送 . 串行通信是将数据字节分成一位一位的形式在一条传输线上逐个地传送. 异步 不要求收发双方时钟的严格一致,实现容易, ...

最新文章

  1. *args and **kwargs in Python 变长参数
  2. LeetCode-二分查找-278. 第一个错误的版本
  3. Android TV开发焦点动作控制小技巧
  4. jQuery 源码分析笔记(3)
  5. 局域网共享问题全方位解决
  6. 赛可达实验室发布2015测评认证标准
  7. Android嵌入式安卓触摸屏|4418开发板平台
  8. 通过hadoop + hive搭建离线式的分析系统之快速搭建一览
  9. SAP License:SAP PI(流程集成)
  10. 评价类模型:1.层次分析法
  11. FL studio 20简易入门教程 -- 第八篇 -- 技巧合集
  12. Java反射创建对象效率高还是通过new创建对象的效率高?
  13. 近而立之年了,老程序员如何建立自己的护城河
  14. django里template中的书名号
  15. 大学英语综合教程二 Unit 8 课文内容英译中 中英翻译
  16. 51单片机教程(从原理开始基于汇编)
  17. python pptx文本提取
  18. 操作系统的分类有哪些?
  19. 还在自己手写请假流程吗?Activiti7帮你快速请假!!!
  20. 如何使用【亿愿专利下载器】批量下载美国专利的PDF全文

热门文章

  1. vue+croppr.js 裁剪圆形图片
  2. props传值强校验validator
  3. 24_MySQL高可用之MMM
  4. 聪明的猴子 黑暗爆炸 - 2429
  5. iOS 图片编辑——涂鸦——在图片上添加文字
  6. rabbitmq的web管理界面无法使用guest用户登录
  7. html超链接自动下划线,html超链接下划线应该加入吗?
  8. 《Proof of Federated Learning: A Novel Energy-recycling Consensus Algorithm》精读
  9. 百度风云榜实时热点API
  10. Excel文件减肥修复终极办法----解决Excel文件打开慢的问题