Verilog-UART串口通信协议

一、通信特点

uart :异步、串行、全双工

一般描述某种通信的特点为:同步/异步 , 串行/并行 , 半双工/全双工
同步:要求一个芯片控制另一芯片的时序,一般,两者之间至少采用一个总线连接以控制时钟(“时钟线”), 其中主机主动控制时钟线(通过时钟线输出),从机被动接受时钟线(通过时钟线输入)。
异步:双方不会通过总线连接时钟,异步通信要求双方使用独立的时钟生成装置(波特率发生器),生成相 同的通信速度。
串行:在每个数据方向上仅有一根数据线。每次仅传输一位数据。
并行:在每个数据方向上有多根数据线。每次可以传输数据的多个位(一般是8/16位)
半双工:数据线仅有一组,同一时刻,只有一方控制数据线的发送,另一方接收数据(即双方不能同时发送 数据)
全双工:数据线有两组或以上,同一时刻,通信双方都可以给对方发送数据。

二、uart协议介绍

uart:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是一种通用串行数据总线,用于异步通信。uart能实现双向通信,在嵌入式设计中,它常用于主机与辅助设备通信。uart包括RS232、RS449、RS432、RS422和RS485等接口标准规范和总线标准规范,既uart是异步串行通信口的的总称。而RS232、RS449、RS432、RS422和RS485等是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容,实际上属于通信网络中的物理层(最底层)的概念,与通信协议没有直接关系。(内容来源于《搭建你的数字积木-数字电路与逻辑设计》)
参数的意义如下:

  1. 波特率:是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数(每秒传输多少个比特位(bit))。典型的波特率有300, 1200, 2400, 9600, 19200, 115200等。一般通信两端设备都要设为相同的波特率。 具体波特率如下图所示。
    波特率计算: 特率生成,就是用一个定时器来定时,产生频率与对应波特率时钟频率相同的时钟信号。例如,我们使用波特率为115200bps,则我们需要产生一个频率为115200Hz的时钟,
    信号。那么如何产生这样一个115200Hz的时钟信号呢?这里,我们首先将115200Hz时钟信特率生成,就是用一个定时器来定时,产生频率与对应波特率时钟频率相同的时钟信号。例如,我们使用波特率为115200bps,则我们需要产生一个频率为115200Hz的时钟
    信号。那么如何产生这样一个115200Hz的时钟信号呢?这里,我们首先将115200Hz时钟信
    波特率:
波特率波特率周期波特率分频计数值
9600104167ns104164 / sys_clk_period
1920052083ns52083 / sys_clk_period
3840026041ns26041 / sys_clk_period
5760017361ns17361 / sys_clk_period
1152008680ns8680 / sys_clk_period
说明:sys_clk_period 为系统时钟周期
  1. 起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。
  2. 数据位:定义单个UART数据传输在开始到停止期间发送的数据位数。可以选择的值有5,6,7,8(默认)这四个值。这个参数最好为8,因为如果此值为其他的值时当你传输的是ASCII值时一般解析肯定会出问题。理由很简单,一个ASCII字符值为8位,如果一帧的数据位为7,那么还有一位就是不确定的值,这样就会出错。
  3. 校验位:用来验证数据的正确性。奇偶校验一般不使用,如果使用,则既可以做奇校验(Odd)也可以做偶校验(Even)。数据位加上奇偶校验后会被相应的置1或0(一般是最高位或最低位),数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。以传输“A”(01000001)为例。
    a. 当为奇数校验:”A”字符的8个bit位中有两个1,那么奇偶校验位为1才能满足1的个数为奇数(奇校验)。
    b. 当为偶数校验:”A”字符的8个bit位中有两个1,那么奇偶校验位为0才能满足1的个数为偶数(偶校验)。 此位还可以去除,即不需要奇偶校验位。
    c. 如果用户选择数据长度为8位,则因为没有多余的比特可被用来作为奇偶校验位,因此就叫做“无奇偶校验(Non)
  4. 停止位:它是一帧数据的结束标志。可以是1bit(默认)、1.5bit、2bit的空闲电平。
  5. 空闲位:没有数据传输时线路上的电平状态。为逻辑1。
  6. 传输方向:即数据是从高位(MSB)开始传输还是从低位(LSB)开始传输。比如传输“A”如果是MSB那么就是01000001,如果是LSB那么就是10000010。
  7. uart传输数据的顺序:刚开始传输一个起始位,接着传输数据位,接着传输校验位(可不需要此位),最后传输停止位。这样完整的一帧数据就传输完了。
  8. 帧间隔:即传送数据的帧与帧之间的间隔大小,可以以位为计量也可以用时间(知道波特率那么位数和时间可以换算)。比如传送”A”完后,这为一帧数据,再传”B”,那么A与B之间的间隔即为帧间隔。

