UART接收器

UART发送器
先看UART发送器模块再看本文!
这两个模块可以仿真通过,代码文末贴上。

UART发送器简介
UART接收器负责接受串行比特流,去除起始位并且以并行格式将数据保存到主机数据相连接的寄存器中。
UART接收器_第1张图片
接受器的时钟信号是发送器时钟信号的八倍,这样使得接受器可以在发送器对应一个时间间隔内工作。
输入为低电平后连续采样到0值表明起始位到来,而且增加三次采样来确定起始位是否有效,此后的8个连续位在每个发送时钟周期内被采样。
UART接收器中控制器和数据通道之间的接口信号描述如图
UART接收器_第2张图片
各个信号意义如下
UART接收器_第3张图片
接收器状态机控制器的状态一共有三个:idle,starting,receiving,状态之间的转移由Sample_clk时钟来同步。

低有效的同步复位输入使得状态机进入idle状态,直到信号Ser_in_0的信号变为低电平进入starting状态。
在starting状态下,状态机重复采样Serial_in以确定第一位是否是有效起始位0,在Sample_clk的下一个时钟有效沿,inc_sample_count,clr_sample_counter需要根据采样值确定是增加计数值还是清零:如果接下来Serial_in的连续三个采样值都为0,则认为有效起始位到达,状态机转移到receiving状态并且将Sample_counter清零。
在receiving状态下inc_Sample_counter有效时,状态机进入八次连续采样,Bit_counter增加。如果采样的位不是最后一个校验位,则inc_Bit_counter和shift保持有效,信号shift有效时采样值将载入接收器移位寄存器RCV_shftreg的MSB位,而且寄存器最左边的7位向LSB移动。

在采样完成后,状态机将输出到主机的握手信号read_not_ready_out置为有效并且清除位寄存器,同时检查数据完整性和主机状态:如果read_not_ready_in有效则表明主机未准备好接受数据(Error1有效),如下一位不是停止位(Serial_in_0=1)则说明接收数据的格式错误(Error2),最后load信号有效时移位寄存器中的内容将以并行格式发送到与data_bus直接相连接的主机数据寄存器RCV_datareg中。

实现代码如下

module UART_RCVR #(parameter word_size = 8, half_word = word_size/2)(
	output [word_size-1:0] 	RCV_datareg,
	output					read_not_ready_out,
							Error1,Error2,
	input					Serial_in,
							read_not_ready_in,
							Sample_clk,
							rst_b
);
	Control_Unit M0(
		read_not_ready_out,
		Error1,Error2,
		clr_Sample_counter,
		inc_Sample_counter,
		clr_Bit_counter,
		inc_bit_counter,
		shift,
		load,
		read_not_ready_in,
		Ser_in_0,
		SC_eq_3,
		SC_It_7,
		BC_eq_8,
		Sample_clk,
		rst_b
	);

	Datapath_Unit M1(
		RCV_datareg,
		Ser_in_0,
		SC_eq_3,
		SC_It_7,
		BC_eq_8,
		Serial_in,
		clr_Sample_counter,
		inc_Sample_counter,
		clr_Bit_counter,
		inc_bit_counter,
		shift,
		load,
		Sample_clk,
		rst_b
	);
	
endmodule

