前记:师夷长技以自强。

1.基本概念

UART:Universal Asynchronous Receiver/Transmitter,通用异步收发传输器,它是一种电子器件,可以在数据发送时将并行数据转换成串行数据来传输,在数据接收时将接收到的串行数据转换成并行数据。UART是异步串行通信的总称,包含了RS232,RS449,RS423,RS422和RS485等协议标准。

RS-232:美国电子工业联盟(EIA)制定的串行数据通信的接口标准,被广泛用于计算机串行接口外设连接。

2.UART设计

2.1关键参数

我们已经知道UART是一种串行传输协议,那么一次传多少个数据呢?应该传多快呢?怎么区分一次传输?还有既然是通信,难免会有干扰,如何降低数据传输错误率呢?这些都是一个通信设计者应该考虑的事情。

数据位:定义单个UART数据传输从开始到停止期间发送的数据位数。可以为5,6,7,8(默认)。

波特率:每秒可以通信的数据比特个数,典型波特率有300,1200,2400,9600,19200,115200。

奇偶校验类型:可选参数,分为奇校验(各数位和校验位中“1”的个数为奇数)和偶校验(各数位和校验位中“1”的个数为偶数)。

停止位:每次传输完成后就要发送停止位,可选1,1.5,2位。

2.2时序

需要注意的是,UART作为一种古老的传输协议,是先传低位数据的。

2.3电路设计

早起采用的方案是RS232转TTL

但由于DB9的RS232接口占用PCB太大,多数系统采用USB转TTL

在windows下装CH340G的驱动程序就能够仿真标准串口了。

3.UART模块设计

3.1模块框图

为了启动UART发送数据,需要一个Send_En信号;发送完成应该输出Tx_Done信号;待发送的数据data_byte[7:0];波特率设置baud_Set[2:0];输出的信号有RS232_Tx;还有基本的时序信号Clk和Rst_n,uart_state。

3.2 代码文件

module UART(
    input Clk,
    input Rst_n,
    input Send_En,
    input [7:0]data_byte,
    input [2:0]baud_set,
    output uart_state,
    output reg Tx_done,
    output reg Rs232_Tx
);
    reg en;
    reg [7:0]r_data_byte;
    reg [12:0]Clk_CNT;
    reg [3:0]BPS_CNT;
    reg [12:0]Clk_CNT_SHR;
    
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        en <= 0;
    else if(Send_En)
        en <= 1;
    else if(Tx_done)
        en <= 0;
    else    
        en <= en;
        
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        r_data_byte <= 0;
    else if(Send_En)
        r_data_byte <= data_byte;
    else
        r_data_byte <= r_data_byte;
        
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Clk_CNT_SHR <= 0;
    else if(Send_En)begin
        case(baud_set)
            0:
                Clk_CNT_SHR <= 5208;  //9600
            1:
                Clk_CNT_SHR <= 3472;  //14400
            2:
                Clk_CNT_SHR <= 2604;  //19200
            3:
                Clk_CNT_SHR <= 1736;  //28800
            4:
                Clk_CNT_SHR <= 1302;  //38400
            5:
                Clk_CNT_SHR <= 892;   //56000
            6:
                Clk_CNT_SHR <= 868;   //57600
            7:
                Clk_CNT_SHR <= 434;   //115200
            default:;
        endcase
    end
    else
        Clk_CNT_SHR <= Clk_CNT_SHR;
    
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Clk_CNT <= 0;
    else if(en)
        if(Clk_CNT == Clk_CNT_SHR)
            Clk_CNT <= 0;
        else
            Clk_CNT <= Clk_CNT + 13'b1;
    else 
        Clk_CNT <= 0;
    
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        BPS_CNT <= 0;
    else if(en&&Clk_CNT == Clk_CNT_SHR)begin
        if(BPS_CNT == 10)
            BPS_CNT <= 0;
        else
            BPS_CNT <= BPS_CNT + 4'b1;
    end
    else if(Tx_done)    
        BPS_CNT <= 0;
    else
        BPS_CNT <= BPS_CNT;
        
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Rs232_Tx <= 1;
    else if(en)
        case(BPS_CNT)
            0:
                Rs232_Tx <= 0;
            1:
                Rs232_Tx <= r_data_byte[0];
            2:
                Rs232_Tx <= r_data_byte[1];
            3:
                Rs232_Tx <= r_data_byte[2];
            4:
                Rs232_Tx <= r_data_byte[3];
            5:
                Rs232_Tx <= r_data_byte[4];
            6:
                Rs232_Tx <= r_data_byte[5];
            7:
                Rs232_Tx <= r_data_byte[6];
            8:
                Rs232_Tx <= r_data_byte[7];
            9:
                Rs232_Tx <= 1;
        endcase
    else
        Rs232_Tx <= 1;
        
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Tx_done <= 1;
    else if(en&&BPS_CNT==10)
        Tx_done <= 1;
    else
        Tx_done <= 0;
        
    assign uart_state = en;
        
    
