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

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

3天内不再提示

UART的回环实例代码设计

FPGA之家 来源:FPGA之家 作者:FPGA之家 2022-07-10 09:20 次阅读

1.UART

UART是异步串行通信口的总称。它所包含的RS232RS449RS423等等是对应各种异步串行通信口的接口标准和总线标准。他们规定了通信口的电气特性、传输速率、连接特性和机械特性等一系列内容,实际上属于通信网络的底层概念,与通信协议没有直接关系。

几个相关名词的解释:

·波特率:每秒钟传送的bit的个数。

·起始位:先发出一个逻辑0的信号,表示传输数据的开始。

·数据位:衡量通信中实际数据位的参数,标准数据位可以是5、7、8位,从最低位开始传输。

·奇偶校验位:UART发送时,检查发送数据中“1”的个数,自动在奇偶校验位添加1/0,用于发送数据的校验。

·停止位:一个数据的结束标志,可以为1位、1.5位、2位的高电平。

·空闲位:处于逻辑1状态,表示当前线路上无数据传输。

·时序图:

033fe9e2-ff1c-11ec-ba43-dac502259ad0.png

·发送数据过程:空闲状态,线路处于高电平,当收到发送数据指令后,拉低电平一个数据位的时间,接着数据按从低位到高位依次发送,数据发送完毕,接着发送奇偶校验位和停止位(停止位为高电平),一帧数据发送结束。

·接收数据过程:空闲状态,线路处于高电平,当检测到线路的下降沿,说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕,接着接收并比较奇偶校验位是否正确,如果正确则通知接收端设备准备接收数据或存入缓存。

由于UART是异步传输,没有同步传输时钟。为保证数据传输的正确性,每个数据有16个时钟采样,取中间的采样值,以保证不会误码或滑码。

·设计实例:

下面是一个UART的回环实例代码设计:

接收模块uart_rx:

module uart_rx(    input rxd,    input clk,    output receive_ack,    output reg [7:0] data_i    );        parameter IDLE = 0;    parameter RECEIVE = 1;    parameter RECEIVE_END = 2;        reg [3:0] CS,NS;    reg [4:0] count;    reg [7:0] data_o_tmp;        always@(posedge clk)        CS <= NS;        always@(*) begin        NS <= CS;        case(CS)            IDLE:       if(!rxd) NS = RECEIVE;            RECEIVE:    if(count == 7) NS = RECEIVE_END;else NS = NS;            RECEIVE_END:NS = IDLE;            default:    NS = IDLE;        endcase    end        always@(posedge clk)        if(CS == RECEIVE)            count <= count + 1;        else if(CS == IDLE | CS == RECEIVE_END)            count <= 0;        always @(posedge clk)        if(CS == RECEIVE)begin            data_i[6:0] <= data_i[7:1];            data_i[7] <= rxd;        end            assign receive_ack = (CS == RECEIVE_END) ? 1 : 0;             endmodule
发送模块uart_tx:

module uart_tx(    input [7:0] data_o,    input       clk,    input       receive_ack,    output reg  txd    );    parameter IDLE          = 0;    parameter SEND_START    = 1;    parameter SEND_DATA     = 2;    parameter SEND_END      = 3;        reg [3:0] CS,NS;    reg [4:0] count;    reg [7:0] data_o_tmp;        always @ (posedge clk)        CS <= NS;        always @ (*) begin        NS <= CS;        case(CS)            IDLE:       begin if(receive_ack) NS = SEND_START;  end            SEND_START: begin NS = SEND_DATA;                   end            SEND_DATA:  begin if(count == 7) NS = SEND_END;     end            SEND_END:   begin if(receive_ack) NS = SEND_START;  end            default:    NS = IDLE;        endcase    end        always @(posedge clk)        if(CS == SEND_START)            count <= count + 1;        else if(CS == IDLE | CS == SEND_END)            count <= 0;        else            count <= count;        always @(posedge clk)        if(CS == SEND_START)            data_o_tmp <= data_o;        else if(CS == SEND_DATA)            data_o_tmp[6:0] <= data_o_tmp[7:1];        always @(posedge clk)        if(CS == SEND_START)            txd <= 0;        else if(CS == SEND_DATA)            txd <= data_o_tmp;        else if(CS == SEND_END)            txd <= 1;            endmodulemodule uart_tx(    input [7:0] data_o,    input       clk,    input       receive_ack,    output reg  txd    );    parameter IDLE          = 0;    parameter SEND_START    = 1;    parameter SEND_DATA     = 2;    parameter SEND_END      = 3;        reg [3:0] CS,NS;    reg [4:0] count;    reg [7:0] data_o_tmp;        always @ (posedge clk)        CS <= NS;        always @ (*) begin        NS <= CS;        case(CS)            IDLE:       begin if(receive_ack) NS = SEND_START;  end            SEND_START: begin NS = SEND_DATA;                   end            SEND_DATA:  begin if(count == 7) NS = SEND_END;     end            SEND_END:   begin if(receive_ack) NS = SEND_START;  end            default:    NS = IDLE;        endcase    end        always @(posedge clk)        if(CS == SEND_START)            count <= count + 1;        else if(CS == IDLE | CS == SEND_END)            count <= 0;        else            count <= count;        always @(posedge clk)        if(CS == SEND_START)            data_o_tmp <= data_o;        else if(CS == SEND_DATA)            data_o_tmp[6:0] <= data_o_tmp[7:1];        always @(posedge clk)        if(CS == SEND_START)            txd <= 0;        else if(CS == SEND_DATA)            txd <= data_o_tmp;        else if(CS == SEND_END)            txd <= 1;            endmodule
特定波特率产生模块clk_div:

