uart串口环回(加FIFO)

一.uart简介

  • UART(universal asynchronous receiver-transmitter)是一种采用异步串行通信方式的通用异步收发传输器。
  • 定义如上,那么出现问题了,什么叫异步串行通信?请关注下文原理。

二.原理

1.同步通信&&异步通信

1.1同步通信

  • 发送方发送出数据后,等接收方响应后才发送下一个数据

1.2异步通信

  • 发送方发出数据后,不等接收方发回相应,接着发送下一个数据

2.并行通信&&串行通信

2.1并行通信

  • 并行通信是指数据各个位用多条数据线同时进行传输
    在这里插入图片描述

2.2串行通信

  • 串行通信是将数据分成一位一位的形式在一条线上逐个传输
    在这里插入图片描述

3.全双工&&半双工

3.1全双工

  • 双方都可以发送接收数据,并可以同时进行
    在这里插入图片描述

3.2半双工

  • 双方都可以发送接收数据,但是同一时刻只能一方发送,一方接收
    在这里插入图片描述

4.协议层

4.1数据格式

在这里插入图片描述

  • 解析上图可以看出:空闲位处于高电平,起始位为0(拉低);数据位可以是6-8bit,注意是低位先发;暂时不考虑校验位,停止位为1(拉高)。

4.2传输速率

  • 串口通信的速率用波特率表示,它表示每秒传输二进制数据的位数,单位是bit/s(位/秒),简称bps。常用的波特率有9600、19200、38400、57600、115200等。本文中设计用的115200的波特率==>传输1bit需要计数50_000_000/115200 = 434次

二.初步设计

1.模块图

在这里插入图片描述

2.tx设计

在这里插入图片描述

  • tx将8bit的数据转换为1bit数据输出

3.rx设计

在这里插入图片描述

  • rx将1bit的数据转换为8bit数据输出
  • 这里由于加入stop状态后面会导致状态跳崩了,于是我不要stop状态了

4.加入FIFO

三.代码

1.uart_tx

/**************************************功能介绍***********************************
Date	: 2023年8月16日17:07:11
Author	: Alegg xy.
Version	: 2.0
Description: FPGA向上位机发送数据【8bit变1bit(波形)】
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module uart_tx( 
    input				clk		,
    input				rst_n	,
    input       [7:0]   tx_data ,
    input               tx_data_vld,
    output              ready   ,
    output  reg         tx              
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter   MAX_1bit = 9'd434;//1bit要计434次
    //状态机参数定义
    localparam  IDLE   = 'b0001,//空闲状态
                START  = 'b0010,//起始位
                DATA   = 'b0100,//数据位
                STOP   = 'b1000;//停止位
//---------<内部信号定义>-----------------------------------------------------    
    reg 	[3:0]	cstate     ;//现态
    reg	    [3:0]	nstate     ;//次态
    
    wire    IDLE_START;
    wire    START_DATA;
    wire    DATA_CHECK;
    wire    CHECK_STOP;
    wire    STOP_IDLE;

    reg			[8:0]	cnt_baud	   	;//波特计数器,波特率115200
    wire				add_cnt_baud	;
    wire				end_cnt_baud	;

    reg			[2:0]	cnt_bit	   	;//bit计数器,起始位1bit,数据位8bit,结束位1bit
    wire				add_cnt_bit	;
    wire				end_cnt_bit	;
    
    reg         [3:0]   bit_max;//bit最大值,复用需要考察每个状态的bit值
    reg         [7:0]   tx_data_r;
    
    //计434次
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_baud <= 'd0;
        end 
        else if(add_cnt_baud)begin 
            if(end_cnt_baud)begin 
                cnt_baud <= 'd0;
            end
            else begin 
                cnt_baud <= cnt_baud + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_baud = cstate != IDLE;
    assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
    
    //bit计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_bit <= 'd0;
        end 
        else if(add_cnt_bit)begin 
            if(end_cnt_bit)begin 
                cnt_bit <= 'd0;
            end
            else begin 
                cnt_bit <= cnt_bit + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_bit = end_cnt_baud;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
    
    //计数器复用
    always @(*)begin 
        case (cstate)
            IDLE :bit_max = 'd0;
            START:bit_max = 'd1;//起始位1bit
            DATA :bit_max = 'd8;//数据位8bit
            STOP :bit_max = 'd1;//结束位1bit
            default: bit_max = 'd0;
        endcase
    end

    assign IDLE_START = (cstate == IDLE) && tx_data_vld;//考察到开始传输信号
    assign START_DATA = (cstate == START) && end_cnt_bit;//计1bit数据
    assign DATA_STOP = (cstate == DATA) && end_cnt_bit;
    assign STOP_IDLE = (cstate == STOP) && end_cnt_bit;//计1bit数据

    //第一段:时序逻辑描述状态转移
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cstate <= IDLE;
        end 
        else begin 
            cstate <= nstate;
        end 
    end
    
    //第二段:组合逻辑描述状态转移规律和状态转移条件
    always @(*) begin
        case(cstate)
            IDLE  :begin
                if (IDLE_START) begin
                    nstate = START;
                end
                else begin
                    nstate = cstate;
                end
            end
            START :begin
                if (START_DATA) begin
                    nstate = DATA;
                end
                else begin
                    nstate = cstate;
                end
            end
            DATA  :begin
                if (DATA_STOP) begin
                    nstate = STOP;
                end
                else begin
                    nstate = cstate;
                end
            end
            STOP  :begin
                if (STOP_IDLE) begin
                    nstate = IDLE;
                end
                else begin
                    nstate = cstate;
                end
            end
            default : nstate = cstate;
        endcase
    end

    //寄存一拍
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            tx_data_r <= 'd0;
        end
        else if (tx_data_vld) begin
            tx_data_r <= tx_data;
        end
        else begin
            tx_data_r <= tx_data_r;
        end
    end
    

    //第三段:描述输出,时序逻辑或组合逻辑皆可
    always @(*)begin 
        case (cstate)
            IDLE : tx = 1'b1;
            START: tx = 1'b0;//起始位为0
            DATA : tx = tx_data_r[cnt_bit];
            STOP : tx = 1'b1;//结束位为1
            default: tx = 1'b1;
        endcase
    end            
                
    assign ready = cstate == IDLE;//当状态为IDLE时,表示tx端可以接收数据
    
    
    
endmodule

2.uart_rx

/**************************************功能介绍***********************************
Date	: 2023年8月16日18:25:03 
Author	: Alegg xy.
Version	: 1.0
Description: FPGA收上位机发来的数据【1bit(波形)变8bit】
*********************************************************************************/

