FPGA串口通信----uart(二)

在UART(一)中主要解决的是单字节的发送和接受但是单字节的应用场景相对较小。在大多数场景下,串口都是用于连续多字节的收发工作。 因此,本篇文章将基于已有的单字节串口收发模块,结合上一章学习的状态机,完成多字节串口发送模块和多字节串口接收模块的设计,并通过仿真和板级测试对设计进行验证,完成多字节串口收发的验证。

一、多字节发送(Tx_bytes)

1.1Verilog 代码: 

例化UART(一)的单字节发送模块 

`timescale 1ns / 1ps
//
// Description: 串口多字节发送
//
module uart_bytes_tx#(
    parameter  DATA_WIDTH = 32
)(
    Clk			,
	Rst_n		,
	data_bytes	,
	send_en		,   
	Baud_Set	,  
	uart_tx		,  
	Tx_Done		,   
	uart_state 
);
	input 		                Clk 		;    //模块全局时钟输入,50M
	input 		                Rst_n		;    //复位信号输入,低有效
	input [DATA_WIDTH - 1:0]    data_bytes	;    //待传输 多字节 数据
	input 		                send_en		;    //发送使能
	input [2:0]	                Baud_Set	;    //波特率设置
	output  	                uart_tx		;    //串口输出信号
	output reg 	                Tx_Done		;    //数据发送完成标志
	output  	                uart_state	;    //发送数据状态

reg [3:0]               state,n_state   ;
reg [7:0]               cnt             ;
reg [DATA_WIDTH - 1:0]  r_data_bytes    ;
reg [7:0]               data_byte       ;
reg                     send_byte_en    ;
wire                    byte_tx_done    ;
wire                    uart_tx         ;
wire                    uart_state      ;
//**********  单字节数据发送模块例化 *******\\
uart_tx_byte uart_tx_byte_u0(
    .Clk			(Clk         ),
	.Rst_n		    (Rst_n       ),  
	.data_byte	    (data_byte   ),
	.send_en		(send_byte_en),   
	.Baud_Set	    (Baud_Set    ),  	
	.uart_tx		(uart_tx     ),  
	.Tx_Done		(byte_tx_done),   
	.uart_state     (uart_state  )
);

localparam  S0 = 4'b0001, //等待发送使能(初始态)
            S1 = 4'b0010, //准备数据
            S2 = 4'b0100, //等待单字节数据发送完成
            S3 = 4'b1000; //检查所有数据是否发送完成
//**************  状态机  ***************\\
always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        state <= S0;
    else 
        state <= n_state;
end

always @(*) begin
    case (state)
        S0: if(send_en)
                n_state <= S1;
            else 
                n_state <= S0;
        S1: n_state <= S2;
        S2: if(byte_tx_done)
                n_state <= S3;
            else
                n_state <= S2;
        S3: if(cnt >= DATA_WIDTH - 8)
                n_state <= S0;
            else
                n_state <= S1;
        default:n_state <= S0;
    endcase
end

always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        r_data_bytes <= 'd0;
    else if(state == S0 && send_en)
        r_data_bytes <= data_bytes;
    else if(state == S1)
        r_data_bytes <= r_data_bytes << 8;
    else 
        r_data_bytes <= r_data_bytes;
end

always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        send_byte_en <= 'd0;
    else if(state == S1)
        send_byte_en <= 'd1;
    else
        send_byte_en <= 'd0;
end

always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        data_byte <= 'd0;
    else if(state == S1)
        data_byte <= r_data_bytes[DATA_WIDTH - 1 : DATA_WIDTH  -8];
    else
        data_byte <= data_byte;
end

always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        cnt <= 'd0;
    else if(state == S3 && cnt >= DATA_WIDTH - 8)
        cnt <= 'd0;
    else if(state == S3)
        cnt <= cnt + 'd8;
    else
        cnt <= cnt;
end

always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        Tx_Done <= 'd0;
    else if(state == S3 && cnt >= DATA_WIDTH - 8)
        Tx_Done <= 'd1;
    else
        Tx_Done <= 'd0;
end

endmodule

1.2 tb文件 

`timescale 1ns / 1ps
module tb_byte_tx();

