【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
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UART(通用异步收发传输器)是一种常用的串行通信协议,它使用了异步传输方式,可以用于电脑与其他设备之间的数据传输。在实现UART硬件时,可以使用Verilog进行设计和描述。下面是一个简单的UART通信模块的Verilog代码示例: ```verilog module uart ( input clk, input rst, input [7:0] data_in, input tx_en, output reg [7:0] data_out, output reg rx_dv, output reg rx_err ); // 定义状态机状态 parameter IDLE = 2'b00; parameter START = 2'b01; parameter DATA = 2'b10; parameter STOP = 2'b11; // 定义状态机输入和输出 reg [1:0] state_reg, state_next; reg [7:0] data_in_reg; reg tx_en_reg; reg [3:0] count_reg; reg [7:0] data_out_reg; reg rx_dv_reg, rx_err_reg; // 定义状态机逻辑 always @(posedge clk, posedge rst) begin if (rst) begin state_reg <= IDLE; data_in_reg <= 8'd0; tx_en_reg <= 1'b0; count_reg <= 4'd0; data_out_reg <= 8'd0; rx_dv_reg <= 1'b0; rx_err_reg <= 1'b0; end else begin state_reg <= state_next; data_in_reg <= data_in; tx_en_reg <= tx_en; count_reg <= (count_reg == 4'd15) ? 4'd0 : count_reg + 1; data_out_reg <= data_out; rx_dv_reg <= rx_dv; rx_err_reg <= rx_err; end end // 定义状态机状态转移 always @(*) begin state_next = state_reg; case (state_reg) IDLE: begin if (!tx_en_reg) begin state_next = IDLE; end else begin state_next = START; count_reg <= 4'd0; end end START: begin if (count_reg == 4'd8) begin state_next = DATA; count_reg <= 4'd0; end else begin state_next = START; count_reg <= count_reg + 1; end end DATA: begin if (count_reg == 4'd8) begin state_next = STOP; count_reg <= 4'd0; end else begin state_next = DATA; count_reg <= count_reg + 1; end end STOP: begin state_next = IDLE; end endcase end // 定义rx_dv输出 always @(posedge clk) begin if (state_reg == STOP) begin rx_dv <= 1'b1; end else begin rx_dv <= 1'b0; end end // 定义rx_err输出 always @(posedge clk) begin if (state_reg == STOP && data_in_reg != data_out_reg) begin rx_err <= 1'b1; end else begin rx_err <= 1'b0; end end // 定义data_out输出 always @(posedge clk) begin if (state_reg == DATA) begin data_out <= data_in_reg; end else if (state_reg == STOP) begin data_out <= 8'd0; end else begin data_out <= data_out_reg; end end endmodule ``` 上述代码示例定义了一个UART通信模块,其包括了发送和接收数据的状态机逻辑。使用Verilog可以实现这个通信模块的设计和描述,从而实现UART串行通信协议的硬件实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值