UART数据发送和接收(Verilog)

微信公众号上线,搜索公众号小灰灰的FPGA,关注可获取相关源码,定期更新有关FPGA的项目以及开源项目源码,包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等
UART数据发送和接收(Verilog)
UART 通信的原理,FPGA 来实现 UART 通信中的数据发送和接收
一、UART通信原理
UART即异步串行通信。一种异步收发传输器,数据发送将并行数据转换成串行数据发送,数据接收将串行数据转换成并行数据接收,可实现全双工传输和接收。
1、RS232的引脚定义
在这里插入图片描述

DCD——调制解调器通知PC有载波被侦测到
RXD——接收数据
TXD——发送数据
DTR——PC通知调制解调器进行传输
GND——地线
DSR——调制解调器通知PC准备就绪
RTS——PC要求调制解调器提交数据
CTS——调制解调器通知PC传输数据
RI——调制解调器通知PC有数据输入
2、UART常用参数及时序
UART常用参数设置包括:数据位、波特率、奇偶校验、停止位
数据位:单个UART数据开始到停止期间发送的数据。
波特率:每秒通信的数据比特个数,通常为115200/19200/9600/2400/1200。
奇偶校验:验证数据的正确性。一般不使用,若使用,在偶校验中,数据改变会使得传送数据(所有位数)中“1”个数为偶数,在奇校验中,数据改变会使得传送数据中“1”个数为奇数。
停止位:每个字节的数据位发送完成,发送停止位,标志一次数据传输完成。
RS-232标准,常用配置8个数据位,无奇偶校验,1个停止位,时序如下:
在这里插入图片描述

二、UART串口发送(Verilog)
波特率计算,采用定时计数器产生波特率的时钟,计数值的计算为系统时钟频率除以波特率数值。

module uart_tx(
    input       wire       [00:00]          i_clk,      
    input       wire       [00:00]          i_rst_n, 
    input       wire       [02:00]          i_baud,        //波特率设置
    input       wire       [07:00]          i_data,        //发送数据
    input       wire       [00:00]          i_Tx_start,   //发送数据使能	
	output      reg        [00:00]          o_data,        //输出串行数据
    output      reg        [00:00]          o_Tx_stop,    //发送数据结束
    output      reg        [00:00]          o_state       //数据发送状态
);
/************************波特率时钟***************************/
    reg           [15:00]          baud_cnt;      //波特率时钟计数器
    reg           [00:00]          baud_clk;      //波特率时钟
    reg           [15:00]          baud_tmp;      //波特率数值设定值
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)    
            baud_tmp <= #1 16'd5208;
	    else begin
		    case(i_baud)
			     0:baud_tmp <= #1 16'd5208;     //波特率9600
				 1:baud_tmp <= #1 16'd2604;     //波特率19200
				 2:baud_tmp <= #1 16'd1302;     //波特率38400
				 3:baud_tmp <= #1 16'd868;      //波特率57600		
				 4:baud_tmp <= #1 16'd434;      //波特率115200
             default:baud_tmp <= #1 16'd5208;
          endcase			 
		end
    end
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
            baud_cnt <= #1 1'b0;
	    else if(o_state)
		     begin
		        if(baud_cnt == baud_tmp)
                    baud_cnt <= #1 1'b0;
		        else
                  baud_cnt <= #1 baud_cnt + 1'b1;		
			 end
    end 	
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
            baud_clk <= #1 1'b0;
	    else if(baud_cnt == baud_tmp)
		      baud_clk <= #1 1'b1;
		else
            baud_clk <= #1 1'b0;		
    end 
