[FPGA入门笔记](十一):UART串口通信实验

简介

今天购买了AXLINX AX7020的开发板,从今天开始每一个例程都要做文档记录,为自己加油。
本实验,基于ALINX AX7020开发板,芯片为xc7z020clg400-2。开发板输入时钟为50MHz。

1.UART协议介绍

UART是一种通用串行数据总线,用于异步通信。UART能实现双向通信,在嵌入式设计中,常用于主机与辅助设备通信。UART包括RS232、RS449、RS423等接口标准规范和总线标准规范,即UART是异步串行通信口的总称。而RS232等式对应各种异步串行通信口的接口标准和总线标准,它们规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。实际上是属于通信网络中的物理层(最底层)的概念,与通信协议并没有关系。

UART传输中,相关名词解释如下:
(1)波特率:每秒钟发送的符号数
(2)起始位:先发出一个逻辑0的信号,表示传输数据的开始
(3)数据位:衡量通信中实际数据位的参数。标准的数据位可以是5、7、8位,从最低位开始传输
(4)奇偶校验位:UART发送时,检查发送数据中1的个数,自动在奇偶校验位上添上1或0,用于发送数据的校验
数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。就比如传输“A”(01000001)为例:
当为奇数校验:“A”字符的8个bit位中有两个1,那么奇偶校验位为1才能满足1的个数为奇数(奇校验);
当为偶数校验:“A”字符的8个bit位中有两个1,那么奇偶校验位为0才能满足1的个数为偶数(偶校验);

(5)停止位:数据结束的标志,可以是1位、1.5位、2位的高电平
(6)空闲位:处于逻辑1的状态,表示当前线路上无数据传输

2.UART传输时序

在这里插入图片描述
**发送数据过程:**空闲状态,线路处于高电平,当收到发送数据指令后,拉低电平一个数据位的时间,接着数据按低位到高位依次发送,数据位发送完毕,接着发送奇偶校验位和停止位,停止位为高电平,一帧数据发送结束;
**接收数据过程:**空闲状态,线路处于高电平,当检测到线路的下降沿,说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后接着接收奇偶校验位并比较,看奇偶校验位是否正确,如果正确则通知接收端设备准备接收数据;

2.UART工程设计

在这里插入图片描述
UART_TOP模块中共包含三个子模块:
1、Baud_Clock模块用来产生115200的波特率时钟;
2、RX模块为接收(receive)模块,输入信号rx_pin为接收的序列数据,rx_ready为接收端的反压信号,只有当ready信号为高时才会输出rx_data数据,rx_valid用来表明什么时候rx_data有效。rx_erro输出接收的rx_pin序列的奇偶校验是否正确,0表示正确,1表示错误,若检验到错误,会要求发送端重发。
3、TX模块为发送(transmission)模块,输入信号为tx_data并行信号,tx_valid表示tx_data的有效性,tx_ready表示当前发送模块是否空闲;tx_pin为输出的串行数据,tx_erro为检错重发信号,当受到erro=1时就把ready=1拉高,重新发送上一次的数据;

3.RX模块(receive)

在这里插入图片描述

