基本原理:通过边沿检测电路检测起始位,一位数据通过采样多次并统计得到高电平出现的次数,次数多的即为该位的电平值。
仿真波形
设计文件程序
module UART(
Clk,
Reset_N,
Baud_Set,
UART_RX,
Data,
Rx_Done
);
input Clk;
input Reset_N;
input [2:0]Baud_Set;
input UART_RX;
output reg [7:0]Data;
output reg Rx_Done;
reg [1:0]UART_RX_R;
always@(posedge Clk)begin
UART_RX_R[0] <= UART_RX;
UART_RX_R[1] <= UART_RX_R[0];
end
wire pedge_UART_RX;
wire nedge_UART_RX;
//上升沿检测
// assign pedge_UART_RX = ((UART_RX_R[0] == 1) && (UART_RX_R[1] == 0));
assign pedge_UART_RX = (UART_RX_R == 2'b01);
//下降沿检测
// assign nedge_UART_RX = ((UART_RX_R[0] == 0) && (UART_RX_R[1] == 1));
assign nedge_UART_RX = (UART_RX_R == 2'b10);
// Baud_Set BaudRate
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
//针对不同的波特率,计算相对应的时间长度
reg [17:0]bps_DR;
parameter Time = 32'd1000000000;
always@(*)
case(Baud_Set)
// 16:16倍采样
0: bps_DR = Time/9600/16/20 - 1;
1: bps_DR = Time/19200/16/20 - 1;
2: bps_DR = Time/38400/16/20 - 1;
3: bps_DR = Time/57600/16/20 - 1;
4: bps_DR = Time/115200/16/20 - 1;
default: bps_DR = Time/9600/16/20 - 1;
endcase
// 16段中心采样位置
wire bps_clk_16x;
assign bps_clk_16x = (div_cnt == bps_DR / 2);
reg RX_EN;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
RX_EN <= 0;
else if(nedge_UART_RX)
RX_EN <= 1;
else if(Rx_Done || (start_bit >= 4))
RX_EN <= 0;
// 每小分段计数器
reg [8:0]div_cnt;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
div_cnt <= 0;
else if(RX_EN)begin
if(div_cnt == bps_DR)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'd1;
end
else
div_cnt <= 0;
// 每帧数据中160小段计数器
reg [7:0]bps_cnt;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
bps_cnt <= 0;
else if(RX_EN)begin
if(bps_clk_16x)begin
if(bps_cnt == 160)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1'd1;
end
else
bps_cnt <= bps_cnt;
end
else
bps_cnt <= 0;
// 二维寄存器 reg width name number
reg [2:0]r_data[7:0];
reg [2:0]start_bit;
reg [2:0]end_bit;
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)begin
r_data[0] <= 0;
r_data[1] <= 0;
r_data[2] <= 0;
r_data[3] <= 0;
r_data[4] <= 0;
r_data[5] <= 0;
r_data[6] <= 0;
r_data[7] <= 0;
start_bit <= 0;
end_bit <= 0;
end
else if(bps_clk_16x)begin
case(bps_cnt)
0:begin
r_data[0] <= 0;
r_data[1] <= 0;
r_data[2] <= 0;
r_data[3] <= 0;
r_data[4] <= 0;
r_data[5] <= 0;
r_data[6] <= 0;
r_data[7] <= 0;
start_bit <= 0;
end_bit <= 0;
end
5,6,7,8,9,10,11: start_bit <= start_bit + UART_RX;
21,22,23,24,25,26,27: r_data[0] <= r_data[0] + UART_RX;
37,38,39,40,41,42,43: r_data[1] <= r_data[1] + UART_RX;
53,54,55,56,57,58,59: r_data[2] <= r_data[2] + UART_RX;
69,70,71,72,73,74,75: r_data[3] <= r_data[3] + UART_RX;
85,86,87,88,89,90,91: r_data[4] <= r_data[4] + UART_RX;
101,102,103,104,105,106,107: r_data[5] <= r_data[5] + UART_RX;
117,118,119,120,121,122,123: r_data[6] <= r_data[6] + UART_RX;
133,134,135,136,137,138,139: r_data[7] <= r_data[7] + UART_RX;
149,150,151,152,153,154,155: end_bit <= end_bit + UART_RX;
default:;
endcase
end
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
Data <= 0;
else if(bps_clk_16x && (bps_cnt == 159))begin
Data[0] <= (r_data[0] >= 4)?1'b1:1'b0;
Data[1] <= (r_data[1] >= 4)?1'b1:1'b0;
Data[2] <= (r_data[2] >= 4)?1'b1:1'b0;
Data[3] <= (r_data[3] >= 4)?1'b1:1'b0;
Data[4] <= (r_data[4] >= 4)?1'b1:1'b0;
Data[5] <= (r_data[5] >= 4)?1'b1:1'b0;
Data[6] <= (r_data[6] >= 4)?1'b1:1'b0;
Data[7] <= (r_data[7] >= 4)?1'b1:1'b0;
end
always@(posedge Clk or negedge Reset_N)
if(!Reset_N)
Rx_Done <= 0;
else if((div_cnt == bps_DR / 2) && (bps_cnt == 160))
Rx_Done <= 1;
else
Rx_Done <= 0;
endmodule
仿真文件程序
`timescale 1ns / 1ns
module UART_tb();
reg Clk;
reg Reset_N;
reg UART_RX;
wire [7:0]Data;
wire Rx_Done;
UART UART(
.Clk(Clk),
.Reset_N(Reset_N),
.Baud_Set(4),
.UART_RX(UART_RX),
.Data(Data),
.Rx_Done(Rx_Done)
);
initial Clk <= 0;
always #10 Clk <= !Clk;
initial begin
Reset_N <= 0;UART_RX = 1;
#201;
Reset_N <= 1;
#200;
uart_tx_byte(8'h5a);
#9000;
uart_tx_byte(8'ha5);
#9000;
uart_tx_byte(8'h6f);
#9000;
$stop;
end
task uart_tx_byte;
input [7:0]tx_data;
begin
UART_RX = 1;
#20;
UART_RX = 0;
#8680;
UART_RX = tx_data[0];
#8680;
UART_RX = tx_data[1];
#8680;
UART_RX = tx_data[2];
#8680;
UART_RX = tx_data[3];
#8680;
UART_RX = tx_data[4];
#8680;
UART_RX = tx_data[5];
#8680;
UART_RX = tx_data[6];
#8680;
UART_RX = tx_data[7];
#8680;
UART_RX = 1;
#8680;
end
endtask
endmodule