/************************波特率时钟***************************/
/***************数据发送状态和结束标志**************************/
    reg           [03:00]          data_cnt;      //数据计数器     
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
          data_cnt <= #1 1'b0;
	    else if(data_cnt == 4'd11)
		    data_cnt <= #1 1'b0;
		else if(baud_clk)
          data_cnt <= #1 data_cnt + 1'b1;
        else 
          data_cnt <= #1 data_cnt;		
    end 				   
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
		    o_state <= #1 1'b0;
		else if(i_Tx_start)
		    o_state <= #1 1'b1;
		else if(data_cnt == 4'd11)
 		    o_state <= #1 1'b0; 
        else 
		    o_state <= #1 o_state;		
    end
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
		    o_Tx_stop <= #1 1'b0;
		else if(data_cnt == 4'd11)
 		    o_Tx_stop <= #1 1'b1; 
        else 
		    o_Tx_stop <= #1 1'b0;		
    end	
/***************数据发送状态和结束标志**************************/
/***************数据发送*************************************/
    reg           [07:00]          i_data_n;      //数据存储器
    always@(posedge i_clk or negedge i_rst_n)
	begin
	    if(!i_rst_n)
		    i_data_n <= #1 1'b0;
		else if(i_Tx_start)
		    i_data_n <= #1 i_data;		 
	    else 
		    i_data_n <= #1 i_data_n;
    end
	always@(posedge i_clk or negedge i_rst_n)
	begin
        if(!i_rst_n)
		    o_data <= #1 1'b1;
		  else begin
		     case(data_cnt)
			     0:o_data <= #1 1'b1;
				 1:o_data <= #1 1'b0;            //start
				 2:o_data <= #1 i_data_n[0];
				 3:o_data <= #1 i_data_n[1];
				 4:o_data <= #1 i_data_n[2];
				 5:o_data <= #1 i_data_n[3];
				 6:o_data <= #1 i_data_n[4];
				 7:o_data <= #1 i_data_n[5];
				 8:o_data <= #1 i_data_n[6];
				 9:o_data <= #1 i_data_n[7];
			    10:o_data <= #1 1'b1;           //stop
		        default:o_data <= #1 1'b1;
		     endcase  
		end
    end
/***************数据发送*************************************/
endmodule

三、UART串口接收(Verilog)

module uart_rx(
    input      wire        [00:00]          i_clk,      
    input      wire        [00:00]          i_rst_n, 
    input      wire        [02:00]          i_baud,        //波特率设置
    input      wire        [00:00]          i_data,        //串行发送数据	
	output     reg         [07:00]          o_data,        //输出并行数据
    output     reg         [00:00]          o_Rx_stop      //接收数据结束
);
/**************************数据锁存***************************/
        reg        [00:00]          state;          //数据接收状态  
        reg        [00:00]          i_data_n;       //数据接收状态  
        reg        [00:00]          i_data_r;       //数据接收状态
        reg        [00:00]	        data_n;
		reg        [00:00]          data_r; 
		wire       [00:00]          i_data_neg;  
        reg        [15:00]          data_cnt;       //数据计数器       
 always@(posedge i_clk or negedge i_rst_n)
	 begin
	       if(!i_rst_n)
			     begin
			      i_data_n <= #1 1'b0;
				  i_data_r <= #1 1'b0;
				 end
		   else begin
			      i_data_n <= #1 i_data;
				  i_data_r <= #1 i_data_n;
	            end
	 end
    always@(posedge i_clk or negedge i_rst_n)
	 begin
	       if(!i_rst_n)
			     begin
			       data_n <= #1 1'b0;
				   data_r <= #1 1'b0;
				 end
		   else begin
			       data_n <= #1 i_data_r;
				   data_r <= #1 data_n;
	            end
	 end 
	 assign  i_data_neg  = (!i_data_r) & data_r;					 
/**************************数据锁存***************************/
/**************************数据发送状态************************/
    always@(posedge i_clk or negedge i_rst_n)
	 begin
	     if(!i_rst_n)
		    state <= #1 1'b0;
		 else if(i_data_neg)
	        state <= #1 1'b1;
		 else if(data_cnt == 16'd159)  
	        state <= #1 1'b0;
         else 
            state <= #1 state;		  
	 end
/**************************数据发送状态************************/
/******************波特率时钟(16倍的波特率)********************/
    reg           [15:00]          baud_cnt;      //波特率时钟计数器
    reg           [00:00]          baud_clk;      //波特率时钟
    reg           [15:00]          baud_tmp;      //波特率数值设定值
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)    
            baud_tmp <= #1 16'd325;
	    else begin
		    case(i_baud)
			     0:baud_tmp <= #1 16'd325;      //波特率9600
				 1:baud_tmp <= #1 16'd162;     //波特率19200
				 2:baud_tmp <= #1 16'd80;      //波特率38400
				 3:baud_tmp <= #1 16'd53;      //波特率57600		
				 4:baud_tmp <= #1 16'd26;      //波特率115200
             default:baud_tmp <= #1 16'd325;
          endcase			 
		end
    end
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
            baud_cnt <= #1 16'd0;
	    else if(state)
		     begin
		        if(baud_cnt == baud_tmp)
		            baud_cnt <= #1 16'd0;
		        else
                    baud_cnt <= #1 baud_cnt + 1'b1;		
			 end
    end 	
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
            baud_clk <= #1 1'b0;
	    else if(baud_cnt == baud_tmp)
		    baud_clk <= #1 1'b1;
		else
            baud_clk <= #1 1'b0;		
    end 
/******************波特率时钟(16倍的波特率)********************/
/********************数据接收结束标志***************************/
    always@(posedge i_clk or negedge i_rst_n)
    begin
         if(!i_rst_n)
            data_cnt <= #1 16'd0;
	     else if((data_cnt == 16'd159)||((data_cnt == 16'd12)&&(start_buffer > 3'd2)))
		    data_cnt <= #1 16'd0;
		 else if(baud_clk)
            data_cnt <= #1 data_cnt + 1'b1;
         else 
            data_cnt <= #1 data_cnt;		
    end 		   
    always@(posedge i_clk or negedge i_rst_n)
    begin
        if(!i_rst_n)
		    o_Rx_stop <= #1 1'b0;
		else if(data_cnt == 16'd159)
 		    o_Rx_stop <= #1 1'b1; 
        else 
		    o_Rx_stop <= #1 1'b0;		
    end	
/********************数据接收结束标志***************************/
/***********************数据发送**************************/
   reg      [02:00]      data_buffer     [07:00];    //中间数据缓存器  
   reg      [02:00]      start_buffer           ;    //开始缓存器
   reg      [02:00]      stop_buffer            ;    //结束缓存器
    always@(posedge i_clk or negedge i_rst_n)
	 begin
		  if(!i_rst_n)
           begin
	              start_buffer   <= #1 3'd0;
				  data_buffer[0] <= #1 3'd0;
				  data_buffer[1] <= #1 3'd0;				  
				  data_buffer[2] <= #1 3'd0;			  
				  data_buffer[3] <= #1 3'd0;			  
				  data_buffer[4] <= #1 3'd0;			  
				  data_buffer[5] <= #1 3'd0;
				  data_buffer[6] <= #1 3'd0;
				  data_buffer[7] <= #1 3'd0;
				  stop_buffer    <= #1 3'd0;				  
           end
		  else begin
		           case(data_cnt)
				   0:begin
	                           start_buffer   <= #1 3'd0;
				               data_buffer[0] <= #1 3'd0;
				               data_buffer[1] <= #1 3'd0;				  
				               data_buffer[2] <= #1 3'd0;			  
				               data_buffer[3] <= #1 3'd0;			  
				               data_buffer[4] <= #1 3'd0;			  
				               data_buffer[5] <= #1 3'd0;
				               data_buffer[6] <= #1 3'd0;
				               data_buffer[7] <= #1 3'd0;
				               stop_buffer    <= #1 3'd0;				
			                end			
		            6,7,8,9,10,11:
	                    start_buffer   <= #1 start_buffer + i_data_r;
                    22,23,24,25,26,27:
				       data_buffer[0] <= #1 data_buffer[0] + i_data_r;
	                38,39,40,41,42,43:
				       data_buffer[1] <= #1 data_buffer[1] + i_data_r;
	                54,55,56,57,58,59:
				       data_buffer[2] <= #1 data_buffer[2] + i_data_r;
	                70,71,72,73,74,75:
				       data_buffer[3] <= #1 data_buffer[3] + i_data_r;	
				    86,87,88,89,90,91:
				       data_buffer[4] <= #1 data_buffer[4] + i_data_r;
	                102,103,104,105,106,107:
				       data_buffer[5] <= #1 data_buffer[5] + i_data_r;
	                118,119,120,121,122,123:
				       data_buffer[6] <= #1 data_buffer[6] + i_data_r;
	                134,135,136,137,138,139:
				       data_buffer[7] <= #1 data_buffer[7] + i_data_r;
		            150,151,152,153,154,155:
	                   stop_buffer    <= #1 stop_buffer + i_data_r;
default : begin
	                                start_buffer   <= #1 start_buffer   ;
			                        data_buffer[0] <= #1 data_buffer[0] ;
			                        data_buffer[1] <= #1 data_buffer[1] ;
			                        data_buffer[2] <= #1 data_buffer[2] ;
			                        data_buffer[3] <= #1 data_buffer[3] ;
			                        data_buffer[4] <= #1 data_buffer[4] ;
			                        data_buffer[5] <= #1 data_buffer[5] ;
			                        data_buffer[6] <= #1 data_buffer[6] ;
			                        data_buffer[7] <= #1 data_buffer[7] ;
			                        stop_buffer    <= #1 stop_buffer    ;				  
                                 end 
    	           endcase
	          end					 
    end  
	 always@(posedge i_clk or negedge i_rst_n)
	 begin
	    if(!i_rst_n)
		    o_data <= #1 8'd0;
		 else if(o_Rx_stop)begin
			   o_data[0] <= #1 data_buffer[0][2] ;
			   o_data[1] <= #1 data_buffer[1][2] ;				  
			   o_data[2] <= #1 data_buffer[2][2] ;			  
			   o_data[3] <= #1 data_buffer[3][2] ;			  
			   o_data[4] <= #1 data_buffer[4][2] ;			  
			   o_data[5] <= #1 data_buffer[5][2] ;
			   o_data[6] <= #1 data_buffer[6][2] ;
			   o_data[7] <= #1 data_buffer[7][2];	    
		 end
	 end
/***********************数据发送**************************/
endmodule

三、UART串口接收和发送顶层Top(Verilog)

module uart_top(
    input      wire        [00:00]          i_clk,      
    input      wire        [00:00]          i_rst_n, 
    input      wire        [02:00]          i_baud,        //波特率设置
    input      wire        [07:00]          i_data,        //发送数据
    input      wire        [00:00]          i_Tx_start,    //发送数据使能
    output     wire        [00:00]          o_Tx_stop,     //发送数据结束
    output     wire        [00:00]          o_state,       //数据发送状态 
    output     wire        [07:00]          o_data_rx,     //输出并行数据
    output     wire        [00:00]          o_Rx_stop      //接收数据结束
);   
wire         [00:00]          o_data;        
uart_rx u_uart_rx(
    .i_clk        (i_clk      ),      
    .i_rst_n      (i_rst_n    ), 
    .i_baud       (i_baud     ),       
    .i_data       (o_data     ),            
	.o_data       (o_data_rx  ),      
    .o_Rx_stop    (o_Rx_stop  )            
);

uart_tx u_uart_tx(
    .i_clk       (i_clk      ),      
    .i_rst_n     (i_rst_n    ), 
    .i_baud      (i_baud     ),        
    .i_data      (i_data     ),        
    .i_Tx_start  (i_Tx_start ),        
	.o_data      (o_data     ),       
    .o_Tx_stop   (o_Tx_stop  ),        
    .o_state     (o_state    )        
);
endmodule

四、UART串口接收和发送测试Testbench(Verilog)

`timescale 1ns/1ns
`define clk_period 7
module tb_uart_top();
        reg          [00:00]          i_clk;      
        reg          [00:00]          i_rst_n;         
        wire         [07:00]          o_data_rx;    
        wire         [00:00]          o_Rx_stop;  
        reg          [02:00]          i_baud;       
        reg          [07:00]          i_data;        
        reg          [00:00]          i_Tx_start;    
        wire         [00:00]          o_Tx_stop;     
        wire         [00:00]          o_state;       		  		  
 uart_top u_uart_top(
    .i_clk     (i_clk),      
    .i_rst_n   (i_rst_n), 
    .i_baud    (i_baud),        
    .i_data    (i_data),        
    .i_Tx_start(i_Tx_start),   	
	.o_Tx_stop(o_Tx_stop),
	.o_state(o_state),  
	.o_data_rx (o_data_rx),     
    .o_Rx_stop (o_Rx_stop)     
);

initial i_clk = 0;
always#(`clk_period/2)  i_clk = ~i_clk;

initial begin
   #(`clk_period*20);
   
   i_rst_n = 0;
   #(`clk_period*20);
   
	i_rst_n = 1;
   #(`clk_period*20);
   
	i_baud  = 3'd0;
	i_data  = 8'h15;
	i_Tx_start = 1;
   #(`clk_period);	
	i_Tx_start = 0;
	
	@(posedge o_Tx_stop)
   #(`clk_period*20);
   i_data  = 8'h12;
	i_Tx_start = 1;
	
   #(`clk_period*20);	
   
   i_Tx_start = 0;
	@(posedge o_Tx_stop) 
   #(`clk_period*20);	
   
	i_data  = 8'h14;
	i_Tx_start = 1;
   #(`clk_period*20);	
   
	i_Tx_start = 0;	
	@(posedge o_Tx_stop) 
   #(`clk_period*20);	
   
	i_data  = 8'h31;
	i_Tx_start = 1;
   #(`clk_period*20);	
   
	i_Tx_start = 0;	
	@(posedge o_Tx_stop) 	
   #(`clk_period*200); 
	$stop; 
end
endmodule
  • 6
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
以下是一个DMA+UART发送接收Verilog代码示例: ```verilog module dma_uart ( input clk, // 时钟信号 input rst, // 复位信号 input [7:0] tx_data, // 待发送数据 output reg tx_busy, // 发送忙标志 output reg [7:0] rx_data, // 接收到的数据 input rx, // 接收数据信号 output reg rx_ready, // 接收就绪标志 input dma_start, // DMA启动信号 input [31:0] dma_src_addr, // DMA源地址 output [31:0] dma_dest_addr, // DMA目的地址 input [7:0] dma_length // DMA数据长度 ); // 内部寄存器定义 reg [7:0] tx_byte_cnt; reg [7:0] rx_byte_cnt; reg [31:0] dma_addr; reg [7:0] dma_cnt; reg [31:0] dma_data; // UART发送状态机 always @ (posedge clk) begin if (rst) begin tx_busy <= 0; tx_byte_cnt <= 0; end else if (tx_busy) begin case (tx_byte_cnt) 0: begin // 发送起始位 tx <= 0; tx_byte_cnt <= tx_byte_cnt + 1; end 9: begin // 发送停止位 tx <= 1; tx_busy <= 0; end default: begin // 发送数据位 tx <= tx_data[tx_byte_cnt-1]; tx_byte_cnt <= tx_byte_cnt + 1; end endcase end end // UART接收状态机 always @ (posedge clk) begin if (rst) begin rx_ready <= 0; rx_byte_cnt <= 0; end else if (rx_ready) begin case (rx_byte_cnt) 0: begin // 接收起始位 rx_byte_cnt <= rx_byte_cnt + 1; end 9: begin // 接收停止位 rx_ready <= 0; end default: begin // 接收数据位 rx_data[rx_byte_cnt-1] <= rx; rx_byte_cnt <= rx_byte_cnt + 1; end endcase end else if (rx) begin // 接收到起始位 rx_ready <= 1; rx_byte_cnt <= 0; end end // DMA控制状态机 always @ (posedge clk) begin // 状态1 - 等待启动信号 if (!tx_busy && !rx_ready && dma_start) begin dma_addr <= dma_src_addr; dma_dest_addr <= 0; // 设置DMA目的地址为UART发送寄存器地址 dma_cnt <= dma_length; tx_busy <= 1; end // 状态2 - 数据传输中 else if (tx_busy && dma_cnt > 0) begin dma_data <= mem[dma_addr]; dma_dest_addr <= 1; // 设置DMA目的地址为UART发送寄存器地址 dma_addr <= dma_addr + 1; dma_cnt <= dma_cnt - 1; end // 状态3 - 数据传输完成 else if (tx_busy && dma_cnt == 0) begin tx_busy <= 0; end // 状态4 - 接收数据 else if (rx_ready) begin // 设置DMA目的地址为接收到的数据寄存器地址 dma_dest_addr <= 2; end end endmodule ``` 在这个示例中,DMA控制器等待启动信号,并将DMA源地址、目的地址和数据长度设置为输入信号。一旦启动,控制器将开始将数据从DMA源地址传输到UART发送寄存器。同时,UART接收状态机等待接收到起始位,一旦接收到,它就开始将数据位存储到接收到的数据寄存器中。请注意,这只是一个简单的示例,实际上的DMA和UART控制器需要更多的控制逻辑和状态。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小灰灰的FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值