module Control_Unit #(parameter
	word_size = 8, half_word = word_size/2, Num_state_bits = 2,
	idle = 2'b00, starting = 2'b01, receiving = 2'b10
)(
	output reg 	read_not_ready_out,
				Error1,Error2,
				clr_Sample_counter,
				inc_Sample_counter,
				clr_Bit_counter,
				inc_bit_counter,
				shift,
				load,
	input		read_not_ready_in,
				Ser_in_0,
				SC_eq_3,
				SC_It_7,
				BC_eq_8,
				Sample_clk,
				rst_b
);

	reg		[word_size-1:0] RCV_shftreg;
	reg		[Num_state_bits-1:0]	state,next_state;
	
	always@(posedge Sample_clk)
		if(rst_b == 1'b0) state <= idle; else state <= next_state;
		
	always@(state,Ser_in_0,SC_eq_3,SC_It_7,read_not_ready_in)begin
		read_not_ready_out = 0;
		clr_Bit_counter = 0;
		clr_Sample_counter = 0;
		inc_Sample_counter = 0;
		inc_bit_counter = 0;
		shift = 0;
		Error1 = 0;
		Error2 = 0;
		load = 0;
		next_state = idle;
		case(state)
			idle:		if(Ser_in_0 == 1'b1)next_state = starting;
						else next_state = idle;
			starting:	if(Ser_in_0 == 1'b0)begin
							next_state = idle;
							clr_Sample_counter = 1;
						end else
						if(SC_eq_3 == 1'b1)begin
							next_state = receiving;
							clr_Sample_counter = 1;
						end else begin
							inc_Sample_counter = 1;
							next_state = starting;
						end
			receiving:	if(SC_It_7 == 1'b1)begin
						inc_Sample_counter = 1;
						next_state = receiving;
						end
						else begin
							clr_Sample_counter = 1;
							if(!BC_eq_8)begin
								shift = 1;
								inc_bit_counter = 1;
								next_state = receiving;
							end
							else begin
								next_state = idle;
								read_not_ready_out = 1;
								clr_Bit_counter = 1;
								if(read_not_ready_in == 1'b1)Error1 = 1;
								else if(Ser_in_0 == 1'b1)Error2 = 1;
								else load = 1;
							end
						end
			default:	next_state = idle;
		endcase
	end
endmodule

module Datapath_Unit #(parameter
	word_size = 8,half_word = word_size/2,Num_counter_bits = 4
)(
	output reg		[word_size-1:0]		RCV_datareg,
	output								Ser_in_0,
										SC_eq_3,
										SC_It_7,
										BC_eq_8,
	input								Serial_in,
										clr_Sample_counter,
										inc_Sample_counter,
										clr_Bit_counter,
										inc_bit_counter,
										shift,
										load,
										Sample_clk,
										rst_b
);

	reg		[word_size-1:0]			RCV_shftreg;
	reg		[Num_counter_bits-1:0]	Sample_counter;
	reg		[Num_counter_bits:0]	Bit_counter;
	
	assign	Ser_in_0 = (Serial_in == 0);
	assign  BC_eq_8 = (Bit_counter == word_size);
	assign  SC_It_7 = (Sample_counter < word_size-1);
	assign  SC_eq_3  = (Sample_counter == half_word - 1);
	
	always@(posedge Sample_clk)
		if(rst_b == 1'b0)begin
			Sample_counter <= 0;
			Bit_counter <= 0;
			RCV_datareg <= 0;
			RCV_shftreg <= 0;
		end
		else begin
			if(clr_Sample_counter == 1) Sample_counter <= 0;
			else if(inc_Sample_counter == 1)Sample_counter <= Sample_counter + 1;
			
			if(clr_Bit_counter == 1) Bit_counter <= 0;
			else if(inc_bit_counter == 1)Bit_counter <= Bit_counter + 1;
			
			if(shift == 1) RCV_shftreg <= {Serial_in,RCV_shftreg[word_size-1:1]};
			if(load == 1) RCV_datareg <= RCV_shftreg;
		end
endmodule 

测试代码如下

module test_UART_receiver();
  parameter	word_size = 8;
  parameter jump = 2*word_size;
  reg  Serial_in;
  reg rst_b, read_not_ready_in;
  wire [word_size - 1:0] RCV_datareg;
  wire read_not_ready_out, Error1, Error2;
  wire Sample_clk;

  UART_RCVR M3(RCV_datareg, read_not_ready_out, Error1, Error2, Serial_in, read_not_ready_in, Sample_clk, rst_b);

Clock_Unit M4 (Sample_clk);

initial #5000 $finish;
initial begin #1 rst_b = 1; #4 rst_b = 0; #5 rst_b = 1; end
initial begin #4 read_not_ready_in = 0; end  // change to 1 for test
initial begin   

  #1 Serial_in = 1;		// stopped	
  #14	Serial_in = 0;	
  #jump Serial_in = 1;	// start bit
  #jump Serial_in = 0;	// word: hb5
  #jump Serial_in = 1;
  #jump Serial_in = 1;
  #jump Serial_in = 0;
  #jump Serial_in = 1;
  #jump Serial_in = 0;
  #jump Serial_in = 1;
  #jump Serial_in = 1;  // stop bit


/*

#2 Serial_in = 1;		// stopped		
  #4 Serial_in = 0;	// start bit
  #jump Serial_in = 1;	// word: h55
  #jump Serial_in = 0;
  #jump Serial_in = 1;
  #jump Serial_in = 0;
  #jump Serial_in = 1;
  #jump Serial_in = 0;
  #jump Serial_in = 1;
  #jump Serial_in = 0;	//parity bit
  #jump Serial_in = 1;  // stop bit
*/
/*
  #2 Serial_in = 1;
  #6 Serial_in = 0;
  #22 Serial_in = 1;
  #38 Serial_in = 0;
  #54 Serial_in = 1;
  #70 Serial_in = 0;
  #86 Serial_in = 1;
  #118 Serial_in = 0;
  #134 Serial_in = 1;
  //#154 Serial_in = 0;	// error - missing stop bit

  #200 Serial_in = 0;
  #300 Serial_in = 1; */


end //join
endmodule

module Clock_Unit(output reg Clock);
parameter delay = 0;
parameter Pulse_Width = 1;
initial begin #delay Clock = 0; forever #Pulse_Width Clock = ~Clock;end
endmodule

仿真结果与书一致
UART接收器_第4张图片

你可能感兴趣的:(Verilog,HDL高级数字设计学习笔记)