0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Uart协议及Verilog代码

FPGA之家 来源:FPGA之家 作者:FPGA之家 2022-07-31 10:26 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

代码注释有些匆忙,如有错误注释还请批评,仅作参考

UART

Uart比较简单,所以仅对tx作比较详细的注释,但里面一些内容还是值得新手学习的

1开始位(低电平)+8位数据+1停止位(高电平,这里选的是一个周期高电平,也可两个)(无校验位)

1、prescale是完成一个bit需要主时钟计数的次数(其和主时钟以及波特率之间的关系参考网上文章)

2、进入uart模块的异步信号,最好使用提供的同步器同步

3、异步复位信号最好使用提供的同步器同步

4、波特率任意选,只要时钟够大,能够符合误码率计算即可,这里使用的是125Mhz

5、基本的思想就是移位

6、传输条件就是握手

7、如果使用Xlinx的片子,建议使用全局时钟资源(IBUFG后面连接BUFG的方法是最基本的全局时钟资源的使用方法)

8、这个完整的代码就是使用IBUFG+BUFG

9、传输虽然简单,但对于新手来讲,还是有挺多的知识点值得学习的点

10、公众号只是对代码进行了简单注释

UART的发送数据模块


// 欢迎大家关注公众号:AriesOpenFPGA// Q群:808033307// Language: Verilog 2001
// 代码注释有些匆忙,如有错误注释还请批评,仅作参考// UART// 1开始位+8位数据+1停止位(无校验)// prescale是完成一个bit需要主时钟计数的次数(其和主时钟以及波特率之间的关系参考网上文章)// 进入uart模块的异步信号,最好使用提供的同步器同步// 异步复位信号最好使用提供的同步器同步// 波特率任意选,只要时钟够大,能够符合误码率计算即可,这里使用的是125M// 基本的思想就是移位// 传输条件就是握手// 如果使用Xlinx的片子,建议使用全局时钟资源(IBUFG后面连接BUFG的方法是最基本的全局时钟资源的使用方法)// 这个完整的代码就是使用IBUFG+BUFG// 传输虽然简单,但对于新手来讲,还是有挺多的知识点值得学习的// 公众号只是对代码进行了简单注释`timescale 1ns / 1ps/* AXI4-Stream UART */module uart_tx #(    parameter DATA_WIDTH = 8)(    input  wire                   clk,           // 系统时钟    input  wire                   rst,           // 复位信号
   /* AXI input */    input  wire [DATA_WIDTH-1:0]  s_axis_tdata,  // 输入到这个模块准备发送出去的数据    input  wire                   s_axis_tvalid, // 有数据要输入到这个模块    output wire                   s_axis_tready, // 该模块准备好接收数据
    output wire                   txd,     // UART interface    output wire                   busy,    // Status 线忙    input  wire [15:0]            prescale // Configuration 预分度);
reg s_axis_tready_reg = 0;reg txd_reg           = 1;reg busy_reg          = 0;
reg [DATA_WIDTH:0] data_reg = 0;reg [18:0] prescale_reg     = 0;reg [3:0] bit_cnt           = 0;
assign s_axis_tready = s_axis_tready_reg;assign txd           = txd_reg;assign busy          = busy_reg;
always @(posedge clk) begin    if (rst)         begin            s_axis_tready_reg <= 0;  // 从机没有准备好发送            txd_reg           <= 1;  // 发送线拉高            prescale_reg      <= 0;  //             bit_cnt           <= 0;  // 位计数器初始化为0            busy_reg          <= 0;  // 复位后为不忙状态        end    else         begin            if (prescale_reg > 0)                 begin                    s_axis_tready_reg <= 0;                    prescale_reg      <= prescale_reg - 1;                end             else if (bit_cnt == 0)     //比特计数器为0                begin                    s_axis_tready_reg <= 1;   // 从机把ready信号拉高                    busy_reg          <= 0;   // 忙信号拉低无效                    if (s_axis_tvalid)        // 如果从机准备好接收数据                        begin                            s_axis_tready_reg <= !s_axis_tready_reg;   //                             prescale_reg      <= (prescale << 3)-1;    //                             bit_cnt           <= DATA_WIDTH+1;         // 一共10次计数                            data_reg          <= {1'b1, s_axis_tdata}; //                             txd_reg           <= 0;                    // 起始位0(起始位tx拉低,停止位拉高)                            busy_reg          <= 1;                    // 开始传输后,传输线进入忙状态                        end                end             else                 begin                    if (bit_cnt > 1)   //                         begin                            bit_cnt             <= bit_cnt - 1;                            prescale_reg        <= (prescale << 3)-1;  // 经过(prescale << 3)-1次的系统时钟计数,完成一位的移位                            {data_reg, txd_reg} <= {1'b0, data_reg};   // 移位操作                        end                     else if (bit_cnt == 1)                          begin                            bit_cnt      <= bit_cnt - 1;                            prescale_reg <= (prescale << 3);                              txd_reg      <= 1;                // 停止位1                        end                end        end end
endmodule

