UART协议的FPGA实现(线性序列机)

实现uart其实早就写了,不过不太完善,对于一个完美主义者来说,必须解决掉它。

1.什么是UART?

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。是异步通信协议。

2.什么是RS232?

RS232是物理层的电气接口要求。是一种接口标准。uart可以使用rs232物理层来通信。总的来说,对于一项通信任务,通信协议可以使用UART协议,而UART协议可以通过COM端口来实现硬件连线,此协议下的传输方式可以选用RS232或者RS485等。

开发板上的是:

UART实现方式:状态机或者线性序列机。

3.什么叫线性序列机?

当知晓信号在每个时刻的改变情况,那么就可以用计数器去拟合信号变化,比如在cnt=5的时候信号变1了,cnt=8的时候信号变0;当然这是可以自定义的。

简单的测试逻辑(回环测试):

以下通过线性序列机实现:

首先看看uart协议的数据格式:信号线上空闲的时候为高电平,当出现下跳到低电平的时候表示数据的起始位,接着的是低位在前高位在后的数据流,尾部可加奇偶校验位,最后加停止位,停止位长度可以定义。

编码实现:

波特率产生,波特率选择。波特率模块塞tx以及rx模块中了。rx中的采样时钟bps要快16倍。

什么叫波特率?

9600bps/s:表示1s信号可以传输9600bit的数据。

波特率与FPGA时钟关系:

总计数等于系统频率除以波特率。比如50m/9600=5208;

rtl图:

回环测试综合资源使用情况以及糟糕条件下的Fmax:

通过串口助手测试:

测试ok。

代码:

//************************************************
//  Filename      : uart_tx.v
//  Author        : kingstacker
//  Company       : School
//  Email         : [email protected]
//  Device        : Altera cyclone4 ep4ce6f17c8
//  Description   :
//************************************************
module  uart_tx (
/*i*/   input    wire             clk            ,
        input    wire             rst_n          ,
        input    wire             send_en        ,
        input    wire    [2:0]    bps_set        ,
        input    wire    [7:0]    data_i         ,
/*o*/   output   wire             tx             ,
        output   wire             tx_done
);
reg send_en_reg0;
reg send_en_reg1;
reg [7:0] data_i_reg;
reg bps_clk;
reg bps_en;
reg [12:0] bps;
reg [12:0] bps_cnt;
reg [3:0] cnt;
reg tx_done_reg;
reg tx_reg;
//bps select;
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps <= 13‘d5207; //324
    end //if
    else begin
        case (bps_set)
                3‘d0:    bps <= 13‘d5207;
                3‘d1:    bps <= 13‘d2603;
                3‘d2:    bps <= 13‘d1301 ;
                3‘d3:    bps <= 13‘d867 ;
                3‘d4:    bps <= 13‘d433 ;
                default: bps <= 13‘d5207;
            endcase //case
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_cnt;
    if (~rst_n) begin
        bps_cnt <= 0;
    end //if
    else begin
        if (bps_en == 1‘b1) begin
            bps_cnt <= (bps_cnt == bps) ? 13‘d0 : bps_cnt + 1‘b1;
        end
        else begin
            bps_cnt <= 0;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_clk;
    if (~rst_n) begin
        bps_clk <= 0;
    end //if
    else begin
        if (bps_cnt == 13‘d1) begin
            bps_clk <= 1‘b1;
        end
        else begin
            bps_clk <= 1‘b0;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //send_en syn;
    if (~rst_n) begin
        send_en_reg0 <= 0;
        send_en_reg1 <= 0;
    end //if
    else begin
        send_en_reg0 <= send_en;
        send_en_reg1 <= send_en_reg0;
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //data refresh;
    if (~rst_n) begin
        data_i_reg <= 0;
    end //if
    else begin
        data_i_reg <= (send_en_reg1) ? data_i : data_i_reg;
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps_en <= 1‘b0;
    end //if
    else begin
        if (send_en_reg1 == 1‘b1) begin
            bps_en <= 1‘b1;
        end
        else begin
            bps_en <= (cnt == 4‘d10) ? 1‘b0 : bps_en;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        cnt <= 0;
    end //if
    else begin
        if (cnt == 4‘d10) begin
            cnt <= 0;
        end
        else begin
            cnt <= (bps_clk == 1‘b1) ? cnt + 1‘b1 : cnt;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        tx_done_reg <= 1‘b0;
        tx_reg <= 1‘b1;
    end //if
    else begin
        case (cnt)
                0 : begin tx_done_reg <= 1‘b0;tx_reg <= 1‘b1; end
                1 : begin tx_reg <= 1‘b0; end
                2 : begin tx_reg <= data_i_reg[0]; end
                3 : begin tx_reg <= data_i_reg[1]; end
                4 : begin tx_reg <= data_i_reg[2]; end
                5 : begin tx_reg <= data_i_reg[3]; end
                6 : begin tx_reg <= data_i_reg[4]; end
                7 : begin tx_reg <= data_i_reg[5]; end
                8 : begin tx_reg <= data_i_reg[6]; end
                9 : begin tx_reg <= data_i_reg[7]; end
                10: begin tx_done_reg <= 1‘b1;tx_reg <= 1‘b1; end
                default:  begin tx_done_reg <= 1‘b0;tx_reg <= 1‘b1; end
            endcase //case
    end //else