module clk_div(    input clk,    output reg clk_out    );
    parameter baud_rata = 9600;parameterdiv_num='d125_000_000/baud_rata;//分频数等于时钟频率除以想要得到的波特率    reg [15:0] num;
    always @(posedge clk) begin        if(num == div_num) begin            num <= 0;            clk_out <= 1;        end        else begin            num <= num + 1;            clk_out <= 0;        end    end
endmodule

顶层文件uart_top:

module uart_top(    input clk,inputrxd,outputtxd    );
    wire clk_9600;    wire receive_ack;    wire [7:0] data;
    uart_tx uart_tx    (        .clk        (clk_9600),        .txd        (txd),        .data_o     (data),        .receive_ack(receive_ack)    );
    uart_rx uart_rx    (        .clk        (clk_9600),        .rxd        (rxd),        .data_i     (data),        .receive_ack(receive_ack)    );
    clk_div clk_div    (        .clk        (clk),        .clk_out    (clk_9600)    );
endmodule

2.PS/2 PS/2是一种双向同步串行通信协议。接口是一种6针的连接口,但只有四个引脚是有意义的,分别是Clock(时钟)、Data(数据)、VCC和GND。其中时钟和数据引脚是双向的。PS/2常用于连接某些输入设备,例如鼠标、键盘等。通信的两端通过时钟来同步,通过数据引脚来交换数据。任何一方想要抑制另外一方的通信,只需要将时钟引脚拉低即可。 如果是PC和PS/2键盘之间通信,PC必须做主机,即PC可以抑制键盘发送数据,而键盘不能抑制PC发送数据。 PS/2的每一位数据帧包含11-12位,具体含义如下:

数据位名称 说明
1个起始位 总是逻辑0
8个数据位 低位在前
1个奇偶校验位 奇校验
1个停止位 总是逻辑1
1个应答位 仅用在主机对设备的通信中

·PS/2的时序图:

03bf9700-ff1c-11ec-ba43-dac502259ad0.png

由设备产生时钟和数据,主机根据时钟来读取数据。以FPGA和PS/2键盘为例,键盘产生时钟和数据,FPGA只需要读数据。当时钟下降沿时,FPGA记录数据信号。 ·设计实例: 主机为FPGA,根据PS/2的时序,得到键盘的按键值。虽然在时序图中,主机是在时钟下降沿读取数据,但实际上要为了排除噪声干扰,需要在FPGA端对信号进行滤波。下面给出设计代码。

