【FPGA】UART串口通信

一、通信方式

1.串行通信

串行通信是指利用一条传输线将数据一位位地顺序传送。(也就是说串行通信传输的数据是1比特1比特的传送的)
在这里插入图片描述常见串行通信接口
在这里插入图片描述
串行通信优点是传输距离远、占用资源少。
串行通信缺点是发送速度慢。

2.并行通信

并行是指多比特数据同时通过并行线进行传送,这样数据传送速度大大提高。

但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,数据也就容易出错。
在这里插入图片描述
并行通信优点是发送速度快。
并行通信缺点是传输距离短、资源占用多。

二、UART串口通信

UART是一种异步全双工通信方式
在这里插入图片描述

1.模块设计与时序图

在这里插入图片描述

uart_tx模块时序图
在这里插入图片描述

uart_rx模块时序图
在这里插入图片描述

2.代码实现

uart.v(顶层模块)

module  uart
(
    input   clk     ,
    input   rst_n   ,

    input   u_rx    ,
    output  u_tx       
);

wire    [7:0]   data    ;
wire            start   ;

uart_rx uart_rx(
    .clk        (clk)   ,
    .rst_n      (rst_n) ,

    .data       (data)  ,
    .start      (start) ,
    .u_rx       (u_rx)
);

uart_tx uart_tx(
    .clk        (clk)   ,
    .rst_n      (rst_n) ,
    
    .data       (data)  ,
    .start      (start) ,
    .u_tx       (u_tx)  
);

endmodule

uart_tx

module uart_tx
#(
    parameter BAUD_MAX  = 5208,
    parameter BAUD_FLAG = 1
)
(
    input           clk         ,
    input           rst_n       ,

    input   [7:0]   data        ,
    input           start       ,

    output  reg     u_tx             
);

reg     [14:0]      baud_cnt    ;
reg     [4:0]       bit_cnt     ;

reg                 data_state  ;
reg                 bit_flag    ;
reg                 done        ;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        data_state <= 1'b0 ;
    else if(start)
        data_state <= 1'b1 ;
    else if(done)
        data_state <= 1'b0 ;
    else
        data_state <= data_state ; 
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        baud_cnt <= 1'b0 ;
    else if(data_state)begin
        if(baud_cnt == BAUD_MAX - 1)
            baud_cnt <= 1'b0 ;
        else
            baud_cnt <= baud_cnt + 1'b1 ;
    end
    else
        baud_cnt <= 1'b0 ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        bit_flag <= 1'b0 ;
    else if(baud_cnt == BAUD_FLAG)
        bit_flag <= 1'b1 ;
    else
        bit_flag <= 1'b0 ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        bit_cnt <= 1'b0 ;
    else if(bit_flag)begin
        if(bit_cnt == 9)
            bit_cnt <= 1'b0 ;
        else
            bit_cnt <= bit_cnt + 1'b1 ;
    end
    else
        bit_cnt <= bit_cnt ;
end

always @(posedge clk or negedge rst_n) begin  
    if(!rst_n)
        u_tx <= 1'b1 ;  
    else if(bit_flag)begin
        case(bit_cnt)
            0 : u_tx <= 1'b0    ;
            1 : u_tx <= data[0] ;
            2 : u_tx <= data[1] ;
            3 : u_tx <= data[2] ;
            4 : u_tx <= data[3] ;
            5 : u_tx <= data[4] ;
            6 : u_tx <= data[5] ;
            7 : u_tx <= data[6] ;
            8 : u_tx <= data[7] ;
            9 : u_tx <= 1'b1    ;
            default : u_tx <= 1'b1 ;
        endcase
    end
    else
        u_tx <= u_tx ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        done <= 1'b0 ;
    else if(bit_cnt == 9 && bit_flag)
        done <= 1'b1 ;
    else
        done <= 1'b0 ;
end

endmodule

uart_rx

module uart_rx
#(
    parameter BAUD_MAX  = 5208,
    parameter BAUD_FLAG = 2604 
)
(
    input   clk     ,
    input   rst_n   ,

    input   u_rx    ,

    output reg        start ,
    output reg  [7:0] data
);

