4、vivado之uart串口数据发送与接收

文章目录

  • 实验目标
  • 实验原理
    • 串口协议
    • 状态机设定
    • 关于波特率,采用115200的波特率设计
  • 实验代码
    • rx_uart
    • uart_tx
    • uart_top
  • 实验结果
    • 仿真结果
    • 仿真代码
    • 上电测试
  • 总结

实验目标

常态下,fpga 侧实现1s一次的的数据发送。在空闲的时候, fpga侧实现串口的数据的接收,然后再通过串口将数据返回给上位机

实验原理

串口协议

4、vivado之uart串口数据发送与接收_第1张图片

状态机设定

4、vivado之uart串口数据发送与接收_第2张图片

4、vivado之uart串口数据发送与接收_第3张图片

关于波特率,采用115200的波特率设计

实验代码

说明:以下的代码是我照着黑金的修改后,形成的自己的代码,要看原来的代码可以参考黑金的资料。

rx_uart

`timescale 1ns / 1ps
/*
模块功能简介
接收来自rx_pin 的 uart 数据v
将接收到的数据完成后,将我们的数据的rx_data_valid 置位有效

# 然后将收到的数据 通过rx_data 发送出去


*/


module uart_rx

#( 
    parameter clk_fre = 50,
    parameter baud_rate = 115200
)
(

    input clk,
    input rst_n,
    
    input rx_pin,
    
        
    input rx_data_ready,
    
    output reg rx_data_valid,
    output reg [7:0] rx_data
);
//calculates the clock cycle for baud rate 
localparam cycle = clk_fre * 1000000/baud_rate;
parameter rx_idle=3'b000;
parameter rx_start=3'b001;
parameter rx_rcv_byte=3'b010;
parameter rx_stop=3'b011;
parameter rx_data_state =3'b100;

reg [2:0]rx_state=0;
reg [2:0]next_stae;
reg rx_d0;
reg rx_d1;

wire rx_negedge;
reg [7:0] rx_bits=0;
reg [15:0] cycle_cnt=0;
reg [2:0] bit_cnt=0;

assign rx_negedge = rx_d1 && ~rx_d0;


// This part is for detecting the start of the translation f
always @(posedge clk or negedge rst_n)
begin
    if (rst_n ==1'b0)
        begin
            rx_d0 <=0;
            rx_d1 <=0;
        
        end
    else 
    begin
        rx_d0 <= rx_pin;
        rx_d1 <= rx_d0; 
    end
end


always@(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
        begin
            rx_state <= rx_idle;
            rx_data_valid <= 1'b0;
            
        end
    else 
        begin
            case(rx_state)
            rx_idle:
                begin
                    if(rx_negedge == 1'b1)
                        rx_state <= rx_start;
                    else
                        rx_state <= rx_idle;
                 end
            rx_start:
                begin
                    if(cycle_cnt == cycle -1)
                        begin
                            rx_state <= rx_rcv_byte;
                            cycle_cnt <= 16'd0;
                        end
                    else
                        begin
                            rx_state <= rx_start;
                            cycle_cnt <= cycle_cnt + 16'd1;
                        end
                end
            rx_rcv_byte:
                begin
                    if(cycle_cnt == cycle - 1)
                    //分成两种情况,达到8个bit/没到8个字节
                    begin
                        if(bit_cnt == 3'd7)
                            begin
                                rx_state <= rx_stop;
                                bit_cnt <= 3'd0;
                                cycle_cnt <= 16'd0;
                            end
                        else
                            begin
                                bit_cnt <= bit_cnt + 3'd1;
                                cycle_cnt <= 16'd0;
                            end
                        
                    end
                    else if (cycle_cnt == cycle/2 -1)
                        begin
                            rx_bits[bit_cnt] <= rx_pin;
                            cycle_cnt <= cycle_cnt + 16'd1;
                        end
                    else
                        cycle_cnt <= cycle_cnt + 16'd1;
                        
                end
            rx_stop:
                begin
                
                    if(cycle_cnt == cycle/2 -1)
                        begin
                            rx_state <= rx_data_state;      
                            rx_data <= rx_bits;//latch received data
                            cycle_cnt <= 16'd0;    
                            rx_data_valid <=1'b1;
                            
                        end
                    else
                        begin   
                            rx_state <= rx_stop;
                            rx_data_valid <=1'b0;
                            cycle_cnt <= cycle_cnt + 16'd1;
                        end
                end
            rx_data_state:
                begin                   
                    
                    if(rx_data_ready) // 低电平时候,就一直处在则个等待数据接收的状态
                        begin
                            rx_state <= rx_idle;
                            rx_data_valid <=1'b0;
                        end
                    else
                        begin                   
                            rx_data_valid <=1'b1;
                            rx_state <= rx_data_state;
                        end
                end
          default:
                rx_state <= rx_idle;
        endcase
    end
end

endmodule


//
//                                                                              //
//                                                                              //
//  Author: meisq                                                               //
//          [email protected]                                                          //
//          ALINX(shanghai) Technology Co.,Ltd                                  //
//          heijin                                                              //
//     WEB: http://www.alinx.cn/                                                //
//     BBS: http://www.heijin.org/                                              //
//                                                                              //
//
//                                                                              //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd                        //
//                    All rights reserved                                       //
//                                                                              //
// This source file may be used and distributed without restriction provided    //
// that this copyright statement is not removed from the file and that any      //
// derivative work contains the original copyright notice and the associated    //
// disclaimer.                                                                  //
//                                                                              //
//

//================================================================================
//  Revision History:
//  Date          By            Revision    Change Description
//--------------------------------------------------------------------------------
//2017/8/1                    1.0          Original
//*******************************************************************************/
//module uart_rx
//#(
//	parameter CLK_FRE = 50,      //clock frequency(Mhz)
//	parameter BAUD_RATE = 115200 //serial baud rate
//)
//(
//	input                        clk,              //clock input
//	input                        rst_n,            //asynchronous reset input, low active 
//	output reg[7:0]              rx_data,          //received serial data
//	output reg                   rx_data_valid,    //received serial data is valid
//	input                        rx_data_ready,    //data receiver module ready
//	input                        rx_pin            //serial data input
//);
calculates the clock cycle for baud rate 
//localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
state machine code
//localparam                       S_IDLE      = 1;
//localparam                       S_START     = 2; //start bit
//localparam                       S_REC_BYTE  = 3; //data bits
//localparam                       S_STOP      = 4; //stop bit
//localparam                       S_DATA      = 5;

//reg[2:0]                         state;
//reg[2:0]                         next_state;
//reg                              rx_d0;            //delay 1 clock for rx_pin
//reg                              rx_d1;            //delay 1 clock for rx_d0
//wire                             rx_negedge;       //negedge of rx_pin
//reg[7:0]                         rx_bits;          //temporary storage of received data
//reg[15:0]                        cycle_cnt;        //baud counter
//reg[2:0]                         bit_cnt;          //bit counter

//assign rx_negedge = rx_d1 && ~rx_d0;

//always@(posedge clk or negedge rst_n)
//begin
//	if(rst_n == 1'b0)
//	begin
//		rx_d0 <= 1'b0;
//		rx_d1 <= 1'b0;	
//	end
//	else
//	begin
//		rx_d0 <= rx_pin;
//		rx_d1 <= rx_d0;
//	end
//end


//always@(posedge clk or negedge rst_n)
//begin
//	if(rst_n == 1'b0)
//		state <= S_IDLE;
//	else
//		state <= next_state;
//end
外部状态切换
//always@(*)
//begin
//	case(state)
//		S_IDLE:
//			if(rx_negedge)
//				next_state <= S_START;
//			else
//				next_state <= S_IDLE;
//		S_START:
//			if(cycle_cnt == CYCLE - 1)//one data cycle 
//				next_state <= S_REC_BYTE;
//			else
//				next_state <= S_START;
//		S_REC_BYTE:
//			if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)  //receive 8bit data
//				next_state <= S_STOP;
//			else
//				next_state <= S_REC_BYTE;
//		S_STOP:
//			if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver
//				next_state <= S_DATA;
//			else
//				next_state <= S_STOP;
//		S_DATA:
//			if(rx_data_ready)    //data receive complete
//				next_state <= S_IDLE;
//			else
//				next_state <= S_DATA;
//		default:
//			next_state <= S_IDLE;
//	endcase
//end
 切换到接收数据是否有效
//always@(posedge clk or negedge rst_n)
//begin
//	if(rst_n == 1'b0)
//		rx_data_valid <= 1'b0;
//	else if(state == S_STOP && next_state != state)
//		rx_data_valid <= 1'b1;
//	else if(state == S_DATA && rx_data_ready)
//		rx_data_valid <= 1'b0;
//end
 当前状态是stop, 并且此时想要切换到下一个状态,此时,stop, stop 表示停止位。
//always@(posedge clk or negedge rst_n)
//begin
//	if(rst_n == 1'b0)
//		rx_data <= 8'd0;
//	else if(state == S_STOP && next_state != state)
//		rx_data <= rx_bits;//latch received data
//end

当前状态处在数据的接收一个bit 的过程中。
//always@(posedge clk or negedge rst_n)
//begin
//	if(rst_n == 1'b0)
//		begin
//			bit_cnt <= 3'd0;
//		end
//	else if(state == S_REC_BYTE)
//		if(cycle_cnt == CYCLE - 1)  // 跟随波特率进行,如果cycle cnt 到达一个周期,这个时候,我们实际上就已经接收了一个bit,此时,我们把接收到bit 个数加1
//			bit_cnt <= bit_cnt + 3'd1;
//		else
//			bit_cnt <= bit_cnt;
//	else
//		bit_cnt <= 3'd0;
//end

  波特率计算模块, 这个
//always@(posedge clk or negedge rst_n)
//begin
//	if(rst_n == 1'b0)
//		cycle_cnt <= 16'd0;
//	else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
//		cycle_cnt <= 16'd0;
//	else
//		cycle_cnt <= cycle_cnt + 16'd1;	
//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 == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
//		rx_bits[bit_cnt] <= rx_pin;
//	else
//		rx_bits <= rx_bits; 
//end
//endmodule 


uart_tx

module uart_tx

#( 
    parameter clk_fre = 50,
    parameter baud_rate = 115200
)
(

    input clk,
    input rst_n,
    input [7:0]tx_data,
    input tx_data_valid,
    
    
    output tx_pin,
    output reg tx_data_ready
    
);
//calculates the clock cycle for baud rate 
localparam cycle = clk_fre * 1000000/baud_rate;
parameter s_idle=3'b000;
parameter s_start=3'b001;
parameter s_send_byte=3'b010;
parameter s_stop=3'b011;

reg [2:0]state=0;
reg [2:0]next_state;

reg [15:0] cycle_cnt=0;
reg [2:0] bit_cnt=0;
reg [7:0] tx_data_latch;
reg tx_reg=1;
assign tx_pin = tx_reg;


always@(posedge clk or negedge rst_n)
begin
    if (rst_n == 1'b0)
        begin
            state <= s_idle;
        end
    else 
        begin
            case(state)
            s_idle:
                begin
                    if(tx_data_valid == 1'b1)
                        begin
                            state <= s_start;
                            tx_data_latch <= tx_data;
                            tx_data_ready <= 1'b0;
                        end
                    else
                        begin
                            tx_reg <= 1'b1;
                            state <=s_idle;
                            tx_data_ready <= 1'b1;
                        end
                 end
            s_start:
                begin
                    if(cycle_cnt == cycle -1)
                        begin
                            state <= s_send_byte;
                            cycle_cnt <= 16'd0;
                        end
                    else
                        begin
                            cycle_cnt <= cycle_cnt + 16'd1;
                            tx_reg <= 1'b0;
                            state <= s_start;
                            
                        end
                end
            s_send_byte:
                begin
                    if(cycle_cnt == cycle - 1)
                        //分成两种情况,达到8个bit/没到8个字节
                        begin
                            if(bit_cnt == 3'd7)
                                begin
                                    state <= s_stop;
                                    bit_cnt <= 3'd0;
                                    cycle_cnt <= 16'd0;
                                end
                            else
                                begin
                                    bit_cnt <= bit_cnt + 3'd1;
                                    cycle_cnt <= 16'd0;
                                end
                            
                        end
                    else
                        begin
                            cycle_cnt <= cycle_cnt + 16'd1;
                            tx_reg = tx_data_latch[bit_cnt];
                        end
                end
            s_stop:
                begin
                    if(cycle_cnt == cycle -1)
                        begin
                            tx_data_ready <= 1'b1;   
                            state <= s_idle;      
                            cycle_cnt <= 16'd0;    
                        end
                    else
                        begin   
                            tx_reg <= 1'b1;
                            cycle_cnt <= cycle_cnt + 16'd1;
                        end
                end
          default:
               state <= s_idle;
        endcase
    end
end

endmodule

uart_top

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/07/31 12:20:32
// Design Name: 
// Module Name: uart_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_top
(
input                           sys_clk_p,         //system clock positive
input                           sys_clk_n,         //system clock negative 
input                           rst_n,             //reset ,low active
input                           uart_rx,           //fpga receive data
output                          uart_tx            //fpga send data
);
parameter                       clk_fre = 200;    //Mhz
localparam                       IDLE =  0;
localparam                       SEND =  1;         //send HELLO ALINX\r\n
localparam                       WAIT =  2;         //wait 1 second and send uart received data
reg[7:0]                         tx_data;          //sending data
reg[7:0]                         tx_str;
reg                              tx_data_valid;    //sending data valid
wire                             tx_data_ready;    //singal for sending data
reg[7:0]                         tx_cnt=0; 
wire[7:0]                        rx_data;          //receiving data
wire                             rx_data_valid;    // receiving data valid
wire                             rx_data_ready;    // singal for receiving data
reg[31:0]                        wait_cnt=0;
reg[3:0]                         state=0;          
wire                             sys_clk;          //single end clock
/*************************************************************************
generate single end clock
**************************************************************************/
IBUFDS sys_clk_ibufgds   
(
.O                      (sys_clk                  ),
.I                      (sys_clk_p                ),
.IB                     (sys_clk_n                )
);
assign rx_data_ready = 1'b1;//always can receive data,
							//if HELLO ALINX\r\n is being sent, the received data is discarded
/*************************************************************************
1 second sends a packet HELLO ALINX\r\n , FPGA has been receiving state
****************************************************************************/
always@(posedge sys_clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
	begin
		wait_cnt <= 32'd0;
		tx_data <= 8'd0;
		state <= IDLE;
		tx_cnt <= 8'd0;
		tx_data_valid <= 1'b0;
	end
	else
	case(state)
		IDLE:
			state <= SEND;
		SEND:
		begin
			wait_cnt <= 32'd0;
			tx_data <= tx_str;

			if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < 8'd12)//Send 12 bytes data
			begin
				tx_cnt <= tx_cnt + 8'd1; //Send data counter
			end
			else if(tx_data_valid && tx_data_ready)//last byte sent is complete
			begin
				tx_cnt <= 8'd0;
				tx_data_valid <= 1'b0;
				state <= WAIT;
			end
			else if(~tx_data_valid)
			begin
				tx_data_valid <= 1'b1;
			end
		end
		WAIT:
		begin
			wait_cnt <= wait_cnt + 32'd1;
            // 等待1s 数据的时候
			if(rx_data_valid == 1'b1) // 如果接收到数据
			begin
				tx_data_valid <= 1'b1; //使得发送数据使能,
				tx_data <= rx_data;   // send uart received data
			end
			else if(tx_data_valid && tx_data_ready)
			begin
				tx_data_valid <= 1'b0;
			end
			else if(wait_cnt >= clk_fre * 1000000) // wait for 1 second
				state <= SEND;
		end
		default:
			state <= IDLE;
	endcase
end
/*************************************************************************
combinational logic  Send "HELLO ALINX\r\n"
****************************************************************************/
always@(*)
begin
	case(tx_cnt)
		8'd0 :  tx_str <= "H";
		8'd1 :  tx_str <= "E";
		8'd2 :  tx_str <= "L";
		8'd3 :  tx_str <= "L";
		8'd4 :  tx_str <= "O";
		8'd5 :  tx_str <= " ";
		8'd6 :  tx_str <= "A";
		8'd7 :  tx_str <= "L";
		8'd8 :  tx_str <= "I";
		8'd9 :  tx_str <= "N";
		8'd10:  tx_str <= "X";
		8'd11:  tx_str <= "\r";
		8'd12:  tx_str <= "\n";
		default:tx_str <= 8'd0;
	endcase
end
/***************************************************************************
calling uart_tx module and uart_rx module
****************************************************************************/
uart_rx#
(
.clk_fre(clk_fre),
.baud_rate(115200)
) uart_rx_inst
(
.clk                        (sys_clk                  ),
.rst_n                      (rst_n                    ),
.rx_data                    (rx_data                  ),
.rx_data_valid              (rx_data_valid            ),
.rx_data_ready              (rx_data_ready            ),
.rx_pin                     (uart_rx                  )
);

uart_tx#
(
.clk_fre(clk_fre),
.baud_rate(115200)
) uart_tx_inst
(
.clk                        (sys_clk                  ),
.rst_n                      (rst_n                    ),
.tx_data                    (tx_data                  ),
.tx_data_valid              (tx_data_valid            ),
.tx_data_ready              (tx_data_ready            ),
.tx_pin                     (uart_tx                  )
);

endmodule


实验结果

仿真结果

4、vivado之uart串口数据发送与接收_第4张图片

仿真代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2020/08/01 10:50:48
// Design Name: 
// Module Name: vtl_uart_rx_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module vtl_uart_rx_test;
wire sys_clk_n;
reg sys_clk_p;
reg rst_n;
reg uart_rx;
wire uart_tx;


uart_top  uart_test(
    .sys_clk_p(sys_clk_p),
    .sys_clk_n(sys_clk_n),
    .rst_n(rst_n),
    .uart_rx(uart_rx),
    .uart_tx(uart_tx)
);

parameter bps_115200 = 86800;
parameter send_data = 8'b1010_0011;
integer i=0;
    initial begin
       sys_clk_p =0;
         #100;
         rst_n = 0;
         #100;
         rst_n =1;
        #100;
        uart_rx = 1'b1;
        #10000;
        uart_rx = 1'b0;
        
         
        for(i =0;i<8;i=i+1)
        #bps_115200 uart_rx = send_data[i];
        
        #bps_115200 uart_rx = 1'b0;
        #bps_115200 uart_rx = 1'b1;;
        #2000000; 
 
        
    end
    
    always #25 sys_clk_p <=~sys_clk_p; //此时的频率是200M
    assign sys_clk_n = ~sys_clk_p;


endmodule



上电测试

4、vivado之uart串口数据发送与接收_第5张图片

总结

相对全面的了解了FPGA中的串口的协议,以及fpga基本状态机的编写的过程,能否相对更加有经验的调试自己所编写的fpga 的程序。

你可能感兴趣的:(vivado,fpga,artix)