module ps2_keyboard(    input clk,    input clr,    input PS2C,       //ps2 clk in    input PS2D,       //ps2 data in        output [15:0] xkey);reg         PS2CF;reg         PS2DF;reg [7:0]   ps2c_filter;reg [7:0]   ps2d_filter;reg [10:0]  shift1;reg [10:0]  shift2;
assign xkey = { shift2[8:1], shift1[8:1] };always @(posedge clk or posedge clr) begin    if (clr) begin        ps2c_filter <= 11'b0;        ps2d_filter <= 11'b0;        PS2CF <= 1;        PS2DF <= 1;    end    else begin        ps2c_filter[7] <= PS2C;        ps2c_filter[6:0] <= ps2c_filter[7:1];        ps2d_filter[7] <= PS2D;        ps2d_filter[6:0] <= ps2d_filter[7:1];        if(ps2c_filter == 8'b1111_1111)            PS2CF <= 1;                         //去时钟毛刺        else if(ps2c_filter == 8'b0000_0000)            PS2CF <= 0;        if(ps2d_filter == 8'b1111_1111)            PS2DF <= 1;                         //去数据毛刺        else if(ps2d_filter == 8'b0000_0000)            PS2DF <= 0;    endend
always @(negedge PS2CF or posedge clr) begin    if (clr) begin        shift1 <= 11'b0;        shift2 <= 11'b0;    end    else begin        shift1 <= {PS2DF, shift1[10:1]};        shift2 <= {shift1[0], shift2[10:1]};     endend
endmodule

原文标题:常用通信协议总结及FPGA实现(上)

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

审核编辑:彭静

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

    关注

    22

    文章

    1227

    浏览量

    101161
  • 代码
    +关注

    关注

    30

    文章

    4741

    浏览量

    68325
  • 异步串行通信

    关注

    0

    文章

    16

    浏览量

    8408
收藏 人收藏

    评论

    相关推荐

    如何对RK代码添加回环测试呢

    怎样去解决RK系列出现网口丢包的问题呢?如何对RK代码添加回环测试呢?
    发表于 03-02 06:36

    UART应用中的实例代码程序-UART In-Applic

    UART应用中的实例代码程序:A UART code loader provides in-system reprogrammability of program code spac
    发表于 01-23 23:04 66次下载

    UART 4 UART参考设计,Xilinx提供VHDL代码

    UART 4 UART参考设计,Xilinx提供VHDL代码 uart_vhdl This zip file contains the following folders
    发表于 06-14 08:57 114次下载

    UART参考设计,带16byte缓冲 VHDL代码 xapp

    UART参考设计,带16byte缓冲 VHDL代码 xapp223 These small UART transmitter and receiver macros of just 7 and 8
    发表于 06-14 09:00 33次下载

    Verilog 入门的实例代码

    Verilog 入门的实例代码,有需要的下来看看
    发表于 05-24 10:03 20次下载

    1768_UART_Test源代码

    1768_UART_Test源代码,下来看看
    发表于 06-07 10:41 13次下载

    LPC2368_UART代码

    LPC2368_UART代码,又需要的下来看看
    发表于 08-15 17:55 19次下载

    vhdl基础实例代码

    vhdl基础实例代码,感兴趣的小伙伴们可以瞧一瞧。
    发表于 11-11 17:17 5次下载

    CAN—回环测试

    程序简介 -工程名称:CAN回环测试 -实验平台: 秉火STM32 F429 开发板 -MDK版本:5.16 -ST固件库版本:1.5.1 【 !】功能简介: 使用CAN回环模式进行通讯实验。 学习
    发表于 12-13 15:35 31次下载

    python代码示例之基于Python的日历api调用代码实例

    本文档的主要内容详细介绍的是python代码示例之基于Python的日历api调用代码实例
    发表于 09-06 14:25 42次下载
    python<b class='flag-5'>代码</b>示例之基于Python的日历api调用<b class='flag-5'>代码</b><b class='flag-5'>实例</b>

    RTC LCD UART的源代码和工程文件免费下载

    本文档的主要内容详细介绍的是RTC LCD UART的源代码和工程文件免费下载
    发表于 01-03 16:22 4次下载
    RTC LCD <b class='flag-5'>UART</b>的源<b class='flag-5'>代码</b>和工程文件免费下载

    linux spi应用层驱动以及回环测试代码

    linux spi应用层驱动以及回环测试代码
    发表于 10-22 15:47 2次下载

    MPC82G516 MCU的串行UART示例代码

    MPC82G516 MCU的串行UART示例代码
    发表于 06-30 17:24 0次下载
    MPC82G516 MCU的串行<b class='flag-5'>UART</b>示例<b class='flag-5'>代码</b>

    鸿蒙应用实例代码

    鸿蒙应用实例代码,仅供参考。
    发表于 09-27 14:56 12次下载

    代码生成器配置和软件UART的实现

    (RL78)上的具体的实现方法,这里略去工程的建立过程,相应的驱动程序细节可以参考代码生成器生成的代码,这里只重点讲述代码生成器配置和软件UART的实现。
    的头像 发表于 05-09 09:25 1487次阅读
    <b class='flag-5'>代码</b>生成器配置和软件<b class='flag-5'>UART</b>的实现