当前位置:网站首页>【FPGA】day15-串口协议uart回环工程

【FPGA】day15-串口协议uart回环工程

2022-06-10 01:15:00 春风浅作序

一、项目概述

1、实验要求

在这里插入图片描述

2、串行通信基础

串口通信概念
在这里插入图片描述

串口通信方式
在这里插入图片描述

串行通信的传输方向
在这里插入图片描述

常见的串行通信接口
在这里插入图片描述

3、UART通信原理

UART概念
在这里插入图片描述

通信协议
在这里插入图片描述
LSB:权重最低位
MSB:权重最高位
以1010_1100为例,传输的数据位从左到右依次为0-0-1-1-0-1-0-1

传输速率
在这里插入图片描述

电平标准
在这里插入图片描述

标准逻辑
在这里插入图片描述

4、需求与设计分析

(1)模块草图

在这里插入图片描述

(2)发送端时序图

在这里插入图片描述

(3)接收端时序图

在这里插入图片描述

二、项目实现

1、建立文件体系

在这里插入图片描述

2、顶层模块

module uart (
    input                clk    ,
    input                rst_n  ,
    input                rx     ,   //接收——串行数据(上位机)

    output               tx         //发送——串行数据(FPGA内部)
);

//信号定义
    wire      [7:0]      dout     ;
    wire                 dout_vld ;

uart_rx u_uart_rx(                  //将接收到的串行数据转换成并行数据
    .clk      (clk      )  ,
    .rst_n    (rst_n    )  ,
    .rx       (rx       )  ,        //串行数据

    .dout     (dout     )  ,        //并行数据
    .dout_vld (dout_vld )
);

uart_tx u_uart_tx(                  //将要发送的并行数据转换成串行数据传输
    .clk      (clk      )  ,
    .rst_n    (rst_n    )  ,
    .din      (dout     )  ,
    .din_vld  (dout_vld )  ,

    .tx       (tx       )           //串行数据
)
    
endmodule

3、发送模块

module uart_tx (
    input                 clk     ,
    input                 rst_n   ,
    input      [7:0]      din     ,
    input                 din_vld ,

    output     reg        tx
);

//参数定义
    parameter BPS_115200 = 433  ;   //1bit数据传输所需的时钟周期

//信号定义
    reg      [9:0]    data        ; //锁存din_vld时的有效输出

    reg               flag        ;

    reg      [8:0]    cnt_bps     ;
    wire              add_cnt_bps ;
    wire              end_cnt_bps ;

    reg      [3:0]    cnt_bit     ;
    wire              add_cnt_bit ;
    wire              end_cnt_bit ;

//数据锁存
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            data <= 1'b0;
        end
        else if(din_vld)begin
            data <= {
    1'b1,din,1'b0};   //锁存数据 停止位,数据,起始位
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            tx <= 1'b1;
        end
        else if(flag || din_vld)begin  //发送数据
            tx <= data[cnt_bit];
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            flag <= 1'b0;
        end
        else if(din_vld)begin         //开启计数器
            flag <= 1'b1;
        end
        else if(end_cnt_bit) begin
            flag <= 1'b0;
        end
    end

//波特率计数器,计数每bit数据传输时间
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_bps <= 1'd0;
        end
        else if(add_cnt_bps)begin
            if(end_cnt_bps)begin
                cnt_bps <= 1'd0;
            end
            else begin
                cnt_bps <= cnt_bps + 1'd1;
            end
        end
    end
    assign add_cnt_bps = flag;
    assign end_cnt_bps = add_cnt_bps && cnt_bps == BPS_115200 - 1 ;

//所需传输的比特数
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_bit <= 1'd0;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 1'd0;
            end
            else begin
                cnt_bit <= cnt_bit + 1'd1;
            end
        end
    end
    assign add_cnt_bit = end_cnt_bps;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == 10 - 1 ;


    
endmodule

4、接收模块

module uart_rx (                      //将接收到的串行数据转化成并行数据
    input                clk      ,
    input                rst_n    ,
    input                rx       ,   //串行数据

    output  reg  [7:0]   dout     ,   //并行数据
    output  reg          dout_vld     //输出数据有效信号
);

//参数定义
    parameter BPS_115200 = 434 ;    //1bit数据传输所需要的时钟周期

//信号定义
    reg             rx_r0       ;
    reg             rx_r1       ;
    reg             rx_r2       ;

    wire            nedge       ;
 
    reg             flag        ;   //接收数据标志
    reg     [9:0]   data_r      ;   //数据接收缓存

    reg     [8:0]   cnt_bps     ;
    wire            add_cnt_bps ;
    wire            end_cnt_bps ;

    reg     [3:0]   cnt_bit     ;
    wire            add_cnt_bit ;
    wire            end_cnt_bit ;

//数据同步 
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            rx_r0 <= 1'b1;
        end
        else begin
            rx_r0 <= rx  ;
        end
    end

