利用两个D触发器来作为边沿检测电路
//两个D触发器的存储逻辑电路
reg [1:0]uart_rx_r;
always@(posedge Clk)begin
uart_rx_r[0]<=uart_rx;
uart_rx_r[1]<=uart_rx_r[0];[1]是前一时刻的值
end
//检测上/下降沿
wire pedge_uart_rx;//检测上升沿
assign pedge_uart_rx=((uart_rx_r[1]==0)&&(uart_rx_r[0]==1));
//等价于assign pedge_uart_rx=(uart_rx_r==2'b01)?1:0;
wire nedge_uart_rx;//检测下降沿沿
assign nedge_uart_rx=((uart_rx_r[1]==1)&&(uart_rx_r[0]==0));
//等价于assign pedge_uart_rx=(uart_rx_r==2'b10)?1:0;
分段采样
时间精度:设波特率为9600,则计数周期为1000000000/9600/16/20= 325,即计数325次产生一个BPS_CLK,除以16的原因是因为将一段数据分成了16段,以方便有舍取得进行采样。
若为115200,则计数周期为27。
module uart_byte_rx(
Clk,
Reset_n,
Baud_Set,
uart_rx,
Data,
Rx_Done
);
input Clk;
inout 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;//检测上升沿
assign pedge_uart_rx=((uart_rx_r[1]==0)&&(uart_rx_r[0]==1));
//等价于assign pedge_uart_rx=(uart_rx_r==2'b01)?1:0;
wire nedge_uart_rx;//检测下降沿沿
assign nedge_uart_rx=((uart_rx_r[1]==1)&&(uart_rx_r[0]==0));
//等价于assign pedge_uart_rx=(uart_rx_r==2'b10)?1:0;
//柑橘波特路计算计数周期
reg [8:0] Bps_DR;
always@(*)
case(Baud_Set)
0:Bps_DR=100000000/9600/16/20-1;
1:Bps_DR=100000000/19200/16/20-1;
2:Bps_DR=100000000/38400/16/20-1;
3:Bps_DR=100000000/57600/16/20-1;
4:Bps_DR=100000000/115200/16/20-1;
default:Bps_DR=100000000/9600/16/20-1;
endcase
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||sta_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'b1;
end
else
div_cnt<=0;
//计数
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'b1;
end
else
bps_cnt<=bps_cnt;
end
else
bps_cnt<=0;
//计采样个数
reg[2:0]r_data[7:0];//定义了一个二维寄存器,前面定义位宽,后面是个数,例r_data[0][1]
reg[2:0]sta_bit;
reg[2:0]sto_bit;
//接收
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)begin
sta_bit<=0;
sto_bit<=0;
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;
end
else if(bps_clk_16x) begin
case(bps_cnt)
0:begin
sta_bit<=0;
sto_bit<=0;
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;
end
5,6,7,8,9,10,11:sta_bit<=sta_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:sto_bit<=sto_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[0]<=r_data[0][2];
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
//因为除法保留整数,所以存在误差。
testbench
`timescale 1ns/1ps
module uart_byte_rx_tb();
reg Clk;
reg Reset_n;
wire [2:0]Baud_Set;
reg uart_rx;
wire [7:0]Data;
wire Rx_Done;
assign Baud_Set=4;
uart_byte_rx uart_byte_rx(
Clk,
Reset_n,
Baud_Set,
uart_rx,
Data,
Rx_Done
);
initial Clk=1;
always#10 Clk=~Clk;
initial begin
Reset_n=0;
uart_rx=1;
#201;
Reset_n=1;
#200;
uart_tx_byte(8'h5a);
//@(posedge Rx_Done);
#90000;
uart_tx_byte(8'ha5);
// @(posedge Rx_Done);
#90000;
uart_tx_byte(8'h86);
//@(posedge Rx_Done);
#90000;
$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