//---------<模块及端口声名>------------------------------------------------------
module uart_rx( 
    input				clk		,
    input				rst_n	,
    input               rx      ,
    output              rx_data_vld,
    output  reg [7:0]   rx_data            
);								 
//---------<参数定义>--------------------------------------------------------- 
    parameter   MAX_1bit = 9'd434;//1bit要计434次
    //状态机参数定义
    localparam  IDLE   = 'b001,//空闲状态
                START  = 'b010,//起始位
                DATA   = 'b100;//数据位

//---------<内部信号定义>-----------------------------------------------------    
    reg 	[2:0]	cstate     ;//现态
    reg	    [2:0]	nstate     ;//次态
    
    wire    IDLE_START;
    wire    START_DATA;
    wire    DATA_IDLE;

    reg			[8:0]	cnt_baud	   	;//波特计数器,波特率115200
    wire				add_cnt_baud	;
    wire				end_cnt_baud	;

    reg			[2:0]	cnt_bit	   	;//bit计数器,起始位1bit,数据位8bit,结束位1bit
    wire				add_cnt_bit	;
    wire				end_cnt_bit	;
    
    reg         [3:0]   bit_max;//bit最大值,复用需要考察每个状态的bit值

    //计434次
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_baud <= 'd0;
        end 
        else if(add_cnt_baud)begin 
            if(end_cnt_baud)begin 
                cnt_baud <= 'd0;
            end
            else begin 
                cnt_baud <= cnt_baud + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_baud = cstate != IDLE;
    assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
    
    //bit计数器
    always @(posedge clk or negedge rst_n)begin 
       if(!rst_n)begin
            cnt_bit <= 'd0;
        end 
        else if(add_cnt_bit)begin 
            if(end_cnt_bit)begin 
                cnt_bit <= 'd0;
            end
            else begin 
                cnt_bit <= cnt_bit + 1'd1;
            end 
        end
    end 
    
    assign add_cnt_bit = end_cnt_baud;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
    
    //计数器复用
    always @(*)begin 
        case (cstate)
            IDLE :bit_max = 'd0;
            START:bit_max = 'd1;//起始位1bit
            DATA :bit_max = 'd8;//数据位8bit
            default: bit_max = 'd0;
        endcase
    end

    assign IDLE_START = (cstate == IDLE) && rx == 0;//识别到起始位0
    assign START_DATA = (cstate == START) && end_cnt_bit;//计1bit数据
    assign DATA_IDLE = (cstate == DATA) && end_cnt_bit;//计8bit数据

    //第一段:时序逻辑描述状态转移
    always @(posedge clk or negedge rst_n)begin 
        if(!rst_n)begin
            cstate <= IDLE;
        end 
        else begin 
            cstate <= nstate;
        end 
    end
    
    //第二段:组合逻辑描述状态转移规律和状态转移条件
    always @(*) begin
        case(cstate)
            IDLE  :begin
                if (IDLE_START) begin
                    nstate = START;
                end
                else begin
                    nstate = cstate;
                end
            end
            START :begin
                if (START_DATA) begin
                    nstate = DATA;
                end
                else begin
                    nstate = cstate;
                end
            end
            DATA  :begin
                if (DATA_IDLE) begin
                    nstate = IDLE;
                end
                else begin
                    nstate = cstate;
                end
            end
            default : nstate = IDLE;
        endcase
    end

    //第三段:描述输出,时序逻辑或组合逻辑皆可
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            rx_data <= 0;
        end
        else if (cstate == DATA && cnt_baud == MAX_1bit >> 1) begin//电平中间值采样,边沿采样容易出错
            rx_data[cnt_bit] <= rx;
        end
        else begin
            rx_data <= rx_data;
        end
    end

    assign rx_data_vld = DATA_IDLE;//开始传输数据信号为计满数据位
    
    
