UART串口发送一个字节

455 阅读3分钟

UART串口发送一个字节

  1. 什么是UART?
    UART代表通用异步收发传输器。它是微控制器内部的硬件外围设备。能够将传入和传出的数据转换为串行二进制流。使用串行到并行转换,将从外围设备接收的8位串行数据转换为并行形式。UART是一种通用串行数据总线,用于异步通信,该总线双向通信,可以实现全双工传输和接收,并以定义的波特率传输。
  2. 什么是波特率?
    由于设备的发送端和接收端需要采用同样的速率,防止数据的丢失,于是在这里提出了波特率,即计算机在串口通信时的速率。也可以说是对信号的传输速率,或者是说线路状态改变的次数。
  3. UART通信协议
    UART作为异步串口通信协议的一种,工作原理是将传输数据的每一个字符一位一位地传输。其中包括起始位、数据位、终止位。
    在这里插入图片描述
    包含一个起始位START和八个数据位以及终止位STOP.

串口发生模块包括两个主要部件:
1.发送波特率生成模块
2.数据发送模块
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据模块化的方式进行verilog编写

		module uart_byte_tx(
	    Clk,
		 Rst_n,
		 send_en,
		 data_byte,
		 band_set,
		  Rs232_Tx,
		 Tx_Done,
		 uart_state
	);
   input  Clk;
   input  Rst_n;
	input  [7:0]data_byte;
	input  send_en;
	input  [2:0]band_set;
	
	output reg Rs232_Tx;
	output reg Tx_Done; //表示发送完成信号
	output reg uart_state;
	
	reg [15:0] div_cnt; //分频计数器
	reg bps_clk;
	reg [15:0] bps_DR;//分频计数最大值
	reg [3:0] bps_cnt;//波特率计数时钟	
	reg [7:0] r_data_byte;
	localparam START_BIT = 1'b0;
	localparam STOP_BIT = 1'b1;
	
	
//r_uart_state模块的实现,为了产生控制信号,让分频计数模块进行工作
	always@(posedge Clk or negedge Rst_n)
	  if(!Rst_n)
	    uart_state <= 1'b0;
	  else if(send_en) 
	    uart_state <= 1'b1;
	  else if(Tx_Done)
	    uart_state <= 1'b0;
	  else
	    uart_state <= uart_state;
			
			//实现当有send_en信号时,进行data_byte的寄存,不管外部信号怎么变都不会对数据改变,只有send_en出现
  always@(posedge Clk or negedge Rst_n)
	  if(!Rst_n)
	    r_data_byte <= 8'b0; 
	  else if(send_en)
       r_data_byte <= data_byte;
	  else 
	     r_data_byte <= r_data_byte;
		  
		  
		  
//实现DR_LUT模块的功能	(查找表)产生分频计数值的输出
	always@(posedge Clk or negedge Rst_n)
	  if(!Rst_n)
	     bps_DR <= 16'd5207;
	  else begin
	    case(band_set)
          0:bps_DR <= 16'd5207;
			 1:bps_DR <= 16'd2603;
			 2:bps_DR <= 16'd1301;
			 3:bps_DR <= 16'd867;
			 4:bps_DR <= 16'd433;
			default: bps_DR <= 16'd5207;
	  endcase
	  
	  end
		

	
//开始进行逻辑设计



//首先进行分频计数器的设计	
	always@(posedge Clk or negedge Rst_n)
	   if(!Rst_n)
		    div_cnt <= 16'd0;
		else if(uart_state) begin //uart_state相当于en_cnt
	
			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'b1)
		  bps_clk <= 1'b1;
		else 
		  bps_clk <= 1'b0;
		  
//将bps_clk信号送到bsp_cnt模块
	always@(posedge Clk or negedge Rst_n)
	  if(!Rst_n)
		bps_cnt <= 4'd0;
	  else if(Tx_Done)
		bps_cnt <= 4'd0;
	  else if(bps_clk)
       bps_cnt <= bps_cnt + 1'b1;
	  else
	    bps_cnt <= bps_cnt;
		 
//编写r_Tx_Done	,产生发送完成信号Tx_Done		 
	always@(posedge Clk or negedge Rst_n)
	  if(!Rst_n)
	    Tx_Done	<= 1'b0;
	  else if(bps_cnt == 4'b11)//可以实现比较器的功能
  	     Tx_Done	<= 1'b1;
		else
		  Tx_Done	<= 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_BIT;
		    2:Rs232_Tx <= r_data_byte[0];
			 3:Rs232_Tx <= r_data_byte[1];
			 4:Rs232_Tx <= r_data_byte[2];
			 5:Rs232_Tx <= r_data_byte[3];
			 6:Rs232_Tx <= r_data_byte[4];
			 7:Rs232_Tx <= r_data_byte[5];
			 8:Rs232_Tx <= r_data_byte[6];
			 9:Rs232_Tx <= r_data_byte[7];
			 10:Rs232_Tx <= STOP_BIT;
			default:  Rs232_Tx <= 1'b1;
		 endcase 
	  
	  end

		
endmodule

tesebench验证

	 `timescale 1ns/1ns
	`define clk_period 20
	 module uart_byte_tx_tb;
	 
	   reg  Clk;
	   reg  Rst_n;
		reg  [7:0]data_byte;
		reg  send_en;
		reg  [2:0]band_set;
		
		wire Rs232_Tx;
		wire Tx_Done; //表示发送完成信号
		wire uart_state;
		
			
	 uart_byte_tx uart_byte_tx(
	    .Clk(Clk),
		 .Rst_n(Rst_n),
		 .send_en(send_en),
		 .data_byte(data_byte),
		 .band_set(band_set),
		 
		 .Rs232_Tx(Rs232_Tx),
		 .Tx_Done(Tx_Done),
		 .uart_state(uart_state)
	);
	
	  initial Clk=1;
	  always#(`clk_period/2)  Clk=~Clk;
	  
	  initial begin //要考虑哪些信号需求赋初值
	     Rst_n=1'b0;
		  data_byte=8'd0;
		  send_en=1'd0;
		  band_set=3'd4;
		  #(`clk_period*200+1)   //+1的目的是不与时钟边沿对齐,便于观察
	     Rst_n=1'b1;
		  #(`clk_period*50)    //延迟50个系统周期
		  data_byte=8'haa;
		  send_en=1'd1;
		  #`clk_period;
		  send_en=1'd0;
		  
		  @(posedge Tx_Done)
	//等待完成重新发送	  
		  #(`clk_period*5000)
		  data_byte=8'h55;
		  send_en=1'd1;
		  #`clk_period
		  send_en=1'd0;	  
	     @(posedge Tx_Done)
		  #(`clk_period*5000)
	     $stop;
	  end
	
	
	
	endmodule 

//为了进行板级调试设计的顶层top文件
module uart_tx_top(Clk,Rst_n,Rs232_Tx);
   input Clk;
	input Rst_n;
	output Rs232_Tx;
	
	 uart_byte_tx uart_byte_tx(
    .Clk(Clk),
	 .Rst_n(Rst_n),
	 .send_en(send_en),
	 .data_byte(data_byte),
	 .band_set(band_set),
	 
	 .Rs232_Tx(Rs232_Tx),
	 .Tx_Done(Tx_Done),
	 .uart_state(uart_state)
);

	
endmodule