串口通信实现-串口接收(vivado&verilog版)

这篇具有很好参考价值的文章主要介绍了串口通信实现-串口接收(vivado&verilog版)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

串口系列知识分享:
(1)串口通信实现-串口发送
(2)串口通信发送多字节数据
(3)串口通信实现-串口接收
(4)UART 通信-使用VIO进行板级验证
(5)串口接收-控制LED闪烁
(6)使用串口发送实现ACX720开发板时钟显示
(7)串口发送+RAM+VGA传图


前言

此文介绍uart串口协议(串口接收)的verilog实现和testbench的编写,仿真环境为vivado 2018.3。

一、串口的通信协议

要进行模块的设计,首先要了解该部分功能的原理。这就涉及到串口的通信协议。
vivado串口通信,FPGA代码分享,fpga开发
从这个图中可以看到,在RX信号线中,空闲状态是高电平。也就是说在不传输信息的时候,信号线置高。拉低的信号就是起始信号,也就是要开始传输数据的信号。第一位是起始位,紧跟后面的是数据位,随后有校验位和停止位。

【设计思路】:

  1. 空闲状态: 高电平
  2. 起始位: 拉低并且持续一位的时间,也就是持续 1/bps 的时间
  3. 数据位: 从这位开始就是数据位,数据位的长度从5 到 8 不等。最常见的是8位数据位。
  4. 校验位: 作为数据的校验位。
  5. 停止位: 拉高持续0.5,1 或者 2个时钟,只要接收双方协议好即可。

这就是一帧数据中包含的信息量,其中对接收方来说最重要的自然是数据位。需要准确的从中提取出数据位,来进行下一步的处理。

其中校验位的设计又有多种选择,校验方法有奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)及无校验(noparity)。常见的就是无校验,或者奇偶校验。

无校验位:就是不设置校验位,直接跟上停止位。

奇偶校验位根据数据位中1 的个数来设计。
奇校验位:如果数据位中1 的个数为奇数个,则该位为0。如果数据位中1 的个数为偶数个,则该位为1。也就是要求数据位与校验位中 1 的个数为奇数。

偶校验位:和奇校验位相反。如果数据位中1 的个数为奇数个,则该位为1。如果数据位中1 的个数为偶数个,则该位为0。也就是要求数据位与校验位中 1 的个数为偶数。
————————————————

二、分模块设计

这次模块的设计让我也是重新的认识到 Verilog 语言设计新的一种格式。先设计好每一个相应的模块,在合理的将每个模块联系起来,形成需要的模块。这种方式使得整体的进程可以进行的比较有条理。下面我们先来进行第一步,分模块的设计。

1.检测模块

首先第一个是检测模块。该模块的功能是检测信号线的下降沿,也就是起始位的开始。那么只要做一个下降沿来的时候,产生一个时钟的高脉冲即可。

 reg [1:0]uart_rx_r;
 always@(posedge Clk)begin  //uart_rx为输入数据
        uart_rx_r[0] <= uart_rx;
        uart_rx_r[1] <= uart_rx_r[0] ;
   end
 wire nedge_uart_rx;
//assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));  
assign nedge_uart_rx = (uart_rx_r == 2'b10);       //下降沿检测

vivado串口通信,FPGA代码分享,fpga开发
根据上图知在uart_rx出现下降沿时,nedge_uart_rx会在下一个时钟上升沿出现高电平信号。

2.波特率设置

代码如下(示例):

reg [8:0]  Bps_DR;      //波特率设置
    always@(*)
        case(Baud_Set)
            0:Bps_DR = 1000000000/9600/16/20 - 1;
            1:Bps_DR = 1000000000/19200/16/20 - 1;
            2:Bps_DR = 1000000000/38400/16/20 - 1;
            3:Bps_DR = 1000000000/57600/16/20 - 1;
            4:Bps_DR = 1000000000/115200/16/20 - 1;
            default:Bps_DR = 1000000000/9600/16/20 - 1;
        endcase

此处为防止信号传输过程中产生干扰,将每一位信号分为16进行判断,舍去前5段,后五段,留中间5段进行判断。
vivado串口通信,FPGA代码分享,fpga开发

reg [8:0]div_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)    
        div_cnt <= 0;
    else if(RX_EN)begin
        if(div_cnt == Bps_DR)
            div_cnt <= 0;
        else
            div_cnt <= div_cnt + 1'b1;
    end
    else
        div_cnt <= 0;


    wire bps_clk_16x;      //取每个信号的中点值 
    assign bps_clk_16x = (div_cnt == Bps_DR / 2);

    
    reg [7:0]bps_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        bps_cnt <= 0;
    else if(RX_EN)begin
        if(bps_clk_16x)begin
            if(bps_cnt == 160)
                bps_cnt <= 0;
            else
                bps_cnt <= bps_cnt + 1'b1;
        end
        else
            bps_cnt <= bps_cnt;
     end
     else
        bps_cnt <= 0;