endmodule

3.ctrl(FIFO)

/**************************************功能介绍***********************************
Date	: 2023年8月16日18:43:33
Author	: Alegg xy.
Version	: 1.0
Description: 调用FIFO
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module ctrl( 
    input				clk		,
    input				rst_n	,
    input       [7:0]   rx_data ,
    input               rx_data_vld,
    input               ready   ,
    output              tx_data_vld,
    output      [7:0]   tx_data
);								 
//---------<参数定义>--------------------------------------------------------- 
    wire    fifo_rdempty;//FIFO读空信号
    wire    fifo_wrfull;//FIFO写满信号
//---------<内部信号定义>-----------------------------------------------------
    fifo	fifo_inst (
	    .aclr ( ~rst_n ),
	    .data ( rx_data ),
	    .rdclk ( clk ),
	    .rdreq ( ready && ~fifo_rdempty ),
	    .wrclk ( clk ),
	    .wrreq ( rx_data_vld && ~fifo_wrfull ),
	    .q ( tx_data ),
	    .rdempty ( fifo_rdempty ),
	    .wrfull ( fifo_wrfulll )
	);
    
    assign tx_data_vld = ready && ~fifo_rdempty;
    
    
endmodule

4.top

/**************************************功能介绍***********************************
Date	: 2023年8月16日18:51:42 
Author	: Alegg xy.
Version	: 1.0
Description: 顶层模块
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module top( 
    input				clk		,
    input				rst_n	,
    input				rx		,
    output              tx
);								 
//---------<参数定义>--------------------------------------------------------- 
    wire    [7:0]   tx_data;
    wire            tx_data_vld;

    wire    [7:0]   rx_data;
    wire            rx_data_vld;

    wire            ready;
//---------<内部信号定义>-----------------------------------------------------
    uart_tx u_uart_tx( 
        .clk		(clk),
        .rst_n	    (rst_n),
        .tx_data    (tx_data),
        .tx_data_vld(tx_data_vld),
        .ready      (ready),
        .tx         (tx)        
    );
    
    uart_rx u_uart_rx( 
        .clk		(clk),
        .rst_n	    (rst_n),
        .rx         (rx),
        .rx_data_vld(rx_data_vld),
        .rx_data    (rx_data)        
    );

    ctrl u_ctrl( 
        .clk		(clk),
        .rst_n	    (rst_n),
        .rx_data    (rx_data),
        .rx_data_vld(rx_data_vld),
        .ready      (ready),
        .tx_data_vld(tx_data_vld),
        .tx_data    (tx_data)
    );
    
    
endmodule

四.效果

在这里插入图片描述

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值