UART的接收模块(不详细讲解)


// Language: Verilog 2001
`timescale 1ns / 1ps
/* * AXI4-Stream UART */module uart_rx #(    parameter DATA_WIDTH = 8)(    input  wire                   clk,    input  wire                   rst,
  /* AXI output */    output wire [DATA_WIDTH-1:0]  m_axis_tdata,    output wire                   m_axis_tvalid,    input  wire                   m_axis_tready,      /* UART interface */    input  wire                   rxd,      /* Status */         output wire                   busy,    output wire                   overrun_error,    output wire                   frame_error,      /* Configuration */    input  wire [15:0]            prescale
);
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = 0;reg m_axis_tvalid_reg = 0;
reg rxd_reg = 1;
reg busy_reg = 0;reg overrun_error_reg = 0;reg frame_error_reg = 0;
reg [DATA_WIDTH-1:0] data_reg = 0;reg [18:0] prescale_reg = 0;reg [3:0] bit_cnt = 0;
assign m_axis_tdata = m_axis_tdata_reg;assign m_axis_tvalid = m_axis_tvalid_reg;
assign busy = busy_reg;assign overrun_error = overrun_error_reg;assign frame_error = frame_error_reg;
always @(posedge clk) begin    if (rst) // 初始化各种参数           begin                           m_axis_tdata_reg <= 0;            m_axis_tvalid_reg <= 0;            rxd_reg <= 1;            prescale_reg <= 0;            bit_cnt <= 0;            busy_reg <= 0;            overrun_error_reg <= 0;            frame_error_reg <= 0;        end     else         begin            rxd_reg <= rxd;            overrun_error_reg <= 0;            frame_error_reg <= 0;
        if (m_axis_tvalid && m_axis_tready) // 准备有数据要发以及准被好发            begin                 m_axis_tvalid_reg <= 0;            end
        if (prescale_reg > 0) //             begin                                prescale_reg <= prescale_reg - 1;            end                     else if (bit_cnt > 0)             begin                if (bit_cnt > DATA_WIDTH+1)                     begin                        if (!rxd_reg)  // 实际的read为0时,开始计数bit                            begin                                               bit_cnt <= bit_cnt - 1;                                prescale_reg <= (prescale << 3)-1;  //prescale是16位移3位减1位,因为prescale_reg                            end                         else                             begin                                bit_cnt <= 0;                                prescale_reg <= 0;                            end                    end                                 else if (bit_cnt > 1)                     begin                        bit_cnt <= bit_cnt - 1;                        prescale_reg <= (prescale << 3)-1;                        data_reg <= {rxd_reg, data_reg[DATA_WIDTH-1:1]};                    end                                 else if (bit_cnt == 1)                     begin                        bit_cnt <= bit_cnt - 1;                        if (rxd_reg)                             begin                                m_axis_tdata_reg <= data_reg;                                m_axis_tvalid_reg <= 1;                                overrun_error_reg <= m_axis_tvalid_reg;                            end                         else                             begin                                frame_error_reg <= 1;                            end                    end            end         else             begin                busy_reg <= 0;                if (!rxd_reg)                 begin                    prescale_reg <= (prescale << 2)-2;                    bit_cnt <= DATA_WIDTH + 2;                    data_reg <= 0;                       busy_reg <= 1;                end            end                    endendendmodule

UART顶层


// Language: Verilog 2001
`timescale 1ns / 1ps
/* * AXI4-Stream UART */module uart #(    parameter DATA_WIDTH = 8)(    input  wire                   clk,    input  wire                   rst,
    /*     * AXI input     */    input  wire [DATA_WIDTH-1:0]  s_axis_tdata,    input  wire                   s_axis_tvalid,    output wire                   s_axis_tready,
    /*     * AXI output     */    output wire [DATA_WIDTH-1:0]  m_axis_tdata,    output wire                   m_axis_tvalid,    input  wire                   m_axis_tready,
    /*     * UART interface     */    input  wire                   rxd,    output wire                   txd,
    /*     * Status     */    output wire                   tx_busy,    output wire                   rx_busy,    output wire                   rx_overrun_error,    output wire                   rx_frame_error,
    /*     * Configuration     */    input  wire [15:0]            prescale
);
uart_tx #(    .DATA_WIDTH(DATA_WIDTH))uart_tx_inst (    .clk(clk),    .rst(rst),    // axi input    .s_axis_tdata(s_axis_tdata),    .s_axis_tvalid(s_axis_tvalid),    .s_axis_tready(s_axis_tready),    // output    .txd(txd),    // status    .busy(tx_busy),    // configuration    .prescale(prescale));
uart_rx #(    .DATA_WIDTH(DATA_WIDTH))uart_rx_inst (    .clk(clk),    .rst(rst),    // axi output    .m_axis_tdata(m_axis_tdata),    .m_axis_tvalid(m_axis_tvalid),    .m_axis_tready(m_axis_tready),    // input    .rxd(rxd),    // status    .busy(rx_busy),    .overrun_error(rx_overrun_error),    .frame_error(rx_frame_error),    // configuration    .prescale(prescale));
endmodule