3.判断过程

//reg width name number/depth
    reg[2:0]r_data[7:0];
    reg [2:0]sta_bit;
    reg [2:0]sto_bit;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) begin
        sta_bit <= 0;
        sto_bit <= 0;
        r_data[0] <= 0;
        r_data[1] <= 0;
        r_data[2] <= 0;
        r_data[3] <= 0;
        r_data[4] <= 0;
        r_data[5] <= 0;
        r_data[6] <= 0;
        r_data[7] <= 0;
    end
    else if(bps_clk_16x)begin
        case(bps_cnt)
            0:begin
                sta_bit <= 0;
                sto_bit <= 0;
                r_data[0] <= 0;
                r_data[1] <= 0;
                r_data[2] <= 0;
                r_data[3] <= 0;
                r_data[4] <= 0;
                r_data[5] <= 0;
                r_data[6] <= 0;
                r_data[7] <= 0;
            end
            5,6,7,8,9,10,11:sta_bit <= sta_bit + uart_rx;
            21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
            37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
            53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
            69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
            85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
            101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
            117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
            133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
            149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
            default:;
        endcase
    end
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Data <= 0;        
    else if(bps_clk_16x && (bps_cnt == 159))begin
        Data[0] <= (r_data[0] >= 4)?1'b1:1'b0;
        Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
        Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
        Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
        Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
        Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
        Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
        Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
    end 

三、完整代码展示

module uart_byte_rx(
    Clk,
    Reset_n,
    Baud_Set,
    uart_rx,
    Data,
    Rx_Done,  
);

   input Clk;
   input Reset_n;
   input [2:0]Baud_Set;
   input uart_rx;
   output reg[7:0]Data; 
   output reg Rx_Done;
   
   reg [1:0]uart_rx_r;
   always@(posedge Clk)begin
        uart_rx_r[0] <= uart_rx;
        uart_rx_r[1] <= uart_rx_r[0] ;
   end

    wire pedge_uart_rx;
