UART介绍
通过串行数据通道进行信息交换和远程交互的系统使用串行器/解串器(SerDes)接口进行数据串并格式的转换。它作为主机/设备和串行数据通路之间的接口如图。主机以并行字格式储存信息,以串行单比特格式发送和接受数据。调试解调器也称异步收发器(UART),该设备能够接受和发送串行数据,而且接受和发送单元不同步。
UART以ASCII码格式交换文本信息。其中每个字母符号采用7位编码和1位错误检验的奇偶校验码。在发送方,UART对位数据打包在最低位上增加起始位,在最高位增加停止位,如图。
从起始位开始的前9个数据位按顺序发送,每个位持续一个UART的时钟周期,停止位的有效时间可能超过一个时钟周期。
UART接收器的实现代码如链接
UART接收器
UART发送器介绍
UART发送器的接口信号如图
其中,输入信号由主机提供,输出信号只有一个串行数据流Serial_out。该发送器包括了控制器、用于计数已发送比特数的状态寄存器(Bit_count)、数据寄存器(XMT_datareg)、数据移位寄存器(XMT_shftreg),第二个在包含在数据通路中,后两个寄存器位于Datapath_unit中。
各位信号解释如下:
Load_XMT_datareg:idle状态下决定Load_XMT_DR的值(判断是否需要将Data_Bus的内容送到XMT_datareg)
Byte_ready:决定Load_XMT_shftreg信号的值(确定是否将XMT_datareg的内容载入XMT_shftreg)
T_byte:确定字节数据的传输开始,包括停止位,起始位,校验位。
BC_It_BCmax:用于指示数据通路中比特计数器的状态
控制状态机输出信号:
Load_XMT_DR:声明将Data_Bus中的内容载入XMT_datareg
Load_XMT_shftreg:声明将XMT_data_reg的内容载入XMT_shftreg
start:将XMT_shftreg[0]清0表示数据的传输开始
shift:将XMT_shftreg向LSB方向移一位,并用停止位(1)回填
clear:将bit_count清零
工作模式
描述UART发送器的工作状态用状态机描述,由idle,waiting,sending三个状态。
一:当复位信号rst有效时,状态机进入idle状态,bit_count清零,将XMT_shftreg的所有位初始化为1,在idle状态下,外部主机在时钟有效沿判定Load_XMT_datareg有效后,输出信号Load_XMT_DR将Data_Bus的内容载入XMT_datareg,状态机保持idle状态知道start有效而且让XMT_shftreg[0]清零。
二:当Byte_ready有效(同时rst和Load_XMT_datareg无效),Load_XMT_shftreg为有效值,状态机进入waiting状态,Load_XMT_shftreg有效表表明XMT_datareg送到内部寄存器执行相应操作,分三个步骤:(1)状态idle转到waiting,(2)XMT_datareg的内容载入XMT_shftrerg最左边比特——XMT_shftreg是一个(word_size+1)位的移位寄存器,它的LSB位表示传输的起始和终止(3)XMT_shftreg的LSB重载入1(停止位)。状态机保持waiting状态直到外部主机声明T_byte有效
三:T_byte有效后下一个时钟有效沿,状态机进入sending状态,XMT_shftreg的LSB置0产生传送开始信号。同时shift置为1保持sending状态,在传送过程中,shift始终有效,XMT_shftreg的内容向LSB移位并且驱动外部串行通道,数据移位时候XMT_shftreg用1回填,bit_count加一操作,在sending状态下bit_count小于9(BC_It_BCmax有效)时shift有效,当bit_count等于9,(BC_It_BCmax无效,clear有效),表示该字所有位已经串行输出,然后在下一个有效状态返回idle状态。
其中UART发送器的ASM图如下
UART发送器的控制信号和数据流如下
实现代码与测试代码
module UART_XMTR #(parameter word_size = 8)(
output Serial_out,
input [word_size-1:0] Data_Bus,
input Load_XMT_datareg,
Byte_ready,
T_byte,
Clock,
rst_b
);
Control_Unit M0(Load_XMT_DR,Load_XMT_shftreg,start,shift,clear,Load_XMT_datareg,
Byte_ready,T_byte,BC_It_BCmax,Clock,rst_b);
Datapath_Unit M1(Serial_out,BC_It_BCmax,Data_Bus,Load_XMT_DR,Load_XMT_shftreg,start,shift,clear,Clock,rst_b);
endmodule
module Control_Unit #(
parameter one_hot_count = 3,
state_count = one_hot_count,
size_bit_count = 3,
idle = 3'b001,
waiting = 3'b010,
sending = 3'b100,
all_ones = 9'b1_1111_1111
)(
output reg Load_XMT_DR,
output reg Load_XMT_shftreg,
output reg start,
output reg shift,
output reg clear,
input Load_XMT_datareg,
input Byte_ready,
input T_byte,
input BC_It_BCmax,
input Clock,
input rst_b
);
reg [state_count-1:0] state,next_state;
always@(state,Load_XMT_datareg,Byte_ready,T_byte,BC_It_BCmax)begin:output_and_next_state
Load_XMT_DR = 0;
Load_XMT_shftreg = 0;
start = 0;
shift = 0;
clear = 0;
next_state = idle;
case(state)
idle: if(Load_XMT_datareg == 1'b1)begin
Load_XMT_DR = 1;
next_state = idle;
end
else if(Byte_ready == 1'b1)begin
Load_XMT_shftreg = 1;
next_state = waiting;
end
waiting: if(T_byte == 1'b1)begin
start = 1;
next_state = sending;
end else next_state = waiting;
sending: if(BC_It_BCmax)begin
shift = 1;
next_state = sending;
end
else begin
clear = 1;
next_state = idle;
end
default: next_state = idle;
endcase
end
always@(posedge Clock, negedge rst_b)begin:state_transitions
if(rst_b == 1'b0) state <= idle; else state <= next_state;
end
endmodule
module Datapath_Unit #(
parameter word_size = 8,
size_bit_count = 3,
all_ones = {(word_size+1){1'b1}}
)(
output Serial_out,BC_It_BCmax,
input [word_size-1:0] Data_Bus,
input Load_XMT_DR,Load_XMT_shftreg,start,shift,clear,Clock,rst_b
);
reg [word_size-1:0] XMT_datareg;
reg [word_size:0] XMT_shftreg;
reg [size_bit_count:0] bit_count;
assign Serial_out = XMT_shftreg[0];
assign BC_It_BCmax = (bit_count < word_size + 1);
always@(posedge Clock, negedge rst_b)
if(rst_b == 1'b0)begin
XMT_shftreg <= all_ones;
bit_count <= 0;
end
else begin
if(Load_XMT_DR == 1'b1)XMT_datareg <= Data_Bus;
if(Load_XMT_shftreg == 1'b1) XMT_shftreg <= {XMT_datareg,1'b1};
if(start == 1'b1) XMT_shftreg[0] <= 0;
if(clear == 1'b1) bit_count <= 0;
if(shift == 1'b1)begin
XMT_shftreg <= {1'b1,XMT_shftreg[word_size:1]};
bit_count <= bit_count + 1;
end
end
endmodule
测试代码
module Test_uart8();
parameter word_size = 8;
reg [word_size-1:0] Data_Bus;
reg Byte_ready, Load_XMT_datareg, T_byte, rst_b;
wire Serial_out;
wire Clock;
reg [5:0] k;
reg [word_size+1:0] Serial_test;
UART_XMTR M0
(Serial_out, Data_Bus,Load_XMT_datareg, Byte_ready, T_byte, Clock, rst_b);
Clock_Unit M2 (Clock);
initial #2000 $finish;
initial begin #5 rst_b =0;#5 rst_b =1 ; end
initial begin #40 Byte_ready = 1; #10 Byte_ready = 0; end
initial begin #10 Load_XMT_datareg = 0; #10 Load_XMT_datareg = 1; #10 Load_XMT_datareg = 0; end
initial begin #90 Load_XMT_datareg=1; #10 Load_XMT_datareg = 0;end
initial begin #120 Load_XMT_datareg = 1; #10 Load_XMT_datareg = 0; end
always @ (posedge Clock or negedge rst_b)
if (rst_b == 0) Serial_test <= 0;
else Serial_test <= {Serial_out, Serial_test[word_size+1 : 1]};
wire [word_size-1:0] sent_word = Serial_test[word_size:1];
initial begin
#80 T_byte = 1;
forever begin
#10 T_byte = ~T_byte;#120 T_byte = ~T_byte;
end
end
initial begin
#5 Data_Bus <= 8'b1010_0111; // ha6
#80 Data_Bus <= 8'b0001_1010; // h1a
#40 Data_Bus <= 8'hb4;
end
endmodule
module Clock_Unit(output reg Clock);
parameter delay = 0;
parameter Pulse_Width = 5;
initial begin #delay Clock = 0; forever #Pulse_Width Clock = ~Clock;end
endmodule
仿真结果
用modelsim仿真与书中一样!
谢谢!