1.接收原理和思路
初步思路:除发送位和停止位外,在数据位的每一位数据的中间时刻进行采样,读取到高电平或者低电平,如图所示:图中读取到的数据位为0110(左至右)
但是,倘若有外界干扰,忽然将某数据位的电平拉低了一瞬间,如图:此时再在各个数据位的中间时刻检测会检测到:0010(从左至右)很显然是错误的。
解决办法:在每一位的数据位上进行多次采样,然后比较0和1的概率。1的概率大就为高电平,0的概率大就为低电平。
然后还需要检测起始位,怎么检测起始位呢?边缘检测电路!边缘检测电路原理如下:
当波形2的第一个上升沿检测到波形 1的的值为1,第二个上升沿检测到波形1的值为0时,就说明其产生了下降沿。边缘检测电路由两个触发器构成,如图所示:
接下来就可以开始代码编写啦!
源文件代码:
module uart_tx(
input clk,
input uart_rx, //从外部接收到的数据
input rst,//复位
input [2:0] Baud_set,//选择接收数据的波特率,要和发送数据的波特率一致
output reg [7:0] Rx_Data, //最后我们看到的数据
output reg Rx_Done
);
reg Rx_En;//开始接收数据
//设置波特率
reg [17:0] Baud;
always@(Baud_set)
case(Baud_set)
3'd0:Baud=18'd166666;//波特率为300
3'd1:Baud=18'd41666;//波特率为1200
3'd2:Baud=18'd20833;//波特率为2400
3'd3:Baud=18'd5208;//波特率为9600
3'd4:Baud=18'd2604;//波特率为19200
3'd5:Baud=18'd1302;//波特率为38400
3'd6:Baud=18'd868;//波特率为57600
3'd7:Baud=18'd434;//波特率为115200
endcase
//波特率分频
reg [17:0] counter_Baud;
always@(posedge clk or negedge rst)
if(!rst) counter_Baud<=0;
else if(Rx_En)
begin
if(counter_Baud==Baud-1) counter_Baud<=0;
else counter_Baud<=counter_Baud+1;
end
else counter_Baud<=0;
//检测起始位
reg [1:0] Detect;
always@(posedge clk or negedge rst)
if(!rst) Detect<=2'b00;
else if(!Rx_En)
begin
Detect[0] <= uart_rx;
Detect[1] <= Detect[0];
end
else Detect<=2'b00;
//控制En
always@(posedge clk or negedge rst)
if(!rst) Rx_En<=0;
else if(Detect==2'b10) Rx_En<=1;
else if(Rx_Done) Rx_En<=0;
else Rx_En<=Rx_En;
//设置采样时钟
//每位数据为分成16段,舍弃前5段后4段,取中间7段进行采样
reg [7:0] counter_1; //对采样次数进行计数
reg [4:0] counter_time; //counter_time计时到24时(1s/115200/16/20=24),为一个时间间隔
wire [14:0] caiyang; // 每位数据为分成16段,每一小段的时间为1s/115200/16,故每一小段的计数值为1s/115200/20/16=Baud/16;
assign caiyang = Baud/16;
always@(posedge clk or negedge rst)
if(!rst) counter_time<=0;
else if(Rx_En==1 )
begin
if(counter_time==caiyang-1) counter_time<=0;
else counter_time<=counter_time+1;
end
else if(Rx_Done) counter_time<=0;
else counter_time<=0;
always@(posedge clk or negedge rst)
if(!rst) counter_1<=0;
else if(Rx_En==1)
begin
if(counter_1==160 && counter_time==18) counter_1<=0;
else if(counter_time==caiyang-1) counter_1<=counter_1+1;
else counter_1<=counter_1;
end
else if(Rx_Done) counter_1<=0;
else counter_1<=0;
wire clk_16_caiyang;
assign clk_16_caiyang = (counter_time==caiyang/2);
//开始采样
reg [3:0] x_bit [7:0]; //定义一个二维数组,该二维数组里面有7个元素,分别表示8个数据位,每个元素位宽三位
reg [3:0] start;//起始位
reg [3:0] stop;//停止位
always@(posedge clk or negedge rst)
if(!rst) begin
start<=0;
stop<=0;
x_bit[0]<=0;
x_bit[1]<=0;
x_bit[2]<=0;
x_bit[3]<=0;
x_bit[4]<=0;
x_bit[5]<=0;
x_bit[6]<=0;
x_bit[7]<=0;
end
else if(clk_16_caiyang)
begin
case(counter_1)
0: begin
start<=0;
stop<=0;
x_bit[0]<=0;
x_bit[1]<=0;
x_bit[2]<=0;
x_bit[3]<=0;
x_bit[4]<=0;
x_bit[5]<=0;
x_bit[6]<=0;
x_bit[7]<=0;
end
5,6,7,8,9,10,11:start<=start+uart_rx;
21,22,23,24,25,26,27:x_bit[0]<=x_bit[0]+uart_rx;
37,38,39,40,41,42,43:x_bit[1]<=x_bit[1]+uart_rx;
53,54,55,56,57,58,59:x_bit[2]<=x_bit[2]+uart_rx;
69,70,71,72,73,74,75:x_bit[3]<=x_bit[3]+uart_rx;
85,86,87,88,89,90,91:x_bit[4]<=x_bit[4]+uart_rx;
101,102,103,104,105,106,107:x_bit[5]<=x_bit[5]+uart_rx;
117,118,119,120,121,122,123:x_bit[6]<=x_bit[6]+uart_rx;
133,134,135,136,137,138,139:x_bit[7]<=x_bit[7]+uart_rx;
149,150,151,152,153,154,155:stop<=stop+uart_rx;
default: begin
start<=start;
x_bit[0]<=x_bit[0];
x_bit[1]<=x_bit[1];
x_bit[2]<=x_bit[2];
x_bit[3]<=x_bit[3];
x_bit[4]<=x_bit[4];
x_bit[5]<=x_bit[5];
x_bit[6]<=x_bit[6];
x_bit[7]<=x_bit[7];
stop<=stop;
end
endcase
end
else begin
start<=start;
x_bit[0]<=x_bit[0];
x_bit[1]<=x_bit[1];
x_bit[2]<=x_bit[2];
x_bit[3]<=x_bit[3];
x_bit[4]<=x_bit[4];
x_bit[5]<=x_bit[5];
x_bit[6]<=x_bit[6];
x_bit[7]<=x_bit[7];
stop<=stop;
end
//控制Rx_Done
always@(posedge clk or negedge rst)
if(!rst) Rx_Done<=0;
else if(counter_1==160&&counter_time==18) Rx_Done<=1;
else Rx_Done<=0;
//判断采样得到的数据并且进行赋值
reg Data_start;
reg Data_stop;
always@(posedge clk or negedge rst)
if(!rst) Rx_Data<=0;
else if(counter_1==159)
begin
Data_start<=(start>=3'd4)?1'b1:1'd0;
Data_stop<=(stop>=3'd4)?1'b1:1'd0;
Rx_Data[0]<=(x_bit[0]>=3'd4)?1'b1:1'd0;
Rx_Data[1]<=(x_bit[1]>=3'd4)?1'b1:1'd0;
Rx_Data[2]<=(x_bit[2]>=3'd4)?1'b1:1'd0;
Rx_Data[3]<=(x_bit[3]>=3'd4)?1'b1:1'd0;
Rx_Data[4]<=(x_bit[4]>=3'd4)?1'b1:1'd0;
Rx_Data[5]<=(x_bit[5]>=3'd4)?1'b1:1'd0;
Rx_Data[6]<=(x_bit[6]>=3'd4)?1'b1:1'd0;
Rx_Data[7]<=(x_bit[7]>=3'd4)?1'b1:1'd0;
end
else Rx_Data<=Rx_Data;
endmodule
激励文件代码:
module uart_rx_tb();
reg clk;
reg uart_rx; //从外部接收到的数据
reg rst;//复位
reg [2:0] Baud_set;//选择接收数据的波特率,要和发送数据的波特率一致
wire [7:0] Rx_Data; //最后我们看到的数据
wire Rx_Done;
uart_tx uart_tx_Inst(
.clk(clk),
.uart_rx(uart_rx),
.rst(rst),
.Baud_set(Baud_set),
.Rx_Data(Rx_Data),
.Rx_Done(Rx_Done)
);
initial clk=1;
initial Baud_set=3'd7;
always #10 clk=~clk;
initial
begin
rst=0;
uart_rx=1;
#200;
rst=1;
uart_tx_byte(8'b11011011);
@(posedge Rx_Done)
#5000;
uart_tx_byte(8'b10011010);
@(posedge Rx_Done)
#6000;
uart_tx_byte(8'b10011110);
end
task uart_tx_byte; //发送一个字节
input [7:0] tx_data;
begin
uart_rx=1;
#200;
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
代码已测试可以使用!