Yindow

【红色飓风Nano二代测评】串口

0
阅读(2671)

经过一天的熟悉,ISE软件的开发流程基本了解了,现在就通过以前使用过的串口模块在ISE上面移植,进一步的加深印象。

串口通讯因为其稳定、简单、成本低等优势在工业控制中有着举足轻重的地位,串口的时序不管是谷歌还是百度上面介绍的相当的详细。

verilog实现串口,我们一般分为以下几个模块:

1.波特率发生器模块

由于FPGA的时钟为50Mhz,而串口通讯的通用波特率一般在960057600115200等之间徘徊,所以我们需要给时钟进行一个分频。时钟是50MHz即每秒钟有50000000个时钟周期,而假设串口的波特率是9600,则分频系数即为:50000000/9600.

通过计算我们可以得到一个波特率发生器分频表格

BPS

Times

9600

5207

12900

2603

38400

1301

57600

867

115200

433

对于这种数据,我们一般采用中间采样原则。

BPS/2

Times/2

9600/2

5207

12900/2

1301

38400/2

650

57600/2

433

115200/2

216

1.波特率发生器源码如下


  module speedSelect
  (
  	input	clk,		//50MHz
  	input	rst_n,
  	input	bps_start,	//波特率发生器启动信号
  	output	clk_bps	//波特率
  );
  
  `define	BPS_PARA		867	//57600 bps
  `define	BPS_PARA_2	433
  
  reg[12:0] cnt; //分频计数器
  reg clk_bps_r;	//波特率时钟计数器
  
  always @ (posedge clk or negedge rst_n)
  begin
  	if(!rst_n)
  		begin
  			cnt <= 13'd0;
  		end
  	else if((cnt == `BPS_PARA) || !bps_start)
  		begin
  			cnt <= 13'd0;
  		end
  	else
  		begin
  			cnt <= cnt + 1'b1;	//start count
  		end
  end
  	
  
  always @ (posedge clk or negedge rst_n)
  	if(!rst_n)
  		begin
  			clk_bps_r <= 1'b0;
  		end
  	else if(cnt == `BPS_PARA_2)
  		begin
  			clk_bps_r <= 1'b1;
  		end
  	else
  		begin
  			clk_bps_r <= 1'b0;
  		end

  assign clk_bps = clk_bps_r;

  endmodule

2.数据接收模块

 


如图1所示,一次串口通讯是从数据位的下降沿开始的,所以FPGA对于UART接受引脚一直处于监听状态,当串口接收引脚产生下降沿之后,延迟一个采样周期后,每隔一个采样周期即可以取得一个数据位。最后将这个数据为拼接起来形成数据。

以下为串口通信源码


  module uatrRX
  (
  	input	clk,			//MCLK 50MHz
  	input	rst_n,
  	input	rs232_rx,	//接收信号
  	input	clk_bps,		//
  
  	output bps_start,	//Receive data, set the baud rate clock start signal
  	output[7:0]	rx_data	//Receive data register
  );
  
  reg rx_int;			//数据接收期间一直保持高电平
  //-------------------------------------------------
  reg[2:0]	rs232REG;
  //---------------------------------------------
  always @ (posedge clk or negedge rst_n)begin
  	if(!rst_n)
  		begin
  			rs232REG <= 3'b000;
  		end
  	else
  		begin
  			rs232REG <= {rs232REG[1:0],rs232_rx};
  		end
  end
  
  //判断接收信号的下降沿
  wire neg_rs232_rx = (rs232REG[2:1] == 2'b10);
  //-------------------------------------------------
  reg bps_start_r;
  reg[3:0] num;
  
  always @ (posedge clk or negedge rst_n) begin
  	if(!rst_n)
  		begin
  			bps_start_r <= 1'b0;
  			rx_int <= 1'b0;
  		end
  	else if(neg_rs232_rx)
  		begin
  			bps_start_r <= 1'b1;
  			rx_int <= 1'b1;
  		end
  	else if(num==4'd10)
  		begin
  			bps_start_r <= 1'b0;
  			rx_int <= 1'b0;
  		end
  end
  
  assign bps_start = bps_start_r;
  
  //----------------------------------------------------
  reg[7:0] rx_data_r;
  reg[7:0] rx_temp_data;
  
  always @ (posedge clk or negedge rst_n) begin
  	if(!rst_n)
  		begin
  			rx_temp_data <= 8'd0;
  			num <= 4'd0;
  			rx_data_r <= 8'd0;
  		end
  	else if(rx_int)
  		begin
  			if(clk_bps)
  				begin
  					num <= num + 1'b1;
  					case (num)
  						4'd1: rx_temp_data[0] <= rs232_rx;
  						4'd2: rx_temp_data[1] <= rs232_rx;
  						4'd3: rx_temp_data[2] <= rs232_rx;
  						4'd4: rx_temp_data[3] <= rs232_rx;
  						4'd5: rx_temp_data[4] <= rs232_rx;
  						4'd6: rx_temp_data[5] <= rs232_rx;
  						4'd7: rx_temp_data[6] <= rs232_rx;
  						4'd8: rx_temp_data[7] <= rs232_rx;
  						default: ;
  					endcase
  				end
  			else if(num == 4'd10)
  				begin
  						num <= 4'd0;
  						rx_data_r <= rx_temp_data;
  				end
  		end
  end
  		
  assign 	rx_data = rx_data_r;	
  
  endmodule

3.数据发送模块

(由于本次实验只用到了串口接收,且串口发送和接收比较类似,略去)

4.顶层模块

一般情况我们需要写一个顶层的模块将串口模块封装好,对于本次实验来说,就是电脑通过串口发送数据并通过LED显示出来。

以下为顶层模块源码

  module UART
  (
     input	clk,
  	input	rst_n,
  	input	rs232_rx,
  	
  	output[7:0] LED
  );
  
  wire bps_start1;	//
  wire clk_bps1;		//
  wire[7:0] rx_data;	//
  
  speedSelect			speed_inst
  ( //Baud rate selection module
  	.clk					(clk),
  	.rst_n				(rst_n),
  	.bps_start			(bps_start1),
  	.clk_bps				(clk_bps1)
  );
  						
  uatrRX				uart_rx_inst
  (
  	.clk					(clk),
  	.rst_n				(rst_n),
  	.rs232_rx			(rs232_rx),
  	.rx_data				(rx_data),
  	.clk_bps				(clk_bps1),
  	.bps_start			(bps_start1)
  );
  
  assign LED = rx_data;
  
  endmodule

下面为效果图:

 

上位机发送0xAALED显示效果图

 

上位机发送0xF0LED显示效果图