end //always
assign tx_done = tx_done_reg;
assign tx = tx_reg;

endmodule
//************************************************
//  Filename      : uart_rx.v
//  Author        : kingstacker
//  Company       : School
//  Email         : [email protected]
//  Device        : Altera cyclone4 ep4ce6f17c8
//  Description   : uart rx;
//************************************************
module  uart_rx (
/*i*/   input    wire             clk                  ,
        input    wire             rst_n                ,
        input    wire    [2:0]    bps_set              ,
        input    wire             rx                   ,
/*o*/   output   wire    [7:0]    data_o               ,
        output   wire             rx_done
);
reg  rx_reg0;
reg  rx_reg1;
reg  rx_temp0;
reg  rx_temp1;
reg  bps_clk;
reg  bps_en;
wire rx_neg;
reg [8:0] bps;
reg [8:0] bps_cnt;
reg [7:0] cnt;
reg rx_done_reg;
reg [7:0] data_o_reg;
reg [7:0] data_o_reg1;
always @(posedge clk or negedge rst_n) begin //syn rx;
    if (~rst_n) begin
        rx_reg0 <= 0;
        rx_reg1 <= 0;
    end //if
    else begin
        rx_reg0 <= rx;
        rx_reg1 <= rx_reg0;
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //neg;
    if (~rst_n) begin
        rx_temp0 <= 0;
        rx_temp1 <= 0;
    end //if
    else begin
        rx_temp0 <= rx_reg1;
        rx_temp1 <= rx_temp0;
    end //else
end //always
assign rx_neg = (~rx_temp0)&&rx_temp1;
//bps select;
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps <= 9‘d324; //324
    end //if
    else begin
        case (bps_set)
                3‘d0:    bps <= 9‘d324;
                3‘d1:    bps <= 9‘d162;
                3‘d2:    bps <= 9‘d80 ;
                3‘d3:    bps <= 9‘d53 ;
                3‘d4:    bps <= 9‘d26 ;
                default: bps <= 9‘d324;
            endcase //case
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_cnt;
    if (~rst_n) begin
        bps_cnt <= 0;
    end //if
    else begin
        if (bps_en == 1‘b1) begin
            bps_cnt <= (bps_cnt == bps) ? 9‘d0 : bps_cnt + 1‘b1;
        end
        else begin
            bps_cnt <= 0;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //bps_clk;
    if (~rst_n) begin
        bps_clk <= 0;
    end //if
    else begin
        if (bps_cnt == 9‘d1) begin
            bps_clk <= 1‘b1;
        end
        else begin
            bps_clk <= 1‘b0;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin //cnt;
    if (~rst_n) begin
        cnt <= 0;
    end //if
    else begin
        if (bps_en == 1‘b1) begin
            cnt <= (bps_clk == 1‘b1) ? cnt + 1‘b1 : cnt;
        end
        else begin
            cnt <= 0;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        bps_en <= 0;
    end //if
    else begin
        if (rx_neg == 1‘b1) begin
            bps_en <= 1‘b1;
        end
        else begin
            bps_en <= (cnt == 8‘d159 || (cnt == 8‘d7 && (rx_reg1))) ? 1‘b0 : bps_en;
        end
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        rx_done_reg <= 1‘b0;
        data_o_reg  <= 0;
    end //if
    else begin
        case (cnt)
            0  : begin rx_done_reg   <= 1‘b0; end
            23 : begin data_o_reg[0] <= rx_reg1; end
              39 : begin data_o_reg[1] <= rx_reg1; end
              55 : begin data_o_reg[2] <= rx_reg1; end
              71 : begin data_o_reg[3] <= rx_reg1; end
              87 : begin data_o_reg[4] <= rx_reg1; end
              103: begin data_o_reg[5] <= rx_reg1; end
              119: begin data_o_reg[6] <= rx_reg1; end
              135: begin data_o_reg[7] <= rx_reg1; end
              159: begin rx_done_reg   <= 1‘b1; end
              default: ;
        endcase //case
    end //else
end //always
always @(posedge clk or negedge rst_n) begin
    if (~rst_n) begin
        data_o_reg1 <= 0;
    end //if
    else begin
        data_o_reg1 <= (cnt == 8‘d159) ? data_o_reg : data_o_reg1;
    end //else
end //always
assign rx_done = rx_done_reg;
assign data_o  = data_o_reg1;

endmodule

top.v就不贴了,

工程完整源代码可在码云中查看和下载:https://gitee.com/kingstacker/uart

以上。

时间: 2024-08-28 20:00:12

UART协议的FPGA实现(线性序列机)的相关文章