parameter DATA_WIDTH = 32;
    reg 		                Clk 		;    //模块全局时钟输入,50M
	reg 		                Rst_n		;    //复位信号输入,低有效
	reg [DATA_WIDTH - 1:0]      data_bytes	;    //待传输 多字节 数据
	reg 		                send_en		;    //发送使能
	wire	                    uart_tx		;    //串口输出信号
	wire	                    Tx_Done		;    //1byte数据发送完成标志
	wire	                    uart_state	;    //发送数据状态

uart_bytes_tx#(
    .DATA_WIDTH     (DATA_WIDTH )
)
uart_bytes_tx_u0
(
    .Clk			(Clk 		),
	.Rst_n		    (Rst_n		),
	.data_bytes	    (data_bytes	),
	.send_en		(send_en	),   
	.Baud_Set	    ('d4     	),  	
	.uart_tx		(uart_tx	),  
	.Tx_Done		(Tx_Done	),   
	.uart_state     (uart_state	)
);
initial Clk = 0;
always #10 Clk = ~Clk;

initial begin
    Rst_n = 0;
    data_bytes = 0;
    send_en = 0;
    #201;
    Rst_n = 1;
    #2000;
    data_bytes = 32'h01234567;
    send_en = 1;
    #20;
    send_en = 0;
    #20;
    @(posedge Tx_Done);
    #1;
    data_bytes = 32'h12345678;
    send_en = 1;
    #20;
    send_en = 0;
    #20;
    @(posedge Tx_Done);
    #1; 
    data_bytes = 32'h23456789;
    send_en = 1;
    #20;
    send_en = 0;
    #20;
    @(posedge Tx_Done);
    #1;
    #2000;
    $stop; 
end
endmodule

仿真图

二、多字节接收 (Rx_bytes)

2.1Verilog 代码 

`timescale 1ns / 1ps
// 
// Description: 多字节接收
//
module uart_bytes_rx#(
    parameter  DATA_WIDTH = 32
)(
    Clk             ,
    Rst_n           ,
    uart_rx         ,
    Baud_Set        ,
    Rx_done         ,
    timeout_flag    ,
    rx_data_bytes
    );
input                           Clk             ;
input                           Rst_n           ;
input                           uart_rx         ;
input[2:0]                      Baud_Set        ;
output reg                      Rx_done         ;
output reg                      timeout_flag    ;
output reg [DATA_WIDTH - 1 : 0] rx_data_bytes   ;

reg  [DATA_WIDTH - 1 : 0]       r_r_data_bytes  ;

wire [19:0]                     TIMEOUT         ;
wire [7:0]                      data_byte       ;
wire                            byte_rx_done    ;

reg                     to_state        ;
reg[31:0]               timeout_cnt     ;
reg[1:0]                state           ;
reg[8:0]                cnt             ;

//根据波特率自动设置超时时间
assign TIMEOUT  =   (Baud_Set == 3'd0) ? 20'd182291:
                    (Baud_Set == 3'd1) ? 20'd91145 :
                    (Baud_Set == 3'd2) ? 20'd45572 :
                    (Baud_Set == 3'd3) ? 20'd30381 :
                                         20'd15190 ;
	
localparam S0 = 0; //等待单字节接收完成信号
localparam S1 = 1; //判断接收是否超时
localparam S2 = 2; //检查所有数据是否接收完成

//**************** 单字节接收模块例化 ******************\\
uart_byte_rx uart_byte_rx_u0(
    .Clk      (Clk          ),
    .Reset_n  (Rst_n        ),
    .Baud_Set (Baud_Set     ),
    .uart_rx  (uart_rx      ),
    .Data     (data_byte    ),
    .Rx_Done  (byte_rx_done )
);
//****************超时标志 ******************\\
always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        timeout_flag <= 'd0;
    else if(timeout_cnt >= TIMEOUT)
        timeout_flag <= 'd1;
    else if(state == S0)
        timeout_flag <= 'd0;
    else
        timeout_flag <= timeout_flag;
end

always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        to_state <= 'd0;
    else if(!uart_rx)
        to_state <= 'd1;
    else if(byte_rx_done)
        to_state <= 'd0;
    else 
        to_state <= to_state;
end

always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)
        timeout_cnt <= 'd0;
    else if(to_state)begin
        if(byte_rx_done)
            timeout_cnt <= 'd0;
        else if(timeout_cnt >= TIMEOUT)
            timeout_cnt <= TIMEOUT;
        else
            timeout_cnt <= timeout_cnt + 1;
    end
    else
        timeout_cnt <= timeout_cnt;
end
//**************** 状态机 ******************\\
always @(posedge Clk or negedge Rst_n) begin
    if(!Rst_n)begin
        state           <= S0;
		r_r_data_bytes  <= 0 ;
		cnt             <= 0 ;
		rx_data_bytes   <= 0 ;
	end
	else begin
		case(state)
			S0: 
				begin
					Rx_done <= 0;
					r_r_data_bytes <= 0;
					if(DATA_WIDTH == 8)begin
						rx_data_bytes <= data_byte;
						Rx_done       <= byte_rx_done;
					end
					else if(byte_rx_done)begin
						state <= S1;
						cnt   <= cnt + 9'd8;
					    r_r_data_bytes <= {r_r_data_bytes[DATA_WIDTH - 1 - 8 : 0], data_byte};
					end
				end
			
			S1:
				if(timeout_flag)begin
					state   <= S0;
					Rx_done <= 1 ;	
				end
				else if(byte_rx_done)begin
					state <= S2;
					cnt   <= cnt + 9'd8;
					r_r_data_bytes <= {r_r_data_bytes[DATA_WIDTH - 1 - 8 : 0], data_byte};
				end
				
			S2:
				if(cnt >= DATA_WIDTH)begin
					state <= S0;
					cnt   <= 0;
					rx_data_bytes  <= r_r_data_bytes;
					Rx_done        <= 1;
				end
				else begin
					state   <= S1;
					Rx_done <= 0;
				end
			default:state <= S0;
		endcase	
	end
end
endmodule

2.2 TB文件

`timescale 1ns / 1ps
module uart_rx_bytes_tb();
parameter  DATA_WIDTH = 32;
reg                         Clk     ;
reg                         Rst_n   ;
reg  [DATA_WIDTH - 1 : 0]   data    ;
wire [DATA_WIDTH - 1 : 0]   rx_data ;
reg                         send_en ;
wire                        uart_tx ;
wire                        uart_rx ;
wire                        Tx_Done ;
wire                        uart_state;
wire                        Rx_Done ;
wire                        timeout_flag;

assign uart_rx = uart_tx;

uart_bytes_tx#(
    .DATA_WIDTH     (DATA_WIDTH)
)
uart_bytes_tx_u0
(
    .Clk			(Clk    ),
	.Rst_n		    (Rst_n  ),
	.data_bytes	    (data   ),
	.send_en		(send_en),   
	.Baud_Set	    ('d4    ),  
	.uart_tx		(uart_tx),  
	.Tx_Done		(Tx_Done),   
	.uart_state     (uart_state)
);

uart_bytes_rx#(
    .DATA_WIDTH    (DATA_WIDTH)
)
uart_bytes_rx_u0
(
    .Clk            (Clk    ),
    .Rst_n          (Rst_n  ),
    .uart_rx        (uart_tx),
    .Baud_Set       ('d4    ),
    .Rx_done        (Rx_Done),
    .timeout_flag   (timeout_flag),
    .rx_data_bytes  (rx_data)
);

initial Clk = 1;
always #10 Clk = !Clk;

initial begin
    Rst_n = 0;
    data = 0;
    send_en = 0;
    #201;
    Rst_n = 1;
    #2000;
    data = 32'h12345678;
    send_en = 1;
    #20;
    send_en = 0;
    #20;
    @(posedge Tx_Done);
    #1;
    #1000000;
    data = 32'h87654321;
    send_en = 1;
    #20;
    send_en = 0;
    #20;
    @(posedge Tx_Done);
    #1; 
    #1000000;
    data = 32'h24680135;
    send_en = 1;
    #20;
    send_en = 0;
    #20;
    @(posedge Tx_Done);
    #1;
    #400000;
    $stop; 
end

endmodule

 仿真图

三、多字节串口收发回环 (loopback)

3.1Verilog 代码

`timescale 1ns / 1ps
//
// Description: 串口回环
//
module uart_loopback#(
    parameter  DATA_WIDTH = 32
)
(
    Clk     ,
    Rst_n   ,
    uart_rx ,
    led     ,
    uart_tx 
);



input                   Clk         ;
input                   Rst_n       ;
input                   uart_rx     ;

output [2:0]            led         ;
output                  uart_tx     ;

wire [DATA_WIDTH-1:0]   data        ;
wire                    Rx_Done     ;
wire [7:0]              data_byte   ;

uart_bytes_rx#(
    .DATA_WIDTH   (DATA_WIDTH)
)
uart_bytes_rx_u0
(
    .Clk             (Clk    ),
    .Rst_n           (Rst_n  ),
    .uart_rx         (uart_rx),
    .Baud_Set        ('d4    ),
    .Rx_done         (Rx_Done),
    .timeout_flag    (led[0]),
    .rx_data_bytes   (data  )   
    );
uart_bytes_tx#(
    .DATA_WIDTH   (DATA_WIDTH)
)
uart_bytes_tx_u0
(
    .Clk			(Clk    ),
	.Rst_n		    (Rst_n  ),
	.data_bytes	    (data   ),
	.send_en		(Rx_Done),   
	.Baud_Set	    ('d4    ),  
	.uart_tx		(uart_tx),  
	.Tx_Done		(led[1]),   
	.uart_state     (led[2])
);
endmodule

 3.2 TB文件(例化多字节发送数据来发模拟数据)

`timescale 1ns / 1ps
module uart_loopback_tb();
parameter  DATA_WIDTH = 256;

reg                   Clk         ;
reg                   Rst_n       ;

wire                  uart_rx     ;
wire [2:0]            led         ;
wire                  uart_tx     ;

reg [DATA_WIDTH-1:0]    data        ;
reg                     send_en     ;
wire                    TX_Done     ;
wire                    uart_state   ;
wire                    uart_tx_u0  ;

assign uart_rx = uart_tx_u0;
uart_bytes_tx#(
    .DATA_WIDTH (DATA_WIDTH)
)
uart_bytes_tx_u0
(
    .Clk			(Clk    ),
	.Rst_n		    (Rst_n  ),
	.data_bytes	    (data   ),
	.send_en		(send_en),   
	.Baud_Set	    ('d4    ),  
	.uart_tx		(uart_tx_u0),  
	.Tx_Done		(TX_Done),   
	.uart_state     (uart_state)
);
uart_loopback #(
    .DATA_WIDTH (DATA_WIDTH)
)
uart_loopback_u0
(
    .Clk     (Clk     ),
    .Rst_n   (Rst_n   ),
    .uart_rx (uart_rx ),
    .led     (led     ),
    .uart_tx (uart_tx )
);

initial Clk = 1;
	always #10 Clk = !Clk;
	
	initial begin
		Rst_n = 0;
		data = 0;
		send_en = 0;
		#201;
		Rst_n = 1;
		#2000;
		data = 256'h890abcdef12312345abcdef674567890cba0987654fed365432121fedcba0987;
		send_en = 1;
		#20;
		send_en = 0;
		#20;
		@(posedge TX_Done);
//        #1;
		#1000000;
		data = 256'hcba0987654fed365432121fedcba0987ba09876fe321dc54b321dc6fe54a0978;
		send_en = 1;
		#20;
		send_en = 0;
		#20;
		@(posedge TX_Done);
//		#1;	
		#1000000;
		data = 256'h890abcdef123123454fed365432121fedcba09875abcdef674567890cba09876;
		send_en = 1;
		#20;
		send_en = 0;
		#20;
		@(posedge TX_Done);
		#1;
		#4000000;
		$stop;		
	end
endmodule

仿真图 

 上板仿真

可以成功实现 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值