UART发送器
先看UART发送器模块再看本文!
这两个模块可以仿真通过,代码文末贴上。
UART发送器简介
UART接收器负责接受串行比特流,去除起始位并且以并行格式将数据保存到主机数据相连接的寄存器中。
接受器的时钟信号是发送器时钟信号的八倍,这样使得接受器可以在发送器对应一个时间间隔内工作。
输入为低电平后连续采样到0值表明起始位到来,而且增加三次采样来确定起始位是否有效,此后的8个连续位在每个发送时钟周期内被采样。
UART接收器中控制器和数据通道之间的接口信号描述如图
各个信号意义如下
接收器状态机控制器的状态一共有三个: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
仿真结果与书一致