UART协议

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,通常称作UART,读音/?ju?art/)是一种异步收发传输器,是电脑硬件的一部分,将资料由串行通信与并行通信间作传输转换.一般和类似Maxim的MAX232之类的标准信号幅度变换芯片进行搭配,作为连接外部设备的接口.在UART上追加同步方式的序列信号变换电路的产品,被称为USART(Universal Synchronous Asynchronous Receiver Transmitt

SATA主机协议的FPGA实现1

从2月中旬准备开始,经过3个月的奋战,我的又一个项目--基于FPGA的固态硬盘读写控制电路,已经基本实现.由于实用资料的匮乏,以及项目本身颇具挑战性,这个过程充满艰辛,这里也是希望写下一些经验,供后来的有心人参考,少走一些弯路.因为这个项目比较大,不是三言两语能说清楚的,可能接下来我会用5至6篇文章来讲这个东西,陆续的码文章也会耗时较久,希望先看到的看官耐心,同时由于完整的SATA协议实在是有点庞大,我的理解也不能尽善尽美,中间有不恰当之处也希望走过路过的指出. 言归正传,这里先普及一下硬盘的两

SATA主机协议的FPGA实现之物理层设计

接上一篇文章,这里讲解SATA主机协议的物理层的实现过程. 下图是标准SATA协议文档中给出的物理层结构.可以看到它包含控制模块.时钟数据提取单元.同步字符源和同步字符检测模块以及模拟前端几个部分.其中,控制模块负责协调控制整个物理层的逻辑功能,并向上层协议提供控制信号.状态信息接口.时钟数据提取模块从串行数据流中提取时钟数据信息.同步字符源和同步字符检测两个模块负责串并/并串转换过程中的字节对齐.模拟前端包含高速差分数据发送接收器和OOB信号检测与生成电路. 上面这个图看上去比较复杂,但是如果

C++线性序列容器&lt;vector&gt;简单总结

C++线性序列容器<vector>简单总结 vector是一个长度可变的数组,使用的时候无须声明上限,随着元素的增加,Vector的长度会自动增加:Vector类提供额外的方法来增加.删除元素,比数组操作高效. 头文件:#include <vector> 命名空间:using namespace std:vector 构造函数 vector<int>vec_int;         // 创建一个整形元素的vector vector<string>vec_s

uart协议及接口

UART使用的是异步.串行通信. 串行通信是指利用一条传输线将资料一位位地顺序传送.特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于远距离通信,但传输速度慢的应用场合. 异步通信以一个字符为传输单位,通信中两个字符间的时间间隔多少是不固定的,然而在同一个字符中的两个相邻位间的时间间隔是固定的. 数据传送速率用波特率来表示,即每秒钟传送的二进制位数.例如数据传送速率为120字符/秒,而每一个字符为10位(1个起始位,7个数据位,1个校验位,1个结束位),则其传送的波特率为10×12

STM32F407-串口学习1(UART协议简介)

一.前言 1.简介 写的这篇博客,是为了学习UART通信协议,以及UART能够实现的一些功能,还有有关使用STM32CubeMX来配置芯片的一些操作,在后面我会以我使用的STM32F407开发板来举例讲解(其他STM32系列芯片大多数都可以按照这些步骤来操作的),如有不足请多多指教. 2.UART简介 嵌入式开发中,UART串口通信协议是我们常用的通信协议(UART.I2C.SPI等)之一,全称叫做通用异步收发传输器(Universal Asynchronous Receiver/Transmi

【小梅哥FPGA进阶教程】第九章 基于串口猎人软件的串口示波器

九.基于串口猎人软件的串口示波器 1.实验介绍 本实验,为芯航线开发板的综合实验,该实验利用芯航线开发板上的ADC.独立按键.UART等外设,搭建了一个具备丰富功能的数据采集卡,芯航线开发板负责进行数据的采集并将数据通过串口发送到PC机上,PC端,利用强大的串口调试工具--串口猎人,来实现数据的接收分析,并将数据分别以波形.码表.柱状图的形式动态显示出来,以让使用者能够直观的看到ADC采集到的信号细节.同时,用户也可以使用串口猎人通过串口给下位机(FPGA)发送指令,下位机将对接收到的指令进行解

FPGA学习笔记(二)——FPGA学习路线及开发流程

###### [该随笔部分内容转载自小梅哥]       ######### 一.FPGA学习路线 工具使用 -> 语法学习 -> 逻辑设计 -> IP使用 ->接口设计 -> 时序分析 -> 片上系统 1.工具使用 Altera:Quartus II Xlinx: Vivado 2.语法学习 Verilog HDL(FPGA设计的是电路) 3. 逻辑设计 组合逻辑:多路选择器.加法器.译码器.乘法器 ······· 时序逻辑:计数器.分频器.移位寄存器.定时器 ···

UART串口协议基础1

Louis [email protected] 串口协议基础 1 串口概述 串口由收发器组成.发送器是通过TxD引脚发送串行数据,接收器是通过RxD引脚接收串行数据.发送器和接收器都利用了一个移位寄存器,这个移位寄存器可以将数据进行"并转串"和"串转并".虽然一个UART接口通常都包含了发送器和接收器,而实际上一个全双工串口UART控制器需要独立的发送和接收通道.这是因为每个控制通道只控制了一个pin(一个通道要么配置成发送器,要么配置成接收器,不能同时配置成接收器