reg                 u_rx0       ;
reg                 u_rx1       ;
reg                 u_rx2       ;

reg     [14:0]      baud_cnt    ;
reg     [4:0]       bit_cnt     ;

reg                 data_state  ;
reg                 bit_flag    ;
reg                 done        ;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        u_rx0 <= 1'b1 ;
        u_rx1 <= 1'b1 ;
        u_rx2 <= 1'b1 ;
    end
    else begin
        u_rx0 <= u_rx  ;
        u_rx1 <= u_rx0 ;
        u_rx2 <= u_rx1 ;
    end
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        data_state <= 1'b0 ;
    else if((!u_rx1) && (u_rx2))
        data_state <= 1'b1 ;
    else if(done)
        data_state <= 1'b0 ;
    else
        data_state <= data_state ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        baud_cnt <= 1'b0 ;
    else if(data_state)begin
        if(baud_cnt == BAUD_MAX - 1)
            baud_cnt <= 1'b0 ;
        else
            baud_cnt <= baud_cnt + 1'b1 ;
    end
    else
        baud_cnt <= 1'b0 ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        bit_flag <= 1'b0 ;
    else if(baud_cnt == BAUD_FLAG)
        bit_flag <= 1'b1 ;
    else
        bit_flag <= 1'b0 ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        bit_cnt <= 1'b0 ;
    else if(bit_flag)begin
        if(bit_cnt == 9)
            bit_cnt <= 1'b0 ;
        else
            bit_cnt <= bit_cnt + 1'b1 ;
    end
    else
        bit_cnt <= bit_cnt ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        data <= 8'b00000000 ;
    else if(bit_flag)begin     
        case(bit_cnt)
            0 : data    <= data  ;
            1 : data[0] <= u_rx2 ;
            2 : data[1] <= u_rx2 ;
            3 : data[2] <= u_rx2 ;
            4 : data[3] <= u_rx2 ;
            5 : data[4] <= u_rx2 ;
            6 : data[5] <= u_rx2 ;
            7 : data[6] <= u_rx2 ;
            8 : data[7] <= u_rx2 ;
            9 : data    <= data  ;
            default : data <= data ;
        endcase
    end
    else
        data <= data ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        done <= 1'b0 ;
    else if(bit_cnt == 9 && bit_flag)
        done <= 1'b1 ;
    else
        done <= 1'b0 ;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        start <= 1'b0 ;
    else
        start <= done ;
end

endmodule

uart_tb

`timescale 1ps/1ps

module uart_tb();

reg             clk     ;
reg             rst_n   ;

reg             u_rx    ;
wire            u_tx    ;

uart    u_uart
(
    .clk        (clk)   ,
    .rst_n      (rst_n) ,

    .u_rx       (u_rx)  ,
    .u_tx       (u_tx)  
);

initial begin
    clk = 1;
    forever
    #10
    clk=~clk;
end

initial begin
    rst_n = 1;
    #10;
    rst_n = 0;
    #20;
    rst_n = 1;
end

parameter TIMEPERIOD = 20;

initial begin
		u_rx = 1'b1;
		#200
		//发送起始位
		u_rx = 1'd0;
		#(5027*TIMEPERIOD);
		//发送数据0
		u_rx = 1'd1;
        #(5027*TIMEPERIOD);
		//发送数据1
		u_rx = 1'd0;
		#(5027*TIMEPERIOD);
		//发送数据2
		u_rx = 1'd0;
		#(5027*TIMEPERIOD);
		//发送数据3
		u_rx = 1'd0;
		#(5027*TIMEPERIOD);
		//发送数据4
		u_rx = 1'd0;
		#(5027*TIMEPERIOD);
		//发送数据5
		u_rx = 1'd1;
        #(5027*TIMEPERIOD);
		//发送数据6
		u_rx = 1'd0;
		#(5027*TIMEPERIOD);
		//发送数据7
		u_rx = 1'd0;
		#(5027*TIMEPERIOD);
		//发送结束位
		u_rx = 1'd1;
		#(100000*TIMEPERIOD);
		$stop ;
end

endmodule

三、测试结果

1.仿真结果

在这里插入图片描述

2.上板验证

在这里插入图片描述

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值