endmodule

3.3 仿真

3.3.1 仿真文件

为了测试UART的时序是否正确,需要进行RTL仿真,代码如下

`timescale 1ns/1ns
`define clock_period 20

module UART_tb();
    reg Clk;
    reg Rst_n;
    reg Send_En;
    reg [7:0]data_byte;
    reg [2:0]baud_set;
    wire uart_state;
    wire Tx_done;
    wire Rs232_Tx;
    UART UART1(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .Send_En(Send_En),
        .data_byte(data_byte),
        .baud_set(baud_set),
        .uart_state(uart_state),
        .Tx_done(Tx_done),
        .Rs232_Tx(Rs232_Tx)
    );
    initial Clk = 0;
    always #10 Clk = ~Clk;
    initial begin
    Rst_n = 0;
    Send_En = 0;
    #`clock_period;
    Rst_n = 1;
    data_byte = 8'h53;
    baud_set = 0;
    Send_En = 1;
    #`clock_period;
    Send_En =0;
    wait(Tx_done);
    #20000;
    data_byte = 8'h73;
    Send_En = 1;
    #`clock_period;
    Send_En =0;
    wait(Tx_done);
    #20000;
    $stop;
    end
    
endmodule

仿真的结果为

3.3.2 板上测试

为了在开发板上能跑起来,需要在写一个UART_top模块,主要的测试思路是固定波特率为9600,要发送的数据是0x54,复位后就不断的发送数据,添加的代码文件如下

module UART_top(
    input Clk,
    input Rst_n,
    output Rs232_Tx
);
    reg Send_En;
    wire [7:0]data_byte;
    wire [2:0]baud_set;
    wire Tx_done;
    UART UART1(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .Send_En(Send_En),
        .data_byte(data_byte),
        .baud_set(baud_set),
        .uart_state(),
        .Tx_done(Tx_done),
        .Rs232_Tx(Rs232_Tx)
    );
    assign data_byte = 8'h54;
    assign baud_set = 8'b0;
    always@(posedge Clk,negedge Rst_n)
    if(!Rst_n)
        Send_En <= 0;
    else if(Tx_done)
        Send_En <= 1;
    else 
        Send_En <= 0;
endmodule

为了确保设计的时序没问题,可以先在软件上仿真,所以需要添加的测试文件UART_top_tb如下