//数据打拍
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            rx_r1 <= 1'b1;
            rx_r2 <= 1'b1;
        end
        else begin
            rx_r1 <= rx_r0;
            rx_r2 <= rx_r1;
        end
    end

    assign nedge = rx_r2 & ~rx_r1 ;   //下降沿检测

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            flag <= 1'b0;
        end
        else if(nedge)begin
            flag <= 1'b1;
        end
        else if(end_cnt_bit) begin
            flag <= 1'b0;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_bps <= 1'd0;
        end
        else if(add_cnt_bps)begin
            if(end_cnt_bps)begin
                cnt_bps <= 1'd0;
            end
            else begin
                cnt_bps <= cnt_bps + 1'd1;
            end
        end
    end
    assign add_cnt_bps = flag;
    assign end_cnt_bps = add_cnt_bps && cnt_bps == BPS_115200 - 1 ;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_bit <= 1'd0;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 1'd0;
            end
            else begin
                cnt_bit <= cnt_bit + 1'd1;
            end
        end
    end
    assign add_cnt_bit = end_cnt_bps;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == 9 ;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            data_r <= 1'b0;
        end
        else if(cnt_bps == (BPS_115200 >> 1))begin   //数据采样
            data_r[cnt_bit] <= rx_r2 ;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            dout <= 1'b0;
        end
        else if(end_cnt_bit)begin     //截取数据位
            dout <= data_r[8:1];
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            dout_vld <= 1'b0;
        end
        else if(end_cnt_bit)begin    //给发送模块锁存数据产生数据有效信号
            dout_vld <= 1'b1;
        end
        else begin
            dout_vld <= 1'b0;
        end
    end

    
    
endmodule

三、功能仿真

1、发送端uart_tx仿真

(1)仿真代码

`timescale 1ns/1ps

module uart_tx_tb ();
    
    reg                clk      ;
    reg                rst_n    ;
    reg       [7:0]    din      ;
    reg                din_vld  ;

    wire               tx       ;

//参数定义
    parameter CYCLE = 20   ;

    uart_tx u_uart_tx(                 
    .clk      (clk      )  ,
    .rst_n    (rst_n    )  ,
    .din      (din      )  ,
    .din_vld  (din_vld  )  ,

    .tx       (tx       )           
);

    always #(CYCLE/2) clk = ~clk ;

    initial begin
        clk   = 1'b1 ;
        rst_n = 1'b1 ;
        #(CYCLE*5);
        rst_n = 1'b0 ;
        din   = 0    ;
        din_vld = 0  ;
        #(CYCLE*5);
        rst_n = 1'b1 ;
        #2;

        repeat(3)begin
        #(CYCLE*10);
        din = {
    $random};
        din_vld = 1'b1 ;
        #(CYCLE*1);
        din_vld = 1'b0 ;

        #(CYCLE*5000);
        end

        //Send(8'b1010_1100);
        //Send(8'hfa);

        $stop;

    end

    /*task Send; input [7:0] send_data ; begin #(CYCLE*10); din = send_data ; din_vld = 1'b1 ; #(CYCLE*1); din_vld = 1'b0 ; #(CYCLE*5000); end endtask*/
    
endmodule

(2)仿真波形

在这里插入图片描述

2、顶层仿真

(1)仿真代码

实例化uart_tx一次,将其作为外部的输出端。

`timescale 1ns/1ps

module uart_tb ();
    
    reg                clk      ;
    reg                rst_n    ;
    reg       [7:0]    din      ;
    reg                din_vld  ;
    
    wire               rx_r       ;
    wire               tx       ;

//参数定义
    parameter CYCLE = 20   ;

    uart_tx u_uart_tx(                 
    .clk      (clk      )  ,
    .rst_n    (rst_n    )  ,
    .din      (din      )  ,
    .din_vld  (din_vld  )  ,

    .tx       (rx_r     )           
);
    uart u_uart(
    .clk      (clk      )  ,
    .rst_n    (rst_n    )  ,
    .rx       (rx_r     )  ,   //接收——串行数据(上位机)

    .tx       (tx       )      //发送——串行数据(FPGA内部)
);

    always #(CYCLE/2) clk = ~clk ;

    initial begin
        clk   = 1'b1 ;
        rst_n = 1'b1 ;
        #(CYCLE*5);
        rst_n = 1'b0 ;
        din   = 0    ;
        din_vld = 0  ;
        #(CYCLE*5);
        rst_n = 1'b1 ;
        #2;

        repeat(3)begin
        #(CYCLE*10);
        din = {
    $random};
        din_vld = 1'b1 ;
        #(CYCLE*1);
        din_vld = 1'b0 ;

        #(CYCLE*5000);
        end

        //Send(8'b1010_1100);
        //Send(8'hfa);

        $stop;

    end

    /*task Send; input [7:0] send_data ; begin #(CYCLE*10); din = send_data ; din_vld = 1'b1 ; #(CYCLE*1); din_vld = 1'b0 ; #(CYCLE*5000); end endtask*/
    
endmodule

(2)仿真波形

在这里插入图片描述

原网站

版权声明
本文为[春风浅作序]所创,转载请带上原文链接,感谢
https://blog.csdn.net/lzh1415926/article/details/125075182

随机推荐