FPGA开发基础篇之一(接口篇)UART串口

这篇具有很好参考价值的文章主要介绍了FPGA开发基础篇之一(接口篇)UART串口。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

从本文开始,将连载fpga开发基础知识,将这几年浅显的fpga开发经验整理出来,一是梳理一下这几年给别人做fpga的经历,同时也是分享给大家,也希望大牛批评指正。

一、UART串口通信基本概念

串口通信是非常基本且应用十分广泛的低速通信接口,无论是在dsp、单片机、arm还是在fpga中,编写uart串口通信程序是必备的基础。

首先要先了解UART串口通信的基本概念,UART串口通信是全双工的,支持发送和接收通信同时进行。硬件上UART串口只需要两条线tx和rx,分别进行发送和接收。UART串口通信没有同步时钟线,这就需要引入一个概念波特率来区分两位数据实现串行通信,波特率是指每秒传输的位数。常见的有9600bps、115200bps、460800bps等等。在fpga实现中,只需要理解每一位的时间长度是1/波特率,计数长度是时钟频率/波特率就可以了。

UART串口通信基本协议,一次UART串口发送和接收一般包含10bit或11bit,包含校验位是11bit,不包含则是10bit。有效数据位一般是8bit。依次为起始位、数据位、校验位(可选)、停止位。

起始位:首先发送的第一位,必须为0,提示接收方开始接收有效数据。

数据位:一般为8位,有效数据位。

校验位:可选位,一般为奇校验、偶校验、固定校验。校验位由数据位中1的个数来决定

停止位:最后发送的一位,必须为1,提示接收方结束接收。

包含以上所有位为一帧数据,经过一个间隔后发送或接收第二帧。由以上的内容我们可以知道如何发送和接收一帧数据了。接下来就是用fpga实现。

二、UART串口通信FPGA实现

首先编写发送模块,先将发送数据缓存,状态机由空闲状态转为发送状态,空闲状态指示信号拉低,通知上层模块发送正在进行不要更新待发送字节。根据波特率进行计数,依次发送一帧数据的所有位,发送完成后状态机转入空闲拉高空闲状态,一次发送就完成了。

//
//                                                                              //
//                                                                              //
// This source file is part of uart module.                                        //
// module features: 1.config bits number of one byte                              //
//                      2.config bitrate                                            //
// module function: transmit uart bits                                            // 
// copyright of this source file belongs to mayidianzi in CSDN blog                //
// contact the author by e-mail 1061165280@qq.com                                //
//                                                                              //
//

//================================================================================
//  Revision History:
//  Date              By                Revision        Change Description
//--------------------------------------------------------------------------------
//    2023/2/26       mayidianzi      1.0              Original
//*******************************************************************************/
module uart_tx
#(
    parameter                                 CLK_FRE            =    50,              //module clock frequency(MHz)
    parameter                                 BAUD_RATE         =    115200,            //serial baud rate
    parameter                                 TRANSMIT_BITS      =    9                //bits number per byte
)
(
    input                                    clk,                  //clock input
    input                                    rst_n,                //asynchronous reset input, low active 
    input[TRANSMIT_BITS-1:0]                tx_data,              //data to send
    input                                    tx_data_valid,        //data to be sent is valid
    output reg                               tx_data_ready,        //send ready
    output                                   tx_pin                //serial data output
);

/ parameter config \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       C_IDLE       = 1;//wait for transmit
localparam                       C_START      = 2;//start bit
localparam                       C_SEND_BYTE  = 3;//data bits
localparam                       C_STOP       = 4;//stop bit
localparam                       C_WAIT       = 5;//blank between two bytes transmit

// register define \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

reg[2:0]                         state;
reg[15:0]                        cycle_cnt; //baud counter
reg[3:0]                         bit_cnt;//bit counter
reg[TRANSMIT_BITS-1:0]           tx_data_latch; //latch data to send
reg                              tx_reg; //serial data output
assign tx_pin = tx_reg;

//    main code     \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

