二,基于FPGA的串口UART通用编程设计

1,串口通信

      异步通信的主要通讯方式,一根数据线即可完成传输,通过约定速率实现数据串并解析,按位顺序进行传输。通过电气标准分为RS-232,RS-422,RS-485。

2,串口通信时时序

一次串口传输主要有4类数据传输,具体如图所示.

   

    空闲位  : 持续的高电平为空闲位

    起始位  :1个低电平表示起始位

    数据位  : 数据位一般有8位,一次传输一个字节的数据,从低到高以此传输。

    校验位  : 校验位可配置为奇校验,偶校验,无效验。

    停止位  : 1个高电平表示起始位。

3,FPGA实现串口通信

     FPGA实现串口通信接口时序,可以通过参数配置系统时钟,波特率,传输数据位,校验,停止位。

     顶层代码如下:

//
// Company:  
// Engineer:  xy
//
// Create Date:    2018.12.12
// Design Name:    
// Module Name:    uart_ip
// Project Name:   uart_design
// Target Device:  
// Tool versions:  
// Description:
//
// Dependencies:
// 
// 

module uart_ip #(
	parameter [31:0]	SYSCLKFREQ	= 50000000, //system clk
	parameter [31:0]	UARTATE		= 115200,	//uart bps 
	parameter [0:0]		PARITY_EN	= 0,    	//papity en?
	parameter [0:0]		PARITY		= 0,    	//papity sel 0-even,1-odd
	parameter [1:0]		STOP_BIT	= 0			//stopbit number 1   2 
)(
	input					rst,
	input					clk,
	
	output		[7:0]		po_rxdata,
	output					po_rxen,
	output		[7:0]		po_error_cnt,
	
	input		[7:0]		pi_txdata,
	input					pi_txen,
	output					po_txover,
	
	input					pi_uart_rx,
	output					po_uart_tx
);

	uart_tx_module #(
		.SYSCLKFREQ		(SYSCLKFREQ),
		.UARTATE		(UARTATE),	
		.PARITY_EN		(PARITY_EN),   
		.PARITY			(PARITY),    	
		.STOP_BIT		(STOP_BIT)
		)
	uart_tx_inst(
		.clk			(clk),
		.rst			(rst),
		.tx_data		(pi_txdata),
		.tx_en			(pi_txen),
		.rs232_tx		(po_uart_tx),
		.tx_over		(po_txover)
	);
	
	
	uart_rx_module#(
		.SYSCLKFREQ		(SYSCLKFREQ),
		.UARTATE		(UARTATE),	
		.PARITY_EN		(PARITY_EN),   
		.PARITY			(PARITY),    	
		.STOP_BIT		(STOP_BIT)
		)
	uart_rx_inst(
		.clk			(clk),
		.rst			(rst),
		.rs232_rx		(pi_uart_rx),
		.rx_data		(po_rxdata),
		.rx_en			(po_rxen),
		.error_cnt		(po_error_cnt)
	);
	


endmodule 

接收端代码 :

//RX UART data
module uart_rx_module #(
	parameter [31:0]	SYSCLKFREQ	= 50000000, //system clk
	parameter [31:0]	UARTATE		= 115200,	//uart bps 8
	parameter [0:0]		PARITY_EN	= 0,    	//papity en?
	parameter [0:0]		PARITY		= 0,    	//papity sel 0-even,1-odd
	parameter [1:0]		STOP_BIT	= 0			//stop bit number 1   2 
)(	
	input					clk,       // 50MHz
	input					rst,       //rst  -1
	input					rs232_rx,  // uart signal -rx
	output		[7:0]		rx_data,   //receive data
	output					rx_en,     //receive data en;if rx_en is 1,rx_data is vaild 
	output	reg	[7:0]		error_cnt  //papity is fail ,count for error data.
);	
	
	localparam [31:0]	BPS_PARA	= SYSCLKFREQ/UARTATE; //bps count 
	localparam [31:0] 	BPS_PARA_2	= BPS_PARA/2;		  //half is bps count
	
	localparam [4:0]	T_DATA_CNT = 1 + 8 + PARITY_EN + STOP_BIT; //start + 8bit + papity_bit + stop_bit;
	
	//************************generate** uart clk***************************************
	wire		clk_bps;	//clock bps
	wire		bps_start;	//start generate bps signal
	reg  [31:0]	clk_cnt;	//count for bps clock
	reg			clk_bps_r;	//clock bps reg /the rising edge of the clock with the data center

	always @ (posedge clk) begin 
		if(rst) 	
			clk_cnt <= 16'd0;
		else if((clk_cnt == BPS_PARA) || !bps_start)	
			clk_cnt <= 16'd0;			
		else 											
			clk_cnt <= clk_cnt + 16'd1;	
	end 

	always @ (posedge clk) begin
		if(rst) 
			clk_bps_r <= 1'b0;
		else if(clk_cnt == BPS_PARA_2) 
			clk_bps_r <= 1'b1;	
		else 
			clk_bps_r <= 1'b0;
	end

	assign clk_bps = clk_bps_r;

