UART串口通信

  1. uart概述
    uart全称叫做异步收发传传输器,能够将多bit数据变为一位一位的进行传输,uart作为一种通用串行数据总线,用于异步通信,可实现全双工接发。RS232是uart的一种,是比较常见的一种串行通讯接口,用于PC机和外部板级进行通信。
  2. RS232通信协议的理解
    1.RS232有两根位宽为1bit的数据线,分别为rx和tx,rx用于接收数据,tx用于发送数据。
    2.rx作为接收线,当上位机通过串口向FPGA发送8位的数据的时候,从数据的最低位到最高位依次发送,FPGA会从rx线一位一位的接收到数据然后拼接还原成原来的8bit数据。同理,当FPGA向上位机发送数据的时候,也是从最低位到最高位,上位机通过tx线接收到每个bit数据后拼接还原成8bit数据。
    3.当rx/tx处于空闲状态时,都处于高电平状态。当开始需要发送数据的时候,数据线会进入一个起始状态即低电平状态,接着是8bit的数据位,数据结束后会有一个停止位,停止位为高电平。若后面数据传送,则会进入空闲态;如果继续收发数据的话,停止位后面会另外接上起始位即0电平。如下图:

    4.关于波特率:即串口通信时的速率,单位时间内载波变化的次数,这里选用的是9600Bd,即发送一比特数据需要的时间为 1/9600 秒。串口收发内容包含着1bit起始位+8位数据位+1bit停止位,每个bit都需要1/9600s。上位机在发送数据的时候,在发送8bit数据之前自动发送1bit的起始位,当8bit数据位发送完成的时候后自动发送1bit的停止位。同理上位机在接收数据时也是如此。
    5.板卡的时钟是50mhz,因为每个bit收发的时间是1/9600s,用该时钟来计数时需要cnt=(1/9600)/20=5208这么多个时钟才能传输该bit,即每个bit需要5208个系统时钟之后再传输下个bit。
  3. RS232回环测试
    测试的原理其实很简单,上位机通过串口助手把数据通过rx发送到FPGA中,然后在通过tx传回到上位机,当回传的数据和发送的数据一致时,证明uart收发是没有问题的。
  4. 顶层框图的设计:

    根据上面这个框图,需要设计出uart_rx和uart_tx两个部分,单独验证完每个模块之后再例化到顶层中完成回环测试。
  5. 根据时序写出对应的代码,uart_rx和uart_tx,然后例化到顶层文件top_uart中。
    uart_rx代码:
module uart_rx(input     wire        clk,
input   wire        rst_n,
input   wire        rx,
output  wire        po_flag,
output  wire [7:0]  po_data);parameter  CNT_BAUD_END        = 5207;//  (1/9600)s/20ns
parameter   CNT_BAUD_END_HALF   = 2603;reg                 rx1,rx2,rx3;
reg                 rx_flag;reg     [12:0]      cnt_baud;
reg                 bit_flag;
reg     [3:0]       bit_cnt;
reg     [7:0]       po_data_r;
reg                 po_flag_r;assign po_data = po_data_r;
assign po_flag = po_flag_r;always @(posedge clk) begin{rx3,rx2,rx1} <= {rx2,rx1,rx};
end// rx_flag
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginrx_flag <= 1'b0;endelse if (bit_cnt == 'd8 && bit_flag == 1'b1 && rx_flag == 1'b1) beginrx_flag <= 1'b0;endelse if (rx3 == 1'b1 && rx2 ==1'b0) beginrx_flag <= 1'b1;end
end// cnt_baud
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) begincnt_baud <= 'd0;endelse if (rx_flag == 1'b0) begincnt_baud <= 'd0;endelse if (rx_flag == 1'b1 && cnt_baud == CNT_BAUD_END) begincnt_baud <= 'd0;endelse if (rx_flag == 1'b1) begincnt_baud <= cnt_baud + 1'b1;end
end// bit_flag
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginbit_flag <= 1'b0;endelse if (rx_flag == 1'b1 && cnt_baud == CNT_BAUD_END_HALF) beginbit_flag <= 1'b1;endelse beginbit_flag <= 1'b0;end
end// bit_cnt
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginbit_cnt <= 'd0;endelse if (rx_flag == 1'b1 && bit_flag == 1'b1 && bit_cnt == 'd8) beginbit_cnt <= 'd0;endelse if (rx_flag == 1'b1 && bit_flag == 1'b1) beginbit_cnt <= bit_cnt  + 1'b1;end
end// po_data_r
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginpo_data_r <= 'd0;endelse if (bit_cnt >= 'd1 && bit_flag == 1'b1) beginpo_data_r <= {rx3,po_data_r[7:1]};end
end// po_flag_r
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginpo_flag_r <= 1'b0;endelse if (bit_cnt == 'd8 && bit_flag == 1'b1 && rx_flag == 1'b1) beginpo_flag_r <= 1'b1;endelse beginpo_flag_r <=1'b0;end
endendmodule