`timescale 1ns/1ns

module UART_top_tb();
    reg Clk;
    reg Rst_n;
    wire Rs232_Tx;
    UART_top UART_top1(
        .Clk(Clk),
        .Rst_n(Rst_n),
        .Rs232_Tx(Rs232_Tx)
    );
    
    initial Clk = 0;
    always #10 Clk = ~Clk;
    
    initial begin
        Rst_n = 0;
        #20;
        Rst_n = 1;
        #10000000;
    end
    
endmodule

仿真后可以得到如下的波形

下载到开发板上,用在PC端用串口调试助手接收也可以看到收到的数据

3.EP4CE10F17的串口设计相关推荐

  1. C#串口设计SerialPort类(维修电工Demo)

    维修电工干久了,都不知道想干点啥? 写个串口助手吧, 0先做准备工作:ui的控件用 ComboBox 1引用命名空间 using System.IO.Ports;//引用命名空间 2 创建一个类对象 ...

  2. 百问网物联网实战-串口设计

    一 串口介绍 对于串口初始化的流程,我们可以总结为4点: 1.使能串口外设时钟: 2.使能串口外设的GPIO的时钟: 3.配置串口外设GPIO的复用功能: 4.配置串口的参数:波特率.数据位.停止位. ...

  3. FPGA串口(UART)通信协议制定与设计思路详解示例

    串口(UART)通信协议制定与设计思路详解 1 概述 本文用于描述规定的串口通信协议,以及传输内容. 2 项目关于串口的要求 a) 支持BIT自检,1路UART上报BIT信息: b) 1路UART接口 ...

  4. 【导纳分析】基于FPGA的导纳分析仪的verilog设计

    1.软件版本 ISE14.7+ Modelsim SE-64 10.1c 2.本算法理论知识 3.核心代码 `timescale 1ns / 1ps // // Company: // Enginee ...

  5. serialport通过usb通讯_IOT串口通讯-RS232/RS485

    串口 串口是串行接口(serial port)的简称,也称为串行通信接口或COM接口.串口通信是指采用串行通信协议(serial communication)在一条信号线上将数据一个比特一个比特地逐位 ...

  6. CH343芯片应用—硬件设计指南

    CH343属于沁恒第三代USB转串口芯片系列的单串口型号,基于经典版CH340芯片完成技术革新,实现USB转高速异步串口,支持最高6Mbps串口波特率. 电源设计 CH343芯片有3个电源端分别是VD ...

  7. 嵌入式学习(四)——串口

    目录 一.通信的基本概念 1.1 同步通信和异步通信 1.2 电平信号和差分信号 1.3 并行接口和串行接口 1.4 单工通信和双工通信 二.串口通信 2.1 基本概念 2.2 起始位.数据位.奇偶校 ...

  8. USB转52单片机下载串口的“转换芯片”MAX232与CH340G的区别

    USB转52单片机下载串口的"转换芯片"MAX232与CH340G的区别:首先需要说明,单片机的下载口TXD.RXD(P3.0与P3.1)是TTL电平(TTL电平是正逻辑数据表示, ...

  9. CH9101芯片应用—硬件设计指南

    CH9101芯片属于沁恒第三代USB转串口芯片系列的单串口型号,基于经典版CH340芯片完成技术革新,实现USB转高速异步串口,支持最高6Mbps串口波特率.CH9101提供了5种封装,CH9101U ...

最新文章

  1. oracle 提示:ORA-02292:integrity constraint(xxxxxxx) violated - child record found
  2. 面试Android实习生
  3. Visual C++语言编程开发详解(孙鑫老师)
  4. 3 weekend110的hadoop中的RPC框架实现机制 + hadoop中的RPC应用实例demo
  5. vbs获取cpu使用率
  6. IDEA中SpringBoot项目使用@Data要安装Lombok插件
  7. write up社工进阶
  8. Swift之深入解析“泛型”的底层原理
  9. C# 9 新特性 —— 增强的模式匹配
  10. fiddler抓包时,出现的 Tunnel to ***** : 443
  11. git升级后jenkins的报错
  12. [LevelDB] 编译和使用
  13. 百度文库的几种下载方法
  14. 李永乐复习全书线性代数 第三章 向量
  15. 西门子s300编程实例_几个西门子plc编程实例图解(含程序应用实例)
  16. git config之后仍无法commit,提示 “fatal: empty ident name“
  17. 【采集项目-(6)全量数据采集】
  18. python爬虫之创建表格
  19. 人行征信2.0对接服务:全业务种类数据,精细您的征信业务管理!
  20. android 实现区域截图

热门文章

  1. 重磅!英伟达400亿英镑收购Arm,国产芯片怎么办?
  2. 社保卡绑定支付宝,直接在支付宝上报销!
  3. 用友iuap重新定义PaaS平台 打造企业数智化新底座
  4. 查看购买物品订单情况
  5. MySQL—Apache+PHP+MySQL实现网上社区
  6. 为MacBook Pro制作WTG系统盘
  7. Python Celery和RabbitMQ实战教程
  8. 截取字符串后几位 php,字符串截取的几种办法(php,js,css三种)
  9. UNCTF2022部分题解
  10. Azure DevOps Server 2019 (TFS)安装教程