//---------------------------------------------------------------------------	
	
   
//**************************************************Falling edge***********************************
    reg		rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;	
    wire	neg_rs232_rx;
    
    always @ (posedge clk) begin
        rs232_rx0 <= rs232_rx;
        rs232_rx1 <= rs232_rx0;
        rs232_rx2 <= rs232_rx1;
        rs232_rx3 <= rs232_rx2;
    end
       
    assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;   //1 clock 
//--------------------------------------------------------------------------------------------------


//******************************bps start*******************************************  
     wire num_flag;
     reg bps;
     reg   bps_r;
     wire rx_int;
   
   always @ (*) begin 
      if(rst)
         bps = 0;
      else if(neg_rs232_rx)
         bps = 1;
      else if(num_flag)
         bps = 0;
      else 
         bps = bps_r;
   end 
   always @ (posedge clk) begin 
      bps_r <= bps;
   end 
   
   assign bps_start = bps_r;
   assign rx_int = bps_r && clk_bps;
//--------------------------------------------------------------------------------------------------   
   
   
//*****************************receiver count**************************************
(*keep = "true"*)  reg [3:0] num;
(*keep = "true"*)  reg  [3:0] num_r;
   
   always @ (*) begin 
      if(rst) 
         num = 0;
      else if(rx_int)
         num = num_r + 1;
      else if(num_flag)
         num = 0;
      else 
         num = num_r;
   end 
   always @ (posedge clk) begin 
       num_r <= num;
   end 
   assign num_flag = (num_r == T_DATA_CNT) ? 1 : 0;
//-----------------------------------------------------------------------------


//********************************receive data**************************************
(*keep = "true"*)   reg [7:0] rx_temp_data;		
	reg  [7:0]	rx_data_r;
	reg			rx_en_r;
	reg 		parity_data;
	reg			parity_r;
	wire 		parity_data_o;
	assign		parity_data_o = (PARITY == 1) ? ~parity_data : parity_data;
	
   always @ (posedge clk) begin
      if(rst) begin 
            rx_temp_data <= 8'd0;
			parity_r <= 0;
			parity_data <= 0;
			end 
      else if(rx_int)
         case (num)
            4'd2 : begin rx_temp_data[0] <= rs232_rx;	parity_data <= 0 ^rs232_rx; end 
            4'd3 : begin rx_temp_data[1] <= rs232_rx;	parity_data <= parity_data ^rs232_rx; end
            4'd4 : begin rx_temp_data[2] <= rs232_rx;	parity_data <= parity_data ^rs232_rx; end
            4'd5 : begin rx_temp_data[3] <= rs232_rx;	parity_data <= parity_data ^rs232_rx; end
            4'd6 : begin rx_temp_data[4] <= rs232_rx;	parity_data <= parity_data ^rs232_rx; end
            4'd7 : begin rx_temp_data[5] <= rs232_rx;	parity_data <= parity_data ^rs232_rx; end
            4'd8 : begin rx_temp_data[6] <= rs232_rx;	parity_data <= parity_data ^rs232_rx; end
            4'd9 : begin rx_temp_data[7] <= rs232_rx;	parity_data <= parity_data ^rs232_rx; end
			4'd10 : if(PARITY_EN == 1) parity_r <= rs232_rx;
            default: ;
         endcase
      else 
         rx_temp_data <= rx_temp_data;
   end
  
	always @ (posedge clk) begin 
		if(rst) begin 
			rx_data_r <= 0;
			rx_en_r <= 0;
			end 
		else if(num_flag) begin 
			rx_data_r <= rx_temp_data;
			rx_en_r <= 1;
			end 
		else 
			rx_en_r <= 0;
  end 
   
   assign rx_data = rx_data_r;
   assign rx_en = rx_en_r;
   
   always @ (posedge clk) begin 
	if(rst)
		error_cnt <= 0;
	else if(num_flag && PARITY_EN == 1) begin 
		if(parity_data_o == parity_r )
			error_cnt <= error_cnt;
		else 
			error_cnt <= error_cnt + 1;
		end 
	else 
		error_cnt <= error_cnt;
   end 
//----------------------------------------------------------------------------- 
endmodule

发送端代码:

