FPGA串口多字节接收、解码和仿真

本项目采用Altera的FPGA,串口多字节接收,并解码以及采用ModelSim进行仿真。串口接收程序源自正点原子的例程。

程序基本框架

程序分为两个部分,单字节接收部分和多字节接收及解码部分,其中单字节接收部分参考资料比较多,收到单字节数据并给出完成标志位;多字节接收在此基础上进行若干个字节的接收,并给出标志位,通过解码模块对数据进行解码。

程序源码

采用Quartus II开发环境,频率50MHz,波特率 115200,8位数据位,1位停止位。
由于手头核心板比较奇怪,是高电平复位,因此程序中复位信号是上升沿,修改一下即可。

module uart_top(
    input			    sys_clk,                  //系统时钟
    input             sys_rst_n,                //系统复位,低电平有效
    input             uart_rxd,                 //UART接收端口

	 output  reg [ 7:0] uart_data,	
	 output  reg        uart_done,
	 output  reg        uart_get,               //采样点
	 
	 output  reg [7:0] pack_cnt,                //字节计数
	 output  reg       pack_ing, 	            //接收过程标志位
	 output  reg       pack_done,               //帧接收完成标志位
	 output  reg [7:0] pack_num,                //接收到的字节数
	 output  reg       recv_done,              //接收完一帧数据的接收和解码
	 output  reg [7:0]  dataA,                 //解码后数据
	 output  reg [15:0] dataB,                 //解码后数据
     output  reg [15:0] dataC                  //解码后数据
    );
    
localparam  DATA_NUM = 8;
integer j;

reg [7:0] pack_data [DATA_NUM-1:0];           //接收的数据
//parameter define
parameter  CLK_FREQ = 50_000_000;                 //系统时钟频率
parameter  UART_BPS = 115200;                     //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率
 
localparam  TimeOut = BPS_CNT*DATA_NUM*10*2;//超时时间

//起始信号下降沿捕捉
wire       start_flag;
reg        uart_rxd_d0;
reg        uart_rxd_d1;

reg [15:0] clk_cnt;                             //系统时钟计数器
reg [ 3:0] rx_cnt;                              //接收数据计数器
reg        rx_flag;                             //接收过程标志信号
reg [ 7:0] rxdata;                              //接收数据寄存器

//接收信号完成标志位上升沿
wire  rxdone_flag;
reg   uart_done_d0;
reg   uart_done_d1;
//包数据接收完成
wire  packdone_flag;
reg   pack_done_d0;
reg   pack_done_d1;

//*****************************************************
//**                    main code
//*****************************************************
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    
//对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or posedge sys_rst_n) begin 
    if (sys_rst_n) begin 
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;          
    end
    else begin
        uart_rxd_d0  <= uart_rxd;                   
        uart_rxd_d1  <= uart_rxd_d0;
    end   
end
//当脉冲信号start_flag到达时,进入接收过程           
always @(posedge sys_clk or posedge sys_rst_n) begin         
    if (sys_rst_n)                                  
        rx_flag <= 1'b0;
    else begin
        if(start_flag)                          //检测到起始位
            rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
        else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))
            rx_flag <= 1'b0;                    //计数到停止位中间时,停止接收过程
        else
            rx_flag <= rx_flag;
    end
end
//进入接收过程后,启动系统时钟计数器与接收数据计数器
always @(posedge sys_clk or posedge sys_rst_n) begin         
    if (sys_rst_n) begin                             
        clk_cnt <= 16'd0;                                  
        rx_cnt  <= 4'd0;
    end                                                      
    else if ( rx_flag ) begin                   //处于接收过程
            if (clk_cnt < BPS_CNT - 1) begin
                clk_cnt <= clk_cnt + 1'b1;
                rx_cnt  <= rx_cnt;
            end
            else begin
                clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
                rx_cnt  <= rx_cnt + 1'b1;       //此时接收数据计数器加1
            end
        end
        else begin                              //接收过程结束,计数器清零
            clk_cnt <= 16'd0;
            rx_cnt  <= 4'd0;
        end