`timescale 1ns/1ps
module rx_control(
    input           clk,//50MHz
    input           rst_n,
    input           baud_clk,

    input           rx_pin,
    output          rx_erro,

    input           rx_ready,
    output          rx_valid,
    output  [6:0]   rx_data
    );

    parameter  IDLE = 4'b0001, RECEIVE = 4'b0010, 
               END  = 4'b0100, ERRO    = 4'b1000;
    
    reg     [3:0]   state_curt; //current state
    reg     [3:0]   state_next; //next state
    reg     [3:0]   count;
    reg     [7:0]   data;

    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            state_curt <= IDLE;
    end
    always@(posedge baud_clk)
    begin
            state_curt <= state_next;
    end

    always@(*)
    begin
        case(state_curt)
            IDLE:
                if(rx_pin==0)
                    state_next <= RECEIVE;
            RECEIVE:
                if(count==7)
                begin
                    if((^data)==0)
                        state_next <= END;
                    else
                        state_next <= ERRO;
                end
                else
                    state_next <= state_next;
            END:
                if(rx_ready)
                    state_next <= IDLE;
                else
                    state_next <= END;
            ERRO:
                state_next <= IDLE;
            default :
                state_next <= IDLE;
        endcase
    end

    always@(posedge baud_clk)
    begin
        if(state_curt==RECEIVE)
            count <= count +1'b1;
        else
            count <= 32'd0;
    end
    
    always@(posedge baud_clk)
    begin
        if(state_curt==RECEIVE)
        begin
            data[7]   <= rx_pin;
            data[6:0] <= data[7:1];
        end
        else 
        begin
            if(state_curt==END | state_curt==ERRO)
                data <= data;
            else
                data <= 8'b0;
        end
    end
    
    assign rx_erro = (state_curt == ERRO)? 1'b1:1'b0;
    assign rx_data = (state_curt == END )? data[6:0]:7'b0;
    assign rx_valid= (state_curt == END )? 1'b1:1'b0;
    
endmodule

4.TX模块(transmission)

在这里插入图片描述

`timescale 1ns/1ps
module tx_control(
    input           clk,
    input           rst_n,
    input           baud_clk,
    
    input           tx_erro,
    output  reg     tx_pin,

    input           tx_valid,
    input   [6:0]   tx_data,
    output          tx_ready
    );

    parameter   IDLE = 4'b0001, START = 4'b0010,
                SEND = 4'b0100, END   = 4'b1000;

    reg     [3:0]   state_curt;
    reg     [3:0]   state_next;

    reg     [7:0]   data;
    reg     [7:0]   r_data;
    reg     [3:0]   count;

    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            state_curt <= IDLE;
    end
    always@(posedge baud_clk)
    begin
        state_curt <= state_next;
    end

    always@(*)
    begin
        case(state_curt)
            IDLE:
                if((tx_valid==1'b1)&(tx_erro==1'b0))
                    begin
                    state_next <= START;
                    r_data     <= tx_data;
                    end
                else
                    state_next <= IDLE;
            START:
                state_next <= SEND;
            SEND:
                if(count==3'd7)
                    state_next <= END;
                else
                    state_next <= SEND;
            END:
                if((tx_valid==1'b1)&(tx_erro==1'b0))
                    begin
                    state_next <= START;
                    r_data     <= tx_data;
                    end
                else
                    state_next <= IDLE;
            default:
                state_next <= IDLE;
        endcase
    end

    always@(posedge baud_clk)
    begin
        if(state_curt==SEND)
            count <= count + 1'b1;
        else
            count <= 4'b0;
    end

    assign tx_ready = ((state_curt==IDLE)|(state_curt==END))? 1'b1:1'b0;

    always@(posedge baud_clk)
    begin
        if(state_next==START)
            begin
                tx_pin    <= 1'b0;
                data[6:0] <= r_data;
                data[7]   <= ^r_data;
            end
        else
        begin
            if(state_next==SEND) 
                begin
                    tx_pin <= data[0];
                    data[6:0] <= data[7:1];
                end
            else
                tx_pin <= 1'b1;
        end
    end

endmodule


5.Baud_Clock模块

`timescale 1ns/1ps
module baud_clock(
    input   clk,
    input   rst_n,
    output  baud_clk
    );
    
    parameter   CLK_FRE   = 32'd50;
    parameter   BAUD_RATE = 32'd115200;//波特率:1s传输的二进制码元个数
    parameter   CNT_NUM   = CLK_FRE * 1000_000 / BAUD_RATE;
    
    reg     [31:0]  count;
    reg             b_clk;
    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            count <= 32'd0;
            b_clk <= 0;
        end
        else 
        begin
            if(count == CNT_NUM-1)
                begin
                    count <= 32'd0;
                    b_clk <= 1;
                end
            else
                begin
                    count <= count + 32'd1;
                    b_clk <= 0;
                end
        end
    end
    assign baud_clk = b_clk;

endmodule
  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值