uart_tx代码:

module uart_tx(input     wire        clk,
input   wire        rst_n,
input   wire        pi_flag,
input   wire [7:0]  pi_data,
output  wire        tx);parameter   CNT_BAUD_END        = 5207;//  (1/9600)s/20nsreg       [7:0]   data_reg;
reg                 tx_flag;
reg     [12:0]      cnt_baud;
reg                 bit_flag;
reg     [3:0]       bit_cnt;
reg                 tx_r;reg    [7:0]       shift_reg;assign tx = tx_r;// data_reg
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) begindata_reg <= 'd0;endelse if (pi_flag == 1'b1) begindata_reg <= pi_data;end
end// tx_flag
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) begintx_flag <= 1'b0;endelse if (cnt_baud == CNT_BAUD_END && bit_flag == 1'b1 && bit_cnt == 'd8) begintx_flag <= 1'b0;endelse if (pi_flag == 1'b1) begintx_flag <= 1'b1;end
end// cnt_baud
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) begincnt_baud <= 'd0;endelse if (tx_flag == 1'b1 && cnt_baud == CNT_BAUD_END) begincnt_baud <= 'd0;endelse if (tx_flag == 1'b1) begincnt_baud <= cnt_baud + 1'b1;end
end// bit_flag
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginbit_flag <= 1'b0;endelse if (tx_flag == 1'b1 && cnt_baud == CNT_BAUD_END-1) beginbit_flag <= 1'b1;endelse beginbit_flag <= 1'b0;end
end// bit_cnt
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginbit_cnt <= 'd0;endelse if (bit_flag == 1'b1 && bit_cnt == 'd8) beginbit_cnt <= 'd0;endelse if (bit_flag == 1'b1) beginbit_cnt <= bit_cnt +1'b1;end
end// tx_r
always @(posedge clk or  negedge rst_n) beginif (rst_n == 1'b0) begintx_r <= 1'b1;endelse if (pi_flag == 1'b1) begintx_r <= 1'b0;endelse if (bit_cnt <= 'd7 && bit_flag == 1'b1) begintx_r <= data_reg[bit_cnt];endelse if (bit_cnt == 'd8 && bit_flag == 1'b1) begintx_r <= 1'b1;end
endendmodule
  1. 写tb文件完成验证。tb的内容主体有三个部分:时钟部分,复位信号,rx数据的产生方式。这里重点记住rx数据是怎么产生的。自己先写一个数据文件,深度为16,位宽为8,然后进行读取。用$readmemh把数据读取到自己定义的变量中去,然后用两个task分别读取深度和宽度。读取深度的task中就有嵌套读取宽度的task。从而达到把写好的8位数据,一位一位的传到rx中,实现并转串。task部分代码如下:
task rd_byte();integer i;for(i=0;i<16;i=i+1)beginrd_bit(mem[i]);endendtasktask rd_bit(input [7:0] data);integer i;for(i=0;i<10;i=i+1)begincase(i)0:rx = 0;1:rx = data[i-1];2:rx = data[i-1];3:rx = data[i-1];4:rx = data[i-1];5:rx = data[i-1];6:rx = data[i-1];7:rx = data[i-1];8:rx = data[i-1];9:rx = 1;endcase#104160;endendtask
  1. 完成以上部分后可以在modelsim中进行验证,若tx中的数据和rx中的是对应,再检查uart_rx和uart_tx部分无误后即可,若有错误,定位到错误到错误点。按照路径进行检查。
  2. 最后一部分则是进行板级验,连接好开发板后,进入ise生bit文件下载到板卡中,打开友善串口助手,把数据位宽和波特率设置好之后,发送数据,最终反馈回来相同的数据。如下:

project1--1.1UART串口通信相关推荐

  1. python第三方库之学习pyserial库--串口通信

    pyserial串口通信库 1.安装pyserial库 2.填写串口参数的注意事项 3.简单封装一下 4.碰到的bug 1.安装pyserial库 pip install pyserial versi ...

  2. VC串口通信编程-2

    VC串口通信编程 (2009-07-08 13:48:40) 转载▼ Win32串口编程(转:韩耀旭) 在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信 ...

  3. Linux ROS与嵌入式的串口通信

    1.根据ros wiki的官方教程 学习即可,并且有许多例子可供学习 http://wiki.ros.org/rosserial_arduino/Tutorials 2.用ASIO读写设备串行口 AS ...

  4. 投影串口测试程序_【原创】串口通信测试程序

    源代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...

  5. labVIEW与单片机实现串口通信的设计过程

    1.概述 在现代测控系统中,我们经常会采用上位机和下位机的开发控制模式.下位机主要是用来采集数据,可以通过嵌入式控制器.单片机控制器.PLC等来实现.上位机主要是图形界面,用来实时显示采集数据,并进行 ...

  6. chord协议模拟实现_C#.NET和单片机串口通信实现监控单片机数字量输入继电器输出模拟量输入模拟量输出...

    一.必备软件和硬件: 1.C#.NET: 2.单片机开发板: 3.通信电缆. 二.通信参数: 1.数据位:8位 2.校验方式:无校验 3.停止位:1位 4.波特率:9600bps 5.通信协议:自定义 ...

  7. java串口通信DataRecive_串口通信之DataReceive事件触发时机

    环境:Windows PC.本机虚拟COM2连接COM3.串口调试助手COM2发数据 图1 1> ReceivedBytesThreshold为默认值1:2> 一次发送41个字节:3> ...

  8. 读取串口数据_自定义串口通信的相关问题整理

    串口通信是常见的通信方式,串口接口是大部分工控器件标配的通信接口.在项目开发的过程中,也经常遇到进行串口通信的处理.这里就串口通信的部分问题分享给大家. 1.TTL.RS232.RS422.RS458 ...

  9. [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)...

    星期一, 20. 八月 2018 01:53上午 - beautifulzzzz 1.前言 做类似zigbee.ble mesh...无线网络节点性能测试的时候,手动操作然后看表象往往很难找出真正的原 ...

最新文章

  1. RDKit toolkit实战二:Generating Similarity Maps Using Fingerprints
  2. python捷豹_图像处理基本工具——Python 环境下的 Pillow( PIL )
  3. IP地址、子网掩码和地址分类
  4. 电路基础知识 -- 三态
  5. Discuz!NT 和网站整合
  6. 41、java应用占用cpu过高原因分析
  7. Expected MultipartHttpServletRequest: is a MultipartResolver configured方案。
  8. 语音识别已逐渐普及 搜狗讯飞各具特色
  9. 雷林鹏分享:PHP 表单 - 验证邮件和URL
  10. 远程工作两个月的体会(转)
  11. 身份证编号前六位对应地区(上)
  12. c语言五子棋设计报告及源代码,课程设计模板C语言之五子棋附源代码.pdf
  13. 很认真的聊一聊程序员的自我修养
  14. 电脑计算机c盘缓存清理,怎么清除电脑C盘缓存
  15. “宝付金融知识普及月”利益相关请务必关注
  16. 斯坦福大学-自然语言处理入门 笔记 第十四课 CGSs和PCFGs
  17. excel表格横向纵向变换_EXCEL打印妙招!(专为新手打造)!
  18. 企业内部系统产品人员对接规范
  19. 毕马威计算机测试题,KPMG毕马威2019招聘最新在线测试cute数字文字逻辑推理答案及解析...
  20. Typo: In word 拼写检查

热门文章

  1. 《惢客创业日记》2020.07.02(周四)七月份的工作计划
  2. swing中播放音频文件,封装成类,完美应用
  3. php cst时间,时区缩写 UTC, CST, GMT, CEST 以及转换(示例代码)
  4. Eureka和zookeeper都可以提供服务注册与发现的功能,请说说两个的区别
  5. iPhone内存管理详细解说(一)
  6. 单片机和计算机特点,什么是单片机,与电脑比较有什么优缺点
  7. 数据库结构设计(逻辑设计和物理设计)
  8. 英飞凌 —— 一文弄懂IGBT驱动
  9. 计算机管理点开没反应,windows 10操作系统右击此电脑点-管理没反应怎么处理...
  10. matlab gui设计 一个按钮两个功能(开始和暂停)