//state machine
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            state        <=    C_IDLE;
            cycle_cnt    <=    0;
            bit_cnt        <=    0;
        end
    else
        case(state)
            C_IDLE:
                if(tx_data_valid == 1'b1)
                    state <= C_START;
                else
                    state <= C_IDLE;
            C_START:
                if(cycle_cnt == CYCLE - 1)
                    begin
                        cycle_cnt    <=    0;
                        state         <=     C_SEND_BYTE;
                    end
                else 
                    cycle_cnt    <=    cycle_cnt + 1;
            C_SEND_BYTE:
                if(cycle_cnt == CYCLE - 1 && bit_cnt == TRANSMIT_BITS-1)
                    begin
                        state         <=     C_STOP;
                        cycle_cnt    <=    0;
                        bit_cnt        <=    0;
                    end
                else if(cycle_cnt == CYCLE - 1)
                    begin
                        cycle_cnt    <=    0;
                        bit_cnt        <=    bit_cnt + 1;
                    end
                else
                    cycle_cnt    <=    cycle_cnt + 1;
            C_STOP:
                if(cycle_cnt == CYCLE - 1)
                    begin
                        state         <= C_WAIT;
                        cycle_cnt    <=    0;
                    end
                else
                    cycle_cnt    <=    cycle_cnt + 1;
            C_WAIT:
                if(cycle_cnt == 10*CYCLE - 1)
                    begin
                        state         <= C_IDLE;
                        cycle_cnt    <=    0;
                    end
                else
                    cycle_cnt    <=    cycle_cnt + 1;
            default:
                state <= C_IDLE;
    endcase
end

//data output
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        tx_data_ready <= 1'b0;
    else if(state == C_IDLE)
        if(tx_data_valid == 1'b1)
            tx_data_ready <= 1'b0;
        else
            tx_data_ready <= 1'b1;
    else if(state == C_WAIT && cycle_cnt == 10*CYCLE - 1)
            tx_data_ready <= 1'b1;
end


always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        begin
            tx_data_latch <= 0;
        end
    else if(state == C_IDLE && tx_data_valid == 1'b1)
            tx_data_latch <= tx_data;
        
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        tx_reg <= 1'b1;
    else
        case(state)
            C_IDLE,C_STOP:
                tx_reg <= 1'b1; 
            C_START:
                tx_reg <= 1'b0; 
            C_SEND_BYTE:
                tx_reg <= tx_data_latch[bit_cnt];
            default:
                tx_reg <= 1'b1; 
        endcase
end

endmodule 

然后再来编写接收模块,接收模块状态机要检测起始位,发现信号拉低后进入接收状态,按照波特率进行计数依次接收所有位,之后转入空闲状态等待下一个起始位,同时拉高数据接收完毕信号提示上层锁存接收数据。

//
//                                                                              //
//                                                                              //
// This source file is part of uart module.                                        //
// module features: 1.config bits number of one byte                              //
//                      2.config bitrate                                            //
// module function: receive uart bits                                            //
// copyright of this source file belongs to mayidianzi in CSDN blog                //
// contact the author by e-mail 1061165280@qq.com                                //
//                                                                              //
//

//================================================================================
//  Revision History:
//  Date              By                Revision        Change Description
//--------------------------------------------------------------------------------
//    2023/2/26       mayidianzi      1.0              Original
//*******************************************************************************/
module uart_rx
#(
    parameter                                 CLK_FRE            =    50,              //module clock frequency(MHz)
    parameter                                 BAUD_RATE        =    115200,         //serial baud rate
    parameter                                 RECEIVE_BITS      =    9                //bits number per byte
)
(
    input                                    clk,                  //clock input
    input                                    rst_n,                //asynchronous reset input, low active 
    output reg[RECEIVE_BITS-1:0]            rx_data,              //received serial data
    output reg                               rx_data_valid,        //received serial data is valid
    input                                    rx_pin                //serial data input
);

/ parameter config \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine
localparam                       C_WAIT      = 0; //blank between two bytes
localparam                       C_IDLE      = 1; //wait for start bit
localparam                       C_START     = 2; //start bit
localparam                       C_REC_BYTE  = 3; //data bits
localparam                       C_STOP      = 4; //stop bit
localparam                       C_DATA      = 5; //data pack

// register define \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

reg[2:0]                         state;
reg[RECEIVE_BITS-1:0]            rx_bits;          //temporary storage of received data
reg[15:0]                        cycle_cnt;        //baud counter
reg[3:0]                         bit_cnt;          //bit counter

//    main code     \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

//state machine
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            state        <=    C_WAIT;
            cycle_cnt    <=    0;
            bit_cnt        <=    0;
        end
    else
        case(state)
            C_WAIT:                                            //wait for blank between two bytes
                if(cycle_cnt > CYCLE & rx_pin == 1)
                    begin
                        cycle_cnt    <=    0;
                        state        <=    C_IDLE;
                        bit_cnt        <=    0;
                    end
                else if(rx_pin == 1)
                    cycle_cnt    <=    cycle_cnt + 1;
                else
                    cycle_cnt    <=    0;
            C_IDLE:                                            //wait for first start bit
                if(rx_pin == 0)
                    state <= C_START;
                else
                    state <= C_IDLE;
            C_START:                                        //start bit
                if(cycle_cnt == CYCLE - 1)                    //one data cycle 
                    begin
                        state         <= C_REC_BYTE;
                        cycle_cnt    <=    0;
                    end
                else
                    cycle_cnt    <=    cycle_cnt + 1;
            C_REC_BYTE:
                if(cycle_cnt == CYCLE - 1 && bit_cnt == RECEIVE_BITS-1)  //receive bits data
                    begin
                        state         <=     C_STOP;
                        bit_cnt        <=    0;
                        cycle_cnt    <=    0;
                    end
                else if(cycle_cnt == CYCLE - 1)
                    begin
                        cycle_cnt    <=    0;
                        bit_cnt        <=    bit_cnt + 1;
                    end
                else
                    cycle_cnt    <=    cycle_cnt + 1;
            C_STOP:
                if(cycle_cnt == CYCLE - 1)
                    begin
                        state         <=     C_DATA;
                        cycle_cnt    <=    0;
                    end
                else
                    cycle_cnt    <=    cycle_cnt + 1;
            C_DATA:                                                        //data receive complete 
                state <= C_IDLE;
            default:
                state <= C_WAIT;
    endcase
end

//data ready signal
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_data_valid <= 1'b0;
    else if(state == C_STOP)
        rx_data_valid <= 1'b1;
    else if(state == C_DATA)
        rx_data_valid <= 1'b0;
end

//data output
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_data <= 8'd0;
    else if(state == C_STOP)
        rx_data <= rx_bits;//latch received data
end

//receive serial data bit data
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_bits <= 8'd0;
    else if(state == C_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
        rx_bits[bit_cnt] <= rx_pin;
    else
        rx_bits <= rx_bits; 
end
endmodule 

三、后记

以上所有内容均记载在我的串口通用模块内,可以直接下载测试工程了解,或根据自己的工程需要进行改编。如果不想在串口通信方面耽误时间,集中力量开发高级功能,可直接调用我编写的通用串口模块,可直接进行例化实现串口通信功能。通用串口模块可分别自定义收发波特率、收发校验种类,具备串口通信常用的全部功能,可根据实际需求设置,减少您的开发周期,本通用串口模块经过仿真模拟和硬件测试,附有测试报告和开发说明,方便使用,传送门:

通用串口模块文章来源地址https://www.toymoban.com/news/detail-787912.html

到了这里,关于FPGA开发基础篇之一(接口篇)UART串口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【FPGA】UART串口通信---基于FIFO

    我们在上一章完成了UART串口通信的收发模块,这一章我们将FIFO引入进来,使用FIFO进行缓存数据,来连接串口通信的收发模块 FIFO即First In First Out,是一种先进先出数据存储、缓冲器,我们知道一般的存储器是用外部的读写地址来进行读写,而FIFO这种存储器的结构并不需要外

    2023年04月14日
    浏览(84)
  • 【FPGA】UART串口通信——奇偶校验实现

    奇偶校验位是基于uart的数据上进行一个判断 奇校验:数据1个数为奇时,校验为0,反之为1 偶校验:数据0个数为偶时,校验为0,反之为1 Uart回环在之前已经实现,现在需要基于uart增加一个奇偶校验位的需求 uart及代码:https://blog.csdn.net/weixin_59150966/article/details/128005066?spm=10

    2024年02月11日
    浏览(42)
  • FPGA实战 -- UART --- 实现串口回环(加FIFO)

    FPGA基础 – 通信协议 — 了解UART以及电脑串口环境准备 咱们上一文章学过了UART的基础,已经初步了解了协议的基础知识和时序要求,接下来就是将学到的写出东西来,本文通过上位机的串口助手发送数据,FIFO将数据在RX和TX之间进行传递,并且传递回上位机的串口助手,修改

    2024年02月20日
    浏览(43)
  • 基于FPGA的超声波测距——UART串口输出

    环境: 1、Quartus18.0 2、vscode 3、板子型号:EP4CE10F17C8 4、超声波模块:HC_SR04 要求: 使用 EP4CE10F17C8开发板驱动 超声波检测模块(HC_SR04 ),并将所测得数据显示到串口助手上。 HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发

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

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

    2024年04月14日
    浏览(35)
  • FPGA-结合协议时序实现UART收发器(五):串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive

    串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive,功能实现。 对照代码,串口发送模块UART_TOP实现功能包括: PLL锁相环,实现稳定系统输入时钟功能 UART_FIFO,数据先进先出,实现数据缓存功能,防止出现数据错乱 w_clk_rst = ~w_system_pll_locked;保证复位电平是先高位再地位 r_use

    2024年02月08日
    浏览(88)
  • FPGA实现UART通信(1)---发送数据

    1、基本概念 通用异步收发传输器,是一种异步收发传输器,在发送数据通过将并行数据转换成串行数据进行传输,在接收数据时将串行数据转换成并行数据。 串行通信分为同步串行通信和异步串行通信。同步串行通信即需要时钟的参与,通信双方需要在同一时钟的控制下,

    2024年02月04日
    浏览(45)
  • FPGA高端图像处理开发板-->鲲叔4EV:12G-SDI、4K HDMI2.0、MIPI等接口谁敢与我争锋?

    在CSDN写博客传播FPGA开发经验已经一年多了,帮助了不少人,也得罪了不少人,有的人用我的代码赢得了某些比赛、得到了心仪的offer,也有的人天天骂我,anyway,哪怕只要还能帮助一个即将毕业的学生找到工作,哪怕只要还能帮助一个工程师解决项目开发的燃眉之急,我做的

    2024年04月16日
    浏览(65)
  • 基于FPGA的高速数据采集ATA接口Verilog开发与Matlab

    基于FPGA的高速数据采集ATA接口Verilog开发与Matlab 摘要: 本文介绍了基于FPGA的高速数据采集ATA接口的Verilog开发与Matlab的应用。通过使用Verilog语言进行FPGA的硬件设计,实现了ATA接口的数据采集功能。同时,结合Matlab进行数据处理和分析,实现了对采集的数据进行实时处理和显

    2024年02月07日
    浏览(55)
  • FPGA(Verilog)实现uart传输协议传输数据(含仿真)

    目录 实现功能: 1.接收uart串行数据,输出并行数据(1byte)。 2.输入并行数据(1byte),输出uart串行数据。 3.完成uart传输的1次环回。 uart协议的1帧数据传输 模块封装-port设置 Verilog代码实现 1.uart接收模块:接收串行数据,输出并行数据和其有效标志。 仿真结果: 2.uart发送模块:接收

    2024年04月16日
    浏览(45)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包