end
//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or posedge sys_rst_n) begin 
    if (sys_rst_n)  begin
        rxdata <= 8'd0;     
		  uart_get<=1'b0;		
	 end  
    else if(rx_flag)                            //系统处于接收过程
        if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
            case ( rx_cnt )
             4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
             4'd2 : rxdata[1] <= uart_rxd_d1;
             4'd3 : rxdata[2] <= uart_rxd_d1;
             4'd4 : rxdata[3] <= uart_rxd_d1;
             4'd5 : rxdata[4] <= uart_rxd_d1;
             4'd6 : rxdata[5] <= uart_rxd_d1;
             4'd7 : rxdata[6] <= uart_rxd_d1;
             4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
             default:;                                    
            endcase
				uart_get<=1'b1;	
        end
        else  begin
            rxdata <= rxdata;
				uart_get<=1'b0;	
		  end
    else begin
        rxdata <= 8'd0;
		  uart_get<=1'b0;	
	 end
end


//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or posedge sys_rst_n) begin        
    if (sys_rst_n) begin
        uart_data <= 8'd0;                               
        uart_done <= 1'b0;
    end
    else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
        uart_data <= rxdata;                    //寄存输出接收到的数据
        uart_done <= 1'b1;                      //并将接收完成标志位拉高
    end
    else begin
        uart_data <= 8'd0;                                   
        uart_done <= 1'b0; 
    end    
end

//---单字节接收程序,uart_done接收完成标志位会持续半个波特率周期,捕捉上升沿可以计数,高电平状态,接收数据有效
//==============================================接收多个字节,添加的模块====================================================//

//捕获接收完成标志位的上升沿,得到一个时钟周期的脉冲信号
assign  rxdone_flag = uart_done_d0 & (~uart_done_d1);    
//对UART完成标志的数据延迟两个时钟周期
always @(posedge sys_clk or posedge sys_rst_n) begin 
    if (sys_rst_n) begin 
        uart_done_d0 <= 1'b0;
        uart_done_d1 <= 1'b0;          
    end
    else begin
        uart_done_d0  <= uart_done;                   
        uart_done_d1  <= uart_done_d0;
    end   
end

//接收到的数据存入数组中,并计数
always @(posedge sys_clk or posedge sys_rst_n) begin      //接收到数据  
    if (sys_rst_n) begin                             
		  pack_cnt <=8'd0;
		  pack_num <=8'd0;
		  pack_done<=1'b0; 
		  pack_ing <=1'b0;
		  for (j=0;j<DATA_NUM;j=j+1) 
		    pack_data[j] <= 8'd0;		 
    end
	 else if(rxdone_flag) begin //接收完成标志位的上升沿,延迟了两个时钟周期
		 if (pack_cnt < DATA_NUM-1) begin       //处于接收过程中
				 for (j=0;j<DATA_NUM;j=j+1) begin
				     if(j==pack_cnt)
					    pack_data[pack_cnt] <= uart_data;//寄存输出接收到的数据
					  else
					    pack_data[j] <= pack_data[j];	
				 end
				 pack_cnt  <= pack_cnt + 1'b1; 
             pack_num <= 8'd0;	
		       pack_done<=1'b0; 
		       pack_ing <=1'b1;		 
		 end
		 else begin //接收完成---最后一个字节的接收
				 for (j=0;j<DATA_NUM;j=j+1) begin
				     if(j==pack_cnt)
					  pack_data[pack_cnt] <= uart_data;//寄存输出接收到的数据
					  else
					  pack_data[j] <= pack_data[j];	
				 end
				 pack_num <= pack_cnt + 1'b1; //加上最后一个字节
			    pack_cnt  <= 8'd0;               //此时接收数据计数器归零,只有接收完成时才清零
				 pack_done<=1'b1;      			 //输出帧接收完成标志位,只存在一个周期
				 pack_ing <=1'b0;
		 end  
	 end
	 else begin
		  pack_cnt <=pack_cnt;
		  pack_ing <=pack_ing;//保持
		  pack_num <=pack_num;
		  pack_done<=1'b0;  
		  for (j=0;j<DATA_NUM;j=j+1) 
		    pack_data[j] <= pack_data[j];	
	 end
end


//------------解码-------------------------//
//捕获接收完成标志位的上升沿,得到一个时钟周期的脉冲信号
assign  packdone_flag = pack_done_d0 & (~pack_done_d1);    
//对UART完成标志的数据延迟两个时钟周期
always @(posedge sys_clk or posedge sys_rst_n) begin 
    if (sys_rst_n) begin 
        pack_done_d0 <= 1'b0;
        pack_done_d1 <= 1'b0;          
    end
    else begin
        pack_done_d0  <= pack_done;                   
        pack_done_d1  <= pack_done_d0;
    end   
end

always @(posedge sys_clk or posedge sys_rst_n) begin         
    if (sys_rst_n) begin                             
       dataA <= 8'd0; 
		 dataB <= 16'd0;
		 dataC <=16'd0;
		 recv_done <=1'b0;
    end  
	 else if(packdone_flag) begin //数据接收完成,进行解码
		 if(pack_num==DATA_NUM && pack_data[0]==8'h55 && pack_data[6]==8'h0d && pack_data[7]==8'h0a ) begin  //判断数据正误
			 dataA <=pack_data[1];
			 dataB <= {pack_data[3],pack_data[2]};
			 dataC <= {pack_data[5],pack_data[4]};
			 recv_done <=1'b1;
		 end  
		 else begin //数据错误
			 dataA <= 8'd1; 
			 dataB <= 16'd0;
			 dataC <=16'd0;
			 recv_done <=1'b0;
		 end
	 end
	 else begin //数据保持到下一个周期,标志位保持一个周期
		 dataA <= dataA; 
		 dataB <= dataB;
		 dataC <=dataC;
		 recv_done <=1'b0;
	 end	 
end


endmodule	

ModelSim仿真

仿真发送两包数据,每包数据八个字节,数据格式为 55 12 13 14 15 16 0d 0a

`timescale 1ns / 1ps
// Description: 测试串口
// Dependencies:
module uart_top_vlg_tst();
//==========================================================================
//wire and reg 定义:信号与参数
//==========================================================================
	// input to module
	reg       sim_clk;		//模拟时钟信号
	//reg     tx_pulse;     // active posedge
	reg 	    sim_rst_n;
	reg       uart_rxd;		//串口发送信号线

	//output from module
	wire [7:0] rx_data;		//送入串口发送模块,准备发送的数据
	wire       rx_en;       //串口接收数据有效,接收完成拉高1个BPS
	wire       rx_get;
	 wire [7:0] pack_cnt;  
	 wire       pack_done; 
	 wire       pack_ing;
	 wire [7:0] pack_num;
	 
	 wire        recv_done;
	 wire [7:0]  dataA;               
	 wire [15:0] dataB;            
	 wire [15:0] dataC;
  
	//时钟参数
	parameter SYS_CLK_FRE = 50_000_000;     //系统频率50MHz  40_000_000
	parameter SYS_CLK_PERIOD = 1_000_000_000/SYS_CLK_FRE;  //周期20ns
	//波特率参数
  	parameter BAUD_RATE = 230400; 	//串口波特率
	parameter BAUD_RATE_PERIOD	= 1_000_000_000/BAUD_RATE;

//==========================================================================
//模拟时钟信号
//==========================================================================
	//模拟系统时钟:50MHz,20ns
	always #((SYS_CLK_PERIOD)/2) sim_clk = ~sim_clk; //延时,电平翻转
	//模拟系统时钟:40MHz,25ns
//	always #((SYS_CLK_PERIOD+1)/2-1) sim_clk = ~sim_clk; //延时,电平翻转
	
	initial	begin
		//模拟复位信号:一次,低电平5个clk
		#0;
			sim_clk = 1'b0;
			sim_rst_n = 1'b1;      //复位
		#BAUD_RATE_PERIOD;		   
			sim_rst_n = 1'b0;      //解除复位

		//==========================================================================
		//模拟串口接收:串行信号输入,转化成并行数据,并显示
		//==========================================================================			
		uart_rxd = 1'b1;	   //串口发送线,默认拉高
		#BAUD_RATE_PERIOD; 						//直接延时,一个波特率周期
		$display("Initialization complete. BAUD_RATE is %d",BAUD_RATE); //命令行显示初始化完成,输出BPS_NUM
		
//一帧数据		
$display("The first byte...");
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h55=8'b0101_0101
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 		
		$display("The uart_rxd 8'h55=8'b0101_0101 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
//一帧数据	
$display("The second byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h12=8'b0001_0010
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 	
		$display("The uart_rxd 8'h12=8'b0001_0010 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
//一帧数据	
$display("The third byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h13=8'b0001_0011
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 
		$display("The uart_rxd 8'h13=8'b0001_0011 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
$display("The 4 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h14=8'b0001_0100
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 
		$display("The uart_rxd 8'h14=8'b0001_0100 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据	
$display("The 5 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h15=8'b0001_0101
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 	
		$display("The uart_rxd 8'h15=8'b0001_0101 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据	

$display("The 6 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h16=8'b0001_0110
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 	
		$display("The uart_rxd 8'h16=8'b0001_0110 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
$display("The 7 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h0d=8'b0000_1101
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 		
		$display("The uart_rxd 8'h0d=8'b0000_1101 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
$display("The 8 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h0a=8'b0000_1010
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;		   	#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;	   		#BAUD_RATE_PERIOD; 		
		$display("The uart_rxd 8'h0a=8'b0000_1010 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
			
//------------------第二包数据------------------------//
$display("The second package...");			
//一帧数据		
$display("The first byte...");
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h55=8'b0101_0101
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 		
		$display("The uart_rxd 8'h55=8'b0101_0101 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
//一帧数据	
$display("The second byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h32=8'b0011_0010
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 	
		$display("The uart_rxd 8'h32=8'b0011_0010 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
//一帧数据	
$display("The third byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h33=8'b0011_0011
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 
		$display("The uart_rxd 8'h33=8'b0011_0011 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
$display("The 4 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h34=8'b0011_0100
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 
		$display("The uart_rxd 8'h34=8'b0011_0100 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据	
$display("The 5 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h35=8'b0001_0101
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 	
		$display("The uart_rxd 8'h35=8'b0011_0101 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据	

$display("The 6 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h36=8'b0001_0110
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;     		#BAUD_RATE_PERIOD; 	
		$display("The uart_rxd 8'h36=8'b0011_0110 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
$display("The 7 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h0d=8'b0000_1101
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b1;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;			   #BAUD_RATE_PERIOD; 		
		$display("The uart_rxd 8'h0d=8'b0000_1101 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据
$display("The 8 byte...");	
		//发送数据----起始位
			uart_rxd = 1'b0;			#BAUD_RATE_PERIOD;	
		//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
		//测试数据为8'h0a=8'b0000_1010
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 		
			uart_rxd = 1'b1;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;				#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;		   	#BAUD_RATE_PERIOD; 
			uart_rxd = 1'b0;	   		#BAUD_RATE_PERIOD; 		
		$display("The uart_rxd 8'h0a=8'b0000_1010 has been sent.");  //命令行显示:串口信号线数据已发送
		//发送数据----停止位
			uart_rxd = 1'b1;	
		#(BAUD_RATE_PERIOD/3);//为了显示
			$display("The uart_rxd has received. rx_data = 8'h%h",rx_data);  
		#(BAUD_RATE_PERIOD*2/3);
		//命令行显示:串口信号线接收已结束,显示接收到的数据

	   #BAUD_RATE_PERIOD;
		#BAUD_RATE_PERIOD;
		$stop;		//结束仿真
		
	end

//==========================================================================
//调用top模块
//==========================================================================
//串口接收
 
uart_top #(
	.CLK_FREQ   (SYS_CLK_FRE), //系统时钟
	.UART_BPS   (  BAUD_RATE )  // 时钟/波特率,1 bit位宽所需时钟周期的个数
)
  u_uart_top(
	.sys_clk     (sim_clk),
	.sys_rst_n   (sim_rst_n),
	.uart_done   (rx_en),
	.uart_rxd    (uart_rxd),
	.uart_data   (rx_data),
	.uart_get    (rx_get),
	.pack_cnt    (pack_cnt),
	.pack_done   (pack_done),
	.pack_ing    (pack_ing),
	.pack_num    (pack_num),
	.recv_done   (recv_done),
	.dataA      (dataA),
	.dataB      (dataB),
	.dataC      (dataC)		
  );  

endmodule

FPGA串口多字节接收、解码和仿真_第1张图片
致谢参考:

https://blog.csdn.net/nomil9/article/details/106763694?spm=1001.2014.3001.5501

你可能感兴趣的:(FPGA,fpga,串口通信)