此号不用改用道法自然了

菜鸟入门之串口通信

0
阅读(2128)



blob.png

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

`timescale 1ns / 1ps
module my_uart_top(
		clk,rst_n,
		rs232_rx,rs232_tx
		);
input     clk;	// 50MHz主时钟
input     rst_n;	//低电平复位信号

input     rs232_rx;		// RS232接收数据信号
output    rs232_tx;	//	RS232发送数据信号


wire     bps_start1,bps_start2;	//接收到数据后,波特率时钟启动信号置位
wire     bps_clk1,bps_clk2;		// bps_clk_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点 
wire    [7:0] rx_data;	//接收数据寄存器,保存直至下一个数据来到
wire     rx_int;		//接收数据中断信号,接收到数据期间始终为高电平
//----------------------------------------------------
//下面的四个模块中,speed_rx和speed_tx是两个完全独立的硬件模块,可称之为逻辑复制
//(不是资源共享,和软件中的同一个子程序调用不能混为一谈)
speed_select	speed_rx(	
			.clk(clk),	//波特率选择模块
			.rst_n(rst_n),
			.bps_start(bps_start1),
			.bps_clk(bps_clk1)
			);

my_uart_rx	my_uart_rx(		
			.clk(clk),	//接收数据模块
			.rst_n(rst_n),
			.rs232_rx(rs232_rx),
			.rx_data(rx_data),
			.rx_int(rx_int),
			.bps_clk(bps_clk1),
			.bps_start(bps_start1)
			);

///////////////////////////////////////////						
speed_select	speed_tx(	
			.clk(clk),	//波特率选择模块
			.rst_n(rst_n),
			.bps_start(bps_start2),
			.bps_clk(bps_clk2)
			);

my_uart_tx	my_uart_tx(		
			.clk(clk),	//发送数据模块
			.rst_n(rst_n),
			.rx_data(rx_data),
			.rx_int(rx_int),
			.rs232_tx(rs232_tx),
			.bps_clk(bps_clk2),
			.bps_start(bps_start2)
			);

endmodule

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

`timescale  1ns/1ps
`define 		BPS 	5207
`define 		BPS_2	2603
module speed_select(
		clk,rst_n,bps_start,
		bps_clk
		);
input		clk;
input 		rst_n;
input 		bps_start;
output 		bps_clk;// 高电平时为接收或者发送数据位的中间采样点 
reg [12:0]	cnt;
reg 			bps_clk_r;
always@(posedge clk or negedge rst_n)
	if(!rst_n)	cnt <= 13'd0;
	else if(cnt == `BPS || !bps_start )
					cnt <= 13'd0;
	else 			cnt <= cnt + 1'b1;
always@(posedge clk or negedge rst_n)
	if(!rst_n)	bps_clk_r <= 1'b0;
	else if(cnt == `BPS_2)	
					bps_clk_r  <= 1'b1;
	else bps_clk_r <= 1'b0;			
assign	 bps_clk	=  bps_clk_r;			
endmodule 				
/*
parameter 		bps9600 	= 5207,	//波特率为9600bps
			 	bps19200 	= 2603,	//波特率为19200bps
				bps38400 	= 1301,	//波特率为38400bps
				bps57600 	= 867,	//波特率为57600bps
				bps115200	= 433;	//波特率为115200bps

parameter 		bps9600_2 	= 2603,
				bps19200_2	= 1301,
				bps38400_2	= 650,
				bps57600_2	= 433,
				bps115200_2 = 216;  
*/			

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

`timescale 1ns/1ps
module my_uart_rx(
		clk,rst_n,
		rs232_rx,bps_clk,        
		bps_start,rx_data,rx_int
		  );
input		clk;
input		rst_n;
input		rs232_rx;//RS232接收数据信号
input		bps_clk;// bps_clk的高电平为接收或者发送数据位的中间采样点

output	bps_start;// clk_bps的高电平为接收或者发送数据位的中间采样点
output  	rx_int;//接收数据中断信号,接收到数据期间始终为高电平
output   [7:0]  rx_data;//接收数据寄存器,保存直至下一个数据来到 

wire     neg_rs232_rx;//表示数据线接收到下降沿

reg 	rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;//接收数据寄存器,滤波用

always@(posedge clk or negedge rst_n)	begin 
	if(!rst_n)	begin 
		rs232_rx0 <= 1'b0;
		rs232_rx1 <= 1'b0;
		rs232_rx2 <= 1'b0;
		rs232_rx3 <= 1'b0;
	    end 				
	else 	begin 
		rs232_rx0 <= rs232_rx;
		rs232_rx1 <= rs232_rx0;
		rs232_rx2 <= rs232_rx1;
		rs232_rx3 <= rs232_rx2;
	    end 
end 
//下面的下降沿检测可以滤掉<20ns-40ns的毛刺(包括高脉冲和低脉冲毛刺),
//这里就是用资源换稳定(前提是我们对时间要求不是那么苛刻,因为输入信号打了好几拍) 
//(当然我们的有效低脉冲信号肯定是远远大于40ns的)
assign	neg_rs232_rx	= rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;
reg	bps_start_r;
reg   [3:0]  num;//移位次数
reg   rx_int;////接收数据中断信号,接收到数据期间始终为高电平
always@(posedge clk or negedge rst_n)
	if(!rst_n)	begin 
		bps_start_r <= 1'bz;
		rx_int <= 1'b0;
	    end 
	else if (neg_rs232_rx)	begin//接收到串口接收线rs232_rx的下降沿信号
		bps_start_r <= 1'b1;//启动串口准备数据接收
		rx_int <= 1'b1;	  //接收数据中断使能信号	
	    end 
	else if (num == 4'd12)	begin //接收完有用数据信息
		bps_start_r <= 1'b0;//数据接收完,释放波特率启动信号
		rx_int <= 1'b0;//接收数据中断信号关闭
	    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)
	if(!rst_n)	begin 
			rx_temp_data <= 8'd0;
			num <= 4'd0;
			rx_data_r <= 8'd0;
	    end 	
	else if(rx_int)	begin 
			if(bps_clk)	begin 
				num <= num + 1'b1;
				case(num)
					4'd1:rx_temp_data[0] <= rs232_rx;//锁存第0bit
					4'd2:rx_temp_data[1] <= rs232_rx;//锁存第1bit
					4'd3:rx_temp_data[2] <= rs232_rx;//锁存第2bit
					4'd4:rx_temp_data[3] <= rs232_rx;//锁存第3bit
					4'd5:rx_temp_data[4] <= rs232_rx;//锁存第4bit
					4'd6:rx_temp_data[5] <= rs232_rx;//锁存第5bit
					4'd7:rx_temp_data[6] <= rs232_rx;//锁存第6bit
					4'd8:rx_temp_data[7] <= rs232_rx;//锁存第7bit
					default:;
				endcase
			end 		
			else if(num == 4'd12)	begin 
				                //我们的标准接收模式下只有1+8+1(2)=11bit的有效数据
				num <= 4'd0;	//接收到STOP位后结束,num清零
				rx_data_r <= rx_temp_data;	//把数据锁存到数据寄存器rx_data中
			end 
	end 
assign	rx_data = rx_data_r;	
endmodule

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