//    assign pedge_uart_rx = ((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1));
    assign pedge_uart_rx = (uart_rx_r == 2'b01);      
    wire nedge_uart_rx;
//    assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));  
    assign nedge_uart_rx = (uart_rx_r == 2'b10);       //下降沿检测
 
    reg [8:0]  Bps_DR;      //波特率设置
    always@(*)
        case(Baud_Set)
            0:Bps_DR = 1000000000/9600/16/20 - 1;
            1:Bps_DR = 1000000000/19200/16/20 - 1;
            2:Bps_DR = 1000000000/38400/16/20 - 1;
            3:Bps_DR = 1000000000/57600/16/20 - 1;
            4:Bps_DR = 1000000000/115200/16/20 - 1;
            default:Bps_DR = 1000000000/9600/16/20 - 1;
        endcase
        
    wire bps_clk_16x;      //取每个信号的中点值 
    assign bps_clk_16x = (div_cnt == Bps_DR / 2);

    reg RX_EN;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        RX_EN <= 0;
    else if(nedge_uart_rx)
        RX_EN <= 1;
    else if(Rx_Done || (sta_bit >= 4))
        RX_EN <= 0;
        
    reg [8:0]div_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)    
        div_cnt <= 0;
    else if(RX_EN)begin
        if(div_cnt == Bps_DR)
            div_cnt <= 0;
        else
            div_cnt <= div_cnt + 1'b1;
    end
    else
        div_cnt <= 0;

    reg [7:0]bps_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        bps_cnt <= 0;
    else if(RX_EN)begin
        if(bps_clk_16x)begin
            if(bps_cnt == 160)
                bps_cnt <= 0;
            else
                bps_cnt <= bps_cnt + 1'b1;
        end
        else
            bps_cnt <= bps_cnt;
     end
     else
        bps_cnt <= 0;
       
    //reg width name number/depth
    reg[2:0]r_data[7:0];
    reg [2:0]sta_bit;
    reg [2:0]sto_bit;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) begin
        sta_bit <= 0;
        sto_bit <= 0;
        r_data[0] <= 0;
        r_data[1] <= 0;
        r_data[2] <= 0;
        r_data[3] <= 0;
        r_data[4] <= 0;
        r_data[5] <= 0;
        r_data[6] <= 0;
        r_data[7] <= 0;
    end
    else if(bps_clk_16x)begin
        case(bps_cnt)
            0:begin
                sta_bit <= 0;
                sto_bit <= 0;
                r_data[0] <= 0;
                r_data[1] <= 0;
                r_data[2] <= 0;
                r_data[3] <= 0;
                r_data[4] <= 0;
                r_data[5] <= 0;
                r_data[6] <= 0;
                r_data[7] <= 0;
            end
            5,6,7,8,9,10,11:sta_bit <= sta_bit + uart_rx;
            21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
            37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
            53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
            69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
            85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
            101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
            117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
            133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
            149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
            default:;
        endcase
    end
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Data <= 0;        
    else if(bps_clk_16x && (bps_cnt == 159))begin
        Data[0] <= (r_data[0] >= 4)?1'b1:1'b0;
        Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
        Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
        Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
        Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
        Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
        Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
        Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
    end 
    
//    always@(posedge Clk or negedge Reset_n)
//    if(!Reset_n) 
//        Data <= 0;        
//    else if(bps_clk_16x && (bps_cnt == 159))begin
//        Data[0] <= r_data[0][2];
//        Data[1] <= r_data[1][2];
//        Data[2] <= r_data[2][2];
//        Data[3] <= r_data[3][2];
//        Data[4] <= r_data[4][2];
//        Data[5] <= r_data[5][2];
//        Data[6] <= r_data[6][2];
//        Data[7] <= r_data[7][2];
//    end 

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Rx_Done <= 0;
    else if((div_cnt == Bps_DR/2) && (bps_cnt == 160))
        Rx_Done <= 1;
    else
        Rx_Done <= 0; 
        
endmodule

四、TB文件