同步(异步复位)模块


// Language: Verilog-2001// 很常用的模块`timescale 1 ns / 1 ps
/* * Synchronizes an active-high asynchronous reset signal to a given clock by * using a pipeline of N registers. */module sync_reset #(    parameter N=2 // depth of synchronizer)(    input wire clk,    input wire rst,    output wire sync_reset_out);
reg [N-1:0] sync_reg = {N{1'b1}};
assign sync_reset_out = sync_reg[N-1];
always @(posedge clk or posedge rst) begin    if (rst)        sync_reg <= {N{1'b1}};    else        sync_reg <= {sync_reg[N-2:0], 1'b0};end
endmodule

同步(异步信号)模块


// Language: Verilog-2001//很常用的模块`timescale 1 ns / 1 ps
/* * Synchronizes an asyncronous signal to a given clock by using a pipeline of * two registers. */module sync_signal #(    parameter WIDTH=1, // width of the input and output signals    parameter N=2 // depth of synchronizer)(    input wire clk,    input wire [WIDTH-1:0] in,    output wire [WIDTH-1:0] out);
reg [WIDTH-1:0] sync_reg[N-1:0];
/* * The synchronized output is the last register in the pipeline. */assign out = sync_reg[N-1];
integer k;
always @(posedge clk) begin    sync_reg[0] <= in;    for (k = 1; k < N; k = k + 1) begin        sync_reg[k] <= sync_reg[k-1];    endend
endmodule

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Verilog
    +关注

    关注

    30

    文章

    1370

    浏览量

    114149
  • uart
    +关注

    关注

    22

    文章

    1304

    浏览量

    106123
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73154

原文标题:Uart协议及Verilog代码

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    UART、SPI、I2C 实战对比:哪个更适合你的项目?

    在嵌入式开发中,设备之间的通信是绕不开的话题。常见的三种总线接口——UART、SPI、I2C——各有优缺点。不同项目需求决定了选择哪一种协议最合适。本文结合实战经验,逐项对比三者,并附带实战代码
    的头像 发表于 11-24 19:04 329次阅读
    <b class='flag-5'>UART</b>、SPI、I2C 实战对比:哪个更适合你的项目?

    SPI、I2C、I2S、UART:通信协议对比表

    在嵌入式开发中,最常用的几种通信接口无非就是SPI、I2C、I2S、UART。名字看起来差不多,但应用场景和特性却大不相同。很多初学者容易混淆:为什么都叫串行通信,结构却不一样?为什么有的能传音频
    的头像 发表于 11-17 10:53 1187次阅读
    SPI、I2C、I2S、<b class='flag-5'>UART</b>:通信<b class='flag-5'>协议</b>对比表

    多路UART数据转发芯片 支持1主4从UART接口 UART扩展芯片

    UART接口
    稳控自动化
    发布于 :2025年11月13日 13:27:11

    多路UART数据转发芯片 支持1主4从UART接口 UART扩展芯片

    多路UART数据转发芯片 支持1主4从UART接口 UART扩展芯片 EU104 是一款高性能 UART 数据转发芯片,采用 SOP16 紧凑封装,工作电压范围为 2.0V 至 5.5
    的头像 发表于 11-12 10:33 153次阅读

    基于Hbird-e-sdk Linux环境下使用Uart0 对串口进行输入的软件代码参考

    本次代码是基于hbird-e-sdk下software参考示例demo_gpio的中断代码实现相应更改,然后通过蜂鸟调试器连接的UART0实现对串口的输入(PC/LINUX) 一.软件头文件修改
    发表于 10-31 06:32

    蜂鸟E203与电脑实现UART通信实现代码并实现上位机控制代码分享

    这里想和大家分享一下蜂鸟E203与电脑的UART通信代码,并通过UART实现上位机控制。 电脑端UART代码: #include "
    发表于 10-28 06:40

    JEDSD204B标准verilog实现-协议演进

    JEDSD204B标准verilog实现3-协议演进 本文对204协议的演进、子类的差异进行简要说明,后续将直接开始数据流的处理和实现,对协议要求的电器特性感兴趣的小伙伴自行查看
    发表于 09-05 21:18

    芯知识|广州唯创电子语音芯片UART通信协议解析:发码长度与校验码计算

    一、UART通信协议概述UART(通用异步收发器)是一种广泛应用于嵌入式系统的串行通信协议,其核心特点为无需时钟同步,通过起始位、数据位、校验位和停止位构成数据帧。在语音芯片应用中,
    的头像 发表于 05-27 08:48 529次阅读
    芯知识|广州唯创电子语音芯片<b class='flag-5'>UART</b>通信<b class='flag-5'>协议</b>解析:发码长度与校验码计算

    基于小凌派RK2206开发板:OpenHarmony如何使用IoT接口控制UART外设

    1、实验简介本实验将演示如何在小凌派-RK2206开发板上使用IOT库的UART接口,进行UART编程开发。例程将创建一个任务,通过配置UART引脚,实现UART读写操作。例程源
    的头像 发表于 04-22 14:22 802次阅读
    基于小凌派RK2206开发板:OpenHarmony如何使用IoT接口控制<b class='flag-5'>UART</b>外设

    FPGA Verilog HDL语法之编译预处理

    Verilog HDL语言和C语言一样也提供了编译预处理的功能。“编译预处理”是Verilog HDL编译系统的一个组成部分。Verilog HDL语言允许在程序中使用几种特殊的命令(它们不是一般
    的头像 发表于 03-27 13:30 1089次阅读
    FPGA <b class='flag-5'>Verilog</b> HDL语法之编译预处理

    ElfBoard嵌入式教育科普|UART接口全面解析

    掌握UART等通信接口的深入知识,对嵌入式初学者而言,不仅能够深化对通信协议与方式的认知,增强调试技巧及通信接口设计能力,还能拓宽应用范畴并培育系统级思考方式。因此本文将对UART接口进行全面解析
    的头像 发表于 03-10 09:29 1597次阅读
    ElfBoard嵌入式教育科普|<b class='flag-5'>UART</b>接口全面解析

    受电端PD快充协议芯片,支持全协议,支持UART串口通讯协议

    置串口通讯协议芯片,这不但使产品的成本增高,也占据了PCB板空间。汇铭达XSP16作为一款既支持快充功能又支持通过UART串口通讯的受电端诱骗协议芯片受到广大关注,它凭借卓越的性能和稳定性,成为了众多电子设备厂商的首选。本文将深
    的头像 发表于 12-26 16:13 1348次阅读
    受电端PD快充<b class='flag-5'>协议</b>芯片,支持全<b class='flag-5'>协议</b>,支持<b class='flag-5'>UART</b>串口通讯<b class='flag-5'>协议</b>

    Verilog 与 ASIC 设计的关系 Verilog 代码优化技巧

    Verilog与ASIC设计的关系 Verilog作为一种硬件描述语言(HDL),在ASIC设计中扮演着至关重要的角色。ASIC(Application Specific Integrated
    的头像 发表于 12-17 09:52 1455次阅读

    Verilog 测试平台设计方法 Verilog FPGA开发指南

    Verilog测试平台设计方法是Verilog FPGA开发中的重要环节,它用于验证Verilog设计的正确性和性能。以下是一个详细的Verilog测试平台设计方法及
    的头像 发表于 12-17 09:50 1562次阅读

    Verilog与VHDL的比较 Verilog HDL编程技巧

    Verilog 与 VHDL 比较 1. 语法和风格 VerilogVerilog 的语法更接近于 C 语言,对于有 C 语言背景的工程师来说,学习曲线较平缓。它支持结构化编程,代码
    的头像 发表于 12-17 09:44 2696次阅读