//TX data
module uart_tx_module #(
	parameter [31:0]	SYSCLKFREQ	= 50000000, //system clk
	parameter [31:0]	UARTATE		= 115200,	//uart bps 
	parameter [0:0]		PARITY_EN	= 0,    	//papity en?
	parameter [0:0]		PARITY		= 0,    	//papity sel 0-even,1-odd
	parameter [1:0]		STOP_BIT	= 0			//stop bit number 1   2 
)(
	input					clk,		// 50MHz
	input					rst,		//rst  -1
	input		[7:0]		tx_data,	//send data
	input					tx_en,		//Send data en .if tx_en is 1. tx_data is vaild 
	output					rs232_tx,	// uart signal -tx
	output					tx_over 	//send data finish. one clock
);

	
	localparam [31:0]	BPS_PARA = SYSCLKFREQ/UARTATE; 	//bps count
	localparam [31:0] 	BPS_PARA_2 = BPS_PARA/2;		//half is bps count
	
	localparam [4:0]	T_DATA_CNT = 1 + 8 + PARITY_EN + STOP_BIT; //start + 8bit + papity_bit + stop_bit;
	
//************************generate** uart clk***************************************
	wire		clk_bps;	//clock bps
	wire		bps_start;	//start generate bps signal
	reg  [31:0]	clk_cnt;	//count for bps clock
	reg			clk_bps_r;	//clock bps reg /the rising edge of the clock with the data center

	always @ (posedge clk) begin 
		if(rst) 	
			clk_cnt <= 16'd0;
		else if((clk_cnt == BPS_PARA) || !bps_start)	
			clk_cnt <= 16'd0;			//count ->0
		else 											
			clk_cnt <= clk_cnt + 16'd1;	//count + 1
	end 

	always @ (posedge clk) begin
		if(rst) 
			clk_bps_r <= 1'b0;
		else if(clk_cnt == BPS_PARA_2) 
			clk_bps_r <= 1'b1;	
		else 
			clk_bps_r <= 1'b0;
	end

	assign clk_bps = clk_bps_r;

//---------------------------------------------------------------------------	

//*******************************start bps*******************************************  
	wire		num_flag;
	reg			bps;
	reg 		bps_r;
	wire		tx_int;
   
   always @ (*) begin 
      if(rst)
         bps = 0;
      else if(tx_en)
         bps = 1;
      else if(num_flag)
         bps = 0;
      else 
         bps = bps_r;
   end 
   always @ (posedge clk) begin 
      bps_r <= bps;
   end 
   
   assign bps_start = bps_r;
   assign tx_int = bps_r && clk_bps;
//--------------------------------------------------------------------------------------------------   


//*****************************data count **************************************
(*keep = "true"*)  reg  [3:0] num;
(*keep = "true"*)  reg  [3:0] num_r;

   always @ (*) begin 
      if(rst)
         num = 0;
      else if(tx_int)
         num = num_r + 1;
      else if(num_r == T_DATA_CNT)
         num = 0;
      else 
         num = num_r;
   end 
   
   always @ (posedge clk) begin 
      num_r <= num;
   end 
   
   assign num_flag = (num_r == T_DATA_CNT) ? 1 : 0;
//-----------------------------------------------------------------------------


//**************************************TX data***********************************

	wire	parity_data; 
	wire	parity_data_o; 
	reg		rs232_t;

	assign parity_data = tx_data[0] ^ tx_data[1] ^ tx_data[2] ^ tx_data[3] ^ tx_data[4] ^ tx_data[5] ^ tx_data[6] ^ tx_data[7];
	assign parity_data_o = (PARITY == 1) ? ~parity_data : parity_data;
   
	always @ (posedge clk) begin 
		if(rst) 
			rs232_t <= 1;
		else case(num)
			4'd0 : rs232_t <= 1'b1; 	
			4'd1 : rs232_t <= 1'b0;  
			4'd2 : rs232_t <= tx_data[0];   //bit1
			4'd3 : rs232_t <= tx_data[1];   //bit2
			4'd4 : rs232_t <= tx_data[2];   //bit3
			4'd5 : rs232_t <= tx_data[3];   //bit4
			4'd6 : rs232_t <= tx_data[4];   //bit5
			4'd7 : rs232_t <= tx_data[5];   //bit6
			4'd8 : rs232_t <= tx_data[6];   //bit7
			4'd9 : rs232_t <= tx_data[7];   //bit7
			4'd10 : if(PARITY_EN == 1)	rs232_t <= parity_data_o;
					else 				rs232_t <= 1'b1;
			4'd11: rs232_t <= 1'b1;   
			4'd12: rs232_t <= 1'b1;   
			default: rs232_t <= 1'b1;
		endcase
	end 

//---------------------------------------------------------------------------------
	assign rs232_tx = rs232_t;
	assign tx_over = num_flag;

endmodule

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值