UART接收模块的Verilog实现

大致思路如下:
【1】在复位状态下,寄存器清零。
【2】将波特率时钟分成16段(即计数满16次产生一个ce_1脉冲),在计数满八次时产生ce_1_mid脉冲信号,进行采样(中间的数据比较稳定),将采用的数据放到移位寄存器in_sync中进行存储,同时会将数据缓存到大。data_buf进行存储,然后传送到输出端。

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

//out<={in,out[3:1]}; 这是在将out[3:0]右移一位,舍弃最低位out[0]同时高位移入in。
// uart receive module  
//
//---------------------------------------------------------------------------------------

module uart_rx 
(
	clock,
	reset,
	ce_16, 
	ser_in, 
	rx_data, 
	new_rx_data 
);


input 			clock;			
input 			reset;			 
input			ce_16;			// 波特率时钟产生 
input			ser_in;			// 串行数据输入 
output	[7:0]	rx_data;		// 接收的新数据 
output 			new_rx_data;	// 接受新数据的信号



// internal wires 
wire ce_1;		 
wire ce_1_mid;	//  时钟启用在每个位的中间-用于采样数据(对每一位数据进行采样时,一般情况下认为数据中间的数据是最稳定的)





// internal registers 
reg	[7:0] rx_data;
reg	new_rx_data;
reg [1:0] in_sync;
reg rx_busy; 
reg [3:0]	count16;
reg [3:0]	bit_count;
reg [7:0]	data_buf;


 
// 异步输入信号被采样两次
always @ (posedge clock or posedge reset)
begin 
	if (reset) 
		in_sync <= 2'b11;
	else 
		in_sync <= {in_sync[0], ser_in};//左移一位,舍弃移位寄存器的高位in_sync[1],同时写入串行输入数据写入低位
end 




// 计数器产生 ce_1 和ce_1_mid 脉冲信号. 
//此计数器用于在接收端不接收时检测起始位,并在接收端对采样周期进行计数
always @ (posedge clock or posedge reset)
begin
	if (reset) 
		count16 <= 4'b0;
	else if (ce_16) 
	begin 
		if (rx_busy | (in_sync[1] == 1'b0))???//这里怎么理解
			count16 <= count16 + 4'b1;
		else 
			count16 <= 4'b0;
	end 
end 





//ce_1信号的产生
assign ce_1 = (count16 == 4'b1111) & ce_16;
// ce_1_mid信号的产生 
assign ce_1_mid = (count16 == 4'b0111) & ce_16;





// rx_busy信号 
always @ (posedge clock or posedge reset)
begin 
	if (reset)
		rx_busy <= 1'b0;
	else if (~rx_busy & ce_1_mid)
		rx_busy <= 1'b1;
	else if (rx_busy & (bit_count == 4'h9) & ce_1_mid) 
		rx_busy <= 1'b0;
end 






//位计数器
always @ (posedge clock or posedge reset)
begin 
	if (reset)
		bit_count <= 4'h0;
	else if (~rx_busy) 
		bit_count <= 4'h0;
	else if (rx_busy & ce_1_mid)
		bit_count <= bit_count + 4'h1;
end 







// 数据缓冲移位寄存器 
always @ (posedge clock or posedge reset)
begin 
	if (reset)
		data_buf <= 8'h0;
	else if (rx_busy & ce_1_mid)
		data_buf <= {in_sync[1], data_buf[7:1]};//移位寄存器右移,舍去data_buf的最低位,同时in_sync[1]高位写入
end 




// data output and flag 
always @ (posedge clock or posedge reset)
begin 
	if (reset) 
	begin 
		rx_data <= 8'h0;
		new_rx_data <= 1'b0;
	end 
	else if (rx_busy & (bit_count == 4'h8) & ce_1)
	begin 
		rx_data <= data_buf;
		new_rx_data <= 1'b1;
	end 
	else 
		new_rx_data <= 1'b0;
end 







//flag
always @ (posedge clock or posedge reset)
	begin 
	if (reset) 
		new_rx_data <= 1'b0;
	else if (rx_busy & (bit_count == 4'h8) & ce_1) //数据接收完成
		new_rx_data <= 1'b1;//高电平为空闲状态
	else 
		new_rx_data <= 1'b0;
end 
endmodule

参考文献:

【1】opencores

发布了50 篇原创文章 · 获赞 5 · 访问量 2693

猜你喜欢

转载自blog.csdn.net/qq_43042339/article/details/103818514