三、RS232接口标准的Verilog代码实现

使用工具:ISE Design Suite 14.7
FPGA开发板: Basys2
波特率:9600 bit/s
实现的功能:
  指令一:PC端发送I like FPGA,开发板回应 I like FPGA, too. 在PC端显示。
  指令二:PC端发送I like Verilog,开发板回应 I like Verilog, too. 在PC端显示。
  RTL视图如下:

image

顶层设计代码
module top_uart_tx_rx(
	input					clk,
	input					rst_n,
	input					rs232_rx,
	
	output                  rs232_tx
    );
	//uart_rx
	wire		[7:0]   	rx_data;
	wire					rx_done;
	//uart_tx
	wire                    tx_finish;
	wire                    send_en;
    wire        [7:0]       data_tx;
	//rx_datadeal
	wire        tx_en1;
	wire        tx_en2;
	//tx_datadeal
	
	
	
uart_rx uart_rx(
     .clk     (clk) ,
	 .rst_n   (rst_n) ,
	 .rs232_rx(rs232_rx) ,
	 
	 .rx_data (rx_data) ,
	 .rx_done (rx_done) 
	);

uart_tx  uart_tx(
   .clk         (clk),              
   .rst_n       (rst_n),              
   .send_en     (send_en),              
   .data_tx     (data_tx),  
				
   .rs232_tx    (rs232_tx),              
   .tx_finish   (tx_finish)                           
);

tx_datadeal tx_datadeal( 
   .clk         (clk   ),              
   .rst_n       (rst_n ),
   .tx_en1      (tx_en1),
   .tx_en2      (tx_en2),
   .tx_finish   (tx_finish),   
   
   .send_en     (send_en),              
   .data_tx     (data_tx)
);

rx_datadeal rx_datadeal(
	.clk	   (clk)	,
	.rst_n     (rst_n)  ,
	.rx_data   (rx_data),
	.rx_done   (rx_done),
	
	.tx_en1    (tx_en1),
	.tx_en2    (tx_en2)
    );	
endmodule