`timescale 1ns / 1ps

module uart_byte_rx_tb();

   reg Clk;
   reg Reset_n;
   wire [2:0]Baud_Set;
   reg uart_rx;
   wire [7:0]Data; 
   wire Rx_Done;
   
   assign Baud_Set = 4;
   
    uart_byte_rx uart_byte_rx(
        Clk,
        Reset_n,
        Baud_Set,
        uart_rx,
        Data,
        Rx_Done,  
    );
    
    initial Clk = 1;
    always#10 Clk = ~Clk;
    
    initial begin
       Reset_n = 0;
       uart_rx = 1;
       #201;
       Reset_n = 1;
       #200; 
       uart_tx_byte(8'h5a);
       #90000;
       uart_tx_byte(8'ha5);
       #90000;
       uart_tx_byte(8'h86);
       #90000;
       $stop;
    end
    
    task uart_tx_byte;
        input [7:0]tx_data;
        begin
            uart_rx = 1;
            #20;
            uart_rx = 0;
            #8680;
            uart_rx = tx_data[0];
            #8680;
            uart_rx = tx_data[1];
            #8680;
            uart_rx = tx_data[2];
            #8680;
            uart_rx = tx_data[3];
            #8680;
            uart_rx = tx_data[4];
            #8680;
            uart_rx = tx_data[5];
            #8680;
            uart_rx = tx_data[6];
            #8680;
            uart_rx = tx_data[7];
            #8680;
            uart_rx = 1;
            #8680;         
        end
    endtask
    
endmodule

五、仿真展示

vivado串口通信,FPGA代码分享,fpga开发
【附件:】链接:https://pan.baidu.com/s/1UcO93C8R2Ab3M9OTqssEKw?pwd=84i9
提取码:84i9文章来源地址https://www.toymoban.com/news/detail-522096.html

到了这里,关于串口通信实现-串口接收(vivado&verilog版)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【FPGA协议篇】UART通信及其verilog实现(代码采用传参实现模块通用性,适用于快速开发)

    ​ 即通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种 串行、异步、全双工 的通信协议。特点是通信线路简单,适用于远距离通信,但传输速度慢。 数据传输速率:波特率(单位:baud,波特) 常见波特率有:1200、2400、4800、19200、38400、57600等,最常用的是9600和11520

    2024年02月05日
    浏览(50)
  • FPGA——用vivado实现串口通讯协议

    串口通信是一种通过串行传输数据的通信方式。它使用单个数据线将数据位逐个传输,而不是同时传输多个数据位。串口通信常用于连接计算机与外部设备,如打印机、调制解调器、传感器等。 串口通信一般使用的是异步传输方式,即发送方和接收方的时钟不同步。数据传输

    2024年02月06日
    浏览(39)
  • FPGA实现串口的任意字节数接收

    目录 1、概述 2、串口接收驱动 3、任意字节接收的实现方法 4、仿真

    2024年02月09日
    浏览(37)
  • 串口通信(6)应用定时器中断+串口中断实现接收一串数据

     本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步! 发布人:@日月同辉,与我共生_单片机-CSDN博客 欢迎你为独创博主日月同辉,与我共生点赞❤❤❤+关注👍+收藏🌹+评论☺。 系列专栏: CSDN- 单片机串

    2024年02月06日
    浏览(57)
  • c51单片机串口通信(中断方式接收数据)(单片机--单片机通信)示例代码 附proteus图

         单片机一般采用中断方式接受数据,这样便于及时处理 其中发送数据段采用的是查询方式,接收端采用了中断方式, 要注意的地方有: 在中断处理函数int_0()内,处理数据前要先关闭中断,否则中断可能会不断传过来, EA=0; 然后退出中断处理函数前恢复中断处理能力:

    2024年02月13日
    浏览(65)
  • FPGA用verilog HDL实现串口通讯协议

    串口通信是一种通过串行传输数据的通信方式。它使用单个数据线将数据位逐个传输,而不是同时传输多个数据位。串口通信常用于连接计算机与外部设备,如打印机、调制解调器、传感器等。 串口通信一般使用的是异步传输方式,即发送方和接收方的时钟不同步。数据传输

    2024年02月05日
    浏览(62)
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)

    🎉欢迎来到Python专栏~与FPGA、蓝牙模块实现串口通信 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: Python学习专栏 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ Python与FPGA串口通信

    2024年02月15日
    浏览(45)
  • FPGA 串口通信(uart)初探篇(含源代码)

    一、UART 串口通信,说实话是日常生活中很常见的一种9针型的主机和显示屏之间的通信模式。本次博客,只为自己复盘相关知识,初学者,错误较多,请多指教。所以本文参考(一)FPGA之串口通信(UART)_fpga uart-CSDN博客 而编著的。 FPGA是一种可编程的逻辑器件,用于各种数字电

    2024年04月14日
    浏览(35)
  • 51单片机UART串口通信实现接收PC的字符串

            基本思路是触发串口接收中断之后,在串口中断服务函数中处理接收到的字节并将其连接成字符串存入全局变量中。 隐含的额外工作有: 1.区分是发送中断还是接收中断,两者都会进入同一个中断服务子函数; 2.判断已接收到了句末,暂停接收,并通过标志位告知

    2023年04月20日
    浏览(96)
  • 【FPGA】FPGA实现UART串口通信回环

    关于UART协议的基础理论部分已经在上一篇文章中讲述,不再重复介绍。 UART通信协议 本文主要介绍如何使用Verlilog编程,通过FPGA实现UART串口通信回环工程。在本工程中所使用的系统时钟为50MHz,如果选择115200的波特率进行数据传输,那么传输1bit所用的时钟周期数就是50_000_

    2024年02月05日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包