接收数据处理代码
module rx_datadeal(
	input									clk			,
	input									rst_n       ,
	input					[7:0]			rx_data     ,
	input									rx_done     ,
	
	output reg 	                            tx_en1      ,
	output reg                              tx_en2
    );
	
    reg [3:0] data_cnt;
	reg [3:0] flag1;
	reg [3:0] flag2;
	
	always@(posedge clk or negedge rst_n)
	 begin
	   if(!rst_n)
	     data_cnt <= 4'd0;
	   else if(flag1 == 4'd11 || flag2 == 4'd14 )
	     data_cnt <= 4'd0;
	   else if(rx_done)
	     data_cnt <= data_cnt + 1'b1;
	 end
	
	//给tx的使能信号
	always@(posedge clk or negedge rst_n)
	begin
	 if(!rst_n)
	  begin
	   tx_en1 <= 1'b0;
	   tx_en2 <= 1'b0;
      end
	 else if(flag1 == 4'd11)
	   tx_en1 <= 1'b1;
	 else if(flag2 == 4'd14)
	   tx_en2 <= 1'b1;
	 else 
	    begin
	   tx_en1 <= 1'b0;
	   tx_en2 <= 1'b0;
      end
	end
	
	always@(posedge clk or negedge rst_n)
	 begin
	   if(!rst_n)
	     begin
		  flag1 <= 4'd0;
		  flag2 <= 4'd0;
		 end
	   else if(flag1 == 4'd11)
	      flag1 <= 4'd0;
	   else if(flag2 == 4'd14)
	      flag2 <= 4'd0;
	   else 
	     begin
		  case(data_cnt)
		    4'd0 :  begin 
		              if(rx_data == "I")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end
				    end
		    4'd1 :  begin 
		              if(rx_data == " ")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
		 
		    4'd2 :  begin 
		              if(rx_data == "L")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
		 
		    4'd3 :  begin 
		              if(rx_data == "i")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
			4'd4 :  begin 
		              if(rx_data == "k")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end
				    end
		    4'd5 :  begin 
		              if(rx_data == "e")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
		 
		    4'd6 :  begin 
		              if(rx_data == " ")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
		 
		    4'd7 :  begin 
		              if(rx_data == "F")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= 4'd0;
		                end
					  else if(rx_data == "V")
					     begin
						 flag1 <= 4'd0;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end		
					
			4'd8 :  begin 
		              if(rx_data == "P")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= 4'd0;
		                end
					  else if(rx_data == "e")
					     begin
						 flag1 <= 4'd0;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end
				    end
		    4'd9 :  begin 
		              if(rx_data == "G")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= 4'd0;
		                end
					  else if(rx_data == "r")
					     begin
						 flag1 <= 4'd0;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
		 
		    4'd10 :  begin 
		              if(rx_data == "A")
					    begin
						 flag1 <= flag1 + 1'b1;
		                 flag2 <= 4'd0;
		                end
					  else if(rx_data == "i")
					     begin
						 flag1 <= 4'd0;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
		 
		    4'd11 :  begin 
					  if(rx_data == "l")
					     begin
						 flag1 <= 4'd0;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end		
			4'd12 :  begin 
		               if(rx_data == "o")
					     begin
						 flag1 <= 4'd0;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end
				    end
		    4'd13 :  begin
                      if(rx_data == "g")
					    begin
						 flag1 <= 4'd0;
		                 flag2 <= flag2 + 1'b1;
		                end
		              else
		                begin
						 flag1 <= flag1;
		                 flag2 <= flag2;
		                end 
		            end
		    default : begin
			                flag1 <= 4'd0;
							flag2 <= 4'd0;
					   end
		   endcase
		 end
	 
	 
	 end
	


endmodule
接收代码
module uart_rx(clk,rst_n,rs232_rx,rx_data,rx_done);
     input                 clk;
	 input                 rst_n;
	 input                 rs232_rx;
	 output   reg  [7:0]   rx_data;
	 output   reg          rx_done;
	 
	 reg  [1:0]s_rs232_rx;//消除亚稳态
	 reg  [1:0]tmp_rs232_rx;//数据寄存器
	 
	 wire      nedge;
	 reg  [15:0]div_cnt;//分频计数器
	 reg       bps_clk;
	 reg       uart_state;
	 reg  [7:0]bps_cnt;
	 
	 reg  [2:0]start_bit;
	 reg  [2:0]stop_bit;
	 reg  [2:0]rx_data_t [7:0];
	 //                    地址宽度
	 always@(posedge clk or negedge rst_n)
	  if(!rst_n)
	    s_rs232_rx <= 0;
	  else  begin
	    s_rs232_rx[0] <= rs232_rx;
		s_rs232_rx[1] <= s_rs232_rx[0];
	   end
	   
	always@(posedge clk or negedge rst_n)
	  if(!rst_n)
	    tmp_rs232_rx <= 0;
	  else  begin
	    tmp_rs232_rx[0] <= s_rs232_rx[1];
		tmp_rs232_rx[1] <= tmp_rs232_rx[0];
	   end
	 assign nedge = tmp_rs232_rx[1] & ~tmp_rs232_rx[0];
	 
	 
	 always@(posedge clk or negedge rst_n)
	  if(!rst_n)
	   div_cnt <= 16'd0;
	  else if(uart_state == 1) begin
	    if(div_cnt == 325)
	     div_cnt <= 16'd0;
	    else 
	     div_cnt <= div_cnt + 1;
	   end
	  else 
	    div_cnt <= 0;
		
	 always@(posedge clk or negedge rst_n) 
	   if(!rst_n)
	     bps_clk <= 1'b0;
	   else if(div_cnt == 16'b1)
	     bps_clk <= 1'b1;
	   else 
	     bps_clk <= 1'b0;
	  
	 always@(posedge clk or negedge rst_n)
	   if(!rst_n)
	     uart_state <= 1'b0;
	   else if(nedge)
	     uart_state <= 1'b1;
	   else if(rx_done || (bps_cnt == 8'd12 && start_bit > 2))
	     uart_state <= 1'b0;
	   else
	     uart_state <= uart_state;
	
		 
	 always@(posedge clk or negedge rst_n)
	   if(!rst_n)
	     bps_cnt <= 0;
	   else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && start_bit > 2))
	     bps_cnt <= 0;
	   else if(bps_clk == 1)
	     bps_cnt <= bps_cnt + 1;
	   else 
	     bps_cnt <= bps_cnt;
	 
	 always@(posedge clk or negedge rst_n)
	   if(!rst_n) begin
	     rx_done <= 1'b0;
		end
	   else if(bps_cnt == 8'd159) begin
	     rx_done <= 1'b1;
        end
	   else  begin
	     rx_done <= 1'b0;
		end
	 
	 always@(posedge clk or negedge rst_n)
	   if(!rst_n)  begin
	     start_bit <= 3'd0;
	     rx_data_t[0] <= 3'd0;
		 rx_data_t[1] <= 3'd0;
		 rx_data_t[2] <= 3'd0;
		 rx_data_t[3] <= 3'd0;
		 rx_data_t[4] <= 3'd0;
		 rx_data_t[5] <= 3'd0;
		 rx_data_t[6] <= 3'd0;
		 rx_data_t[7] <= 3'd0;
		 stop_bit <= 3'd0;
		end
	   else if(bps_clk == 1) begin
	     case(bps_cnt)
		   0:begin
		      start_bit <= 3'd0;
	          rx_data_t[0] <= 3'd0;
		      rx_data_t[1] <= 3'd0;
		      rx_data_t[2] <= 3'd0;
		      rx_data_t[3] <= 3'd0;
		      rx_data_t[4] <= 3'd0;
		      rx_data_t[5] <= 3'd0;
		      rx_data_t[6] <= 3'd0;
		      rx_data_t[7] <= 3'd0;
		      stop_bit <= 3'd0;
			 end
           5,6,7,8,9,10: start_bit <= start_bit + s_rs232_rx[1];
           21,22,23,24,25,26: rx_data_t[0] <= rx_data_t[0] + s_rs232_rx[1];	
           37,38,39,40,41,42: rx_data_t[1] <= rx_data_t[1] + s_rs232_rx[1];	
           53,54,55,56,57,58: rx_data_t[2] <= rx_data_t[2] + s_rs232_rx[1];	
           69,70,71,72,73,74: rx_data_t[3] <= rx_data_t[3] + s_rs232_rx[1];	
           85,86,87,88,89,90: rx_data_t[4] <= rx_data_t[4] + s_rs232_rx[1];	
           101,102,103,104,105,106: rx_data_t[5] <= rx_data_t[5] + s_rs232_rx[1];
           117,119,120,121,122,123: rx_data_t[6] <= rx_data_t[6] + s_rs232_rx[1];
           133,135,136,137,138,139:	rx_data_t[7] <= rx_data_t[7] + s_rs232_rx[1];	
		   149,151,152,153,154,155: stop_bit <= stop_bit + s_rs232_rx[1];
         endcase		   
	    end
	    
     always@(posedge clk or negedge rst_n)
      if(!rst_n)
       	rx_data <= 8'd0;
	  else if(bps_cnt == 159)  begin
	    rx_data[0] <= rx_data_t[0][2];
		rx_data[1] <= rx_data_t[1][2];
		rx_data[2] <= rx_data_t[2][2];
		rx_data[3] <= rx_data_t[3][2];
		rx_data[4] <= rx_data_t[4][2];
		rx_data[5] <= rx_data_t[5][2];
		rx_data[6] <= rx_data_t[6][2];
		rx_data[7] <= rx_data_t[7][2];
	   end
	 
endmodule
发送数据处理代码
module tx_datadeal(
 input    		clk,
 input 			rst_n,
 input 			tx_finish,
 input          tx_en1,
 input          tx_en2,
 
 output reg 		send_en,
 output reg [7:0]   data_tx
 
    );
//define	
reg [4:0] data_cnt;
reg tx_state1;
reg tx_state2;

always@(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
     tx_state1 <= 1'b0;
	 tx_state2 <= 1'b0;
   end
  else if(tx_en1)
     tx_state1 <= 1'b1;
  else if(tx_en2)
     tx_state2 <= 1'b1;
  else if(data_cnt  == 5'd15)
     tx_state1 <= 1'b0;  
  else if(data_cnt  == 5'd18)
     tx_state2 <= 1'b0; 
  else 
    begin
     tx_state1 <= tx_state1;
	 tx_state2 <= tx_state2;
   end
 
 end
 
 //data_cnt
always@(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   data_cnt <= 5'd0;
  else if(tx_state1 == 1'b1 && data_cnt == 5'd15)
   data_cnt <= 5'd0;
  else if(tx_state2 == 1'b1 && data_cnt == 5'd18)
   data_cnt <= 5'd0;
  else if(tx_finish)
   data_cnt <= data_cnt + 1'b1;
  else 
   data_cnt <= data_cnt;
end 

 //send_en
always@(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   send_en <= 1'b0;
  else if(tx_en1 || tx_en2)
   send_en <= 1'b1;
  else if(tx_finish)
    begin
		if(tx_state1)
		  begin
            if(data_cnt < 5'd14)
                send_en <= 1'b1;
            else
                send_en <= 1'b0;
		  end
		else if(tx_state2)
		  begin
            if(data_cnt < 5'd17)
                send_en <= 1'b1;
            else
                send_en <= 1'b0;
		  end
    end
   else
         send_en <= 1'b0;
    end
 
always@(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   data_tx <= 8'd0;
  else if(tx_state1) 
    begin 
     case(data_cnt)
	  5'd0 : data_tx <= "I";
	  5'd1 : data_tx <= " ";
	  5'd2 : data_tx <= "L";
	  5'd3 : data_tx <= "i";
	  5'd4 : data_tx <= "k";
	  5'd5 : data_tx <= "e";
	  5'd6 : data_tx <= " ";
	  5'd7 : data_tx <= "F";
	  5'd8 : data_tx <= "P";
	  5'd9 : data_tx <= "G";
	  5'd10 : data_tx <= "A";
	  5'd11 : data_tx <= ",";
	  5'd12 : data_tx <= "t";
	  5'd13 : data_tx <= "o";
	  5'd14 : data_tx <= "o";
      default : data_tx <= 8'd0;
    endcase
   end
  else if(tx_state2) 
   begin 
    case(data_cnt)
	  5'd0 : data_tx <= "I";
	  5'd1 : data_tx <= " ";
	  5'd2 : data_tx <= "L";
	  5'd3 : data_tx <= "i";
	  5'd4 : data_tx <= "k";
	  5'd5 : data_tx <= "e";
	  5'd6 : data_tx <= " ";
	  5'd7 : data_tx <= "V";
	  5'd8 : data_tx <= "e";
	  5'd9 : data_tx <= "r";
	  5'd10 : data_tx <= "i";
	  5'd11 : data_tx <= "l";
	  5'd12 : data_tx <= "o";
	  5'd13 : data_tx <= "g";
	  5'd14 : data_tx <= ",";
	  5'd15 : data_tx <= "t";
	  5'd16 : data_tx <= "o";
	  5'd17 : data_tx <= "o";
     default : data_tx <= 8'd0;
    endcase
   end
  else
    data_tx <= 8'd0;
 end
endmodule

发送代码
module uart_tx(clk,rst_n,tx_finish,send_en,rs232_tx,uart_state,data_tx);
    input                               clk                        ;
    input                               rst_n                      ;
    input                               send_en                    ;//发送使能信号
    input              [   7:0]         data_tx                    ;//发送字节
	
    output reg                          rs232_tx                   ;
    output reg                          tx_finish                  ;
    output reg                          uart_state                 ;

reg                                     bps_clk                    ;//波特率时钟
reg                    [  15:0]         div_cnt                    ;//分频计数器
reg                    [  15:0]         bps_DR = 5207              ;//分频计数最大值
reg                    [   3:0]         bps_cnt                    ;//波特率计数时钟
reg                    [   7:0]         r_data_tx                  ;
	
localparam                              START_BYTE = 1'b0          ;
localparam                              STOP_BYTE  = 1'b1          ;
	
	//控制信号
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        uart_state <= 1'b0;
    else if(send_en)
        uart_state <= 1'b1;
    else if(bps_cnt == 4'd11)
        uart_state <= 1'b0;
    else
        uart_state <= uart_state;
		
	//寄存器存储发送信息
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        r_data_tx <= 1'b0;
    else if(uart_state)
        r_data_tx <= data_tx;
    else
        r_data_tx <= r_data_tx;
	
	//counter
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        div_cnt <= 16'd0;
    else if(uart_state)
    begin
        if(div_cnt == bps_DR)
            div_cnt <= 16'd0;
        else
            div_cnt <= div_cnt + 1'b1;
    end
    else
        div_cnt <= 16'd0;
	//产生bps_clk
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        bps_clk <= 1'b0;
    else if(div_cnt == 16'd1)
        bps_clk <= 1'd1;
    else
        bps_clk <= 1'b0;
		
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        bps_cnt <= 4'd0;
    else if(bps_cnt == 4'd11)
        bps_cnt <= 4'd0;
    else if(bps_clk)
        bps_cnt <= bps_cnt + 1'b1;
    else
        bps_cnt <= bps_cnt;
	//产生发送完成信号
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        tx_finish <= 1'b0;
    else if(bps_cnt == 4'd11)
        tx_finish <= 1'b1;
    else
        tx_finish <= 1'b0;
	//发送模块
    always@(posedge clk or negedge rst_n)
    if(!rst_n)
        rs232_tx <= 1'b1;
    else
    begin
        case(bps_cnt)
            0:rs232_tx <= 1'b1;
            1:rs232_tx <= START_BYTE;                               //0
            2:rs232_tx <= r_data_tx[0];
            3:rs232_tx <= r_data_tx[1];
            4:rs232_tx <= r_data_tx[2];
            5:rs232_tx <= r_data_tx[3];
            6:rs232_tx <= r_data_tx[4];
            7:rs232_tx <= r_data_tx[5];
            8:rs232_tx <= r_data_tx[6];
            9:rs232_tx <= r_data_tx[7];
            10:rs232_tx <= STOP_BYTE;                               //1
            default:rs232_tx <= 1'b1;
        endcase
    end
endmodule

TESTBENCH
module tb_uart_tx_rx;

	// Inputs
	reg clk;
	reg rst_n;
	reg rs232_rx;

	// Outputs
	wire rs232_tx;

	// Instantiate the Unit Under Test (UUT)
	top_uart_tx_rx uut (
		.clk(clk), 
		.rst_n(rst_n), 
		.rs232_rx(rs232_rx), 
		.rs232_tx(rs232_tx)
	);
   	parameter period=20,
			  RST_ING=1'b0,
			  BPS_9600=32'd104_167;
	initial begin
		// Initialize Inputs
		clk = 0;
		forever
			#(period/2)clk=~clk;
	end


	
	reg	[4:0]	cnt;
	reg	[7:0]	data_tx;
	initial	begin
	rst_n = RST_ING;
	#5000;
	rst_n = ~RST_ING;
	
	rs232_rx = 1'b1;
	
//I Like FPGA	
	#1000_000;
	data_tx = "I";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = " ";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "L";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "i";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "k";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "e";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = " ";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "F";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "P";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "G";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "A";
	tx_task(data_tx);

	//I Like Verilog
	#100_000_000;
	data_tx = "I";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = " ";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "L";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "i";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "k";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "e";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = " ";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "V";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "e";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "r";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "i";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "l";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "o";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "g";
	tx_task(data_tx);

//I Like FPGA	
	#100_000_000;
	data_tx = "I";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = " ";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "L";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "i";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "k";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "e";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = " ";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "F";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "P";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "G";
	tx_task(data_tx);
	
	#1000_000;
	data_tx = "A";
	tx_task(data_tx);
	end	
   	
	task tx_task;
		input	[7:0]	rs232_tx;
		integer i;
		begin
			rs232_rx = 0;
			#BPS_9600;
			for(i = 0;i < 8;i = i+1)	begin
				rs232_rx = data_tx[i];
				#BPS_9600;
			end
			rs232_rx = 1;
			#BPS_9600;
		end
	endtask

endmodule

仿真图如下:
image

本篇博文为记录学习所用,如有错误,请各位指正批评,如有转载请注明出处。

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值