1接收原理
对于每一位的采样点而言,一般认为每一位数据中心点采样是最稳定,下图是串口接收模块的时序图
但是在工业控制或者实际生产实践中单单采样一次往往是不可靠的,环境中充满了各种各样的电磁干扰,很可能由此而采样到错误的信号。使用改进型单比特采用 ,通过概率计算,来求出最优的采样信号的点。并且进行状态判断。
中间段灰色的实际是采样的信号点。
2串口异步通信接收模块设计和实现
2.1串口异步通信总模块封装
模块中接口部分的设计
rx_done | O | 读取字符串完成 |
2.2各个子模块设计
2.2.1单比特bit同步信号设计
为了规避信号设计中亚稳态的问题,在电路设计过程中要将信号同步到fpga信号的时钟域,同步方式是将信号延迟两拍,打两拍。
//同步串行输入信号,消除亚稳态
always@(posedge clk or posedge reset)
if(reset)begin
uart_rx_sync1 <= 1'b0;
uart_rx_sync2 <= 1'b0;
end
else begin
uart_rx_sync1 <= uart_rx;
uart_rx_sync2 <= uart_rx_sync1;
end
2.2.2边沿检测模块
下降沿检测-01 ,上升沿检测_10 双边沿检测是上升沿和下降沿的或
//数据寄存器
always@(posedge clk or posedge reset)
if(reset)begin
uart_rx_reg1 <= 1'b0;
uart_rx_reg2 <= 1'b0;
end
else begin
uart_rx_reg1 <= uart_rx_sync2;
uart_rx_reg2 <= uart_rx_reg1;
end
//下降沿检测
assign uart_rx_nedge = !uart_rx_reg1 & uart_rx_reg2;
2.2.3采样时钟模块设计
根据接收协议表明采样频率是波特率频率的16倍,举例,假设波特率为9600 ,波特率周期为1041ns 假定时钟为50M,周期为20ns。 计数值为 1041 / 20 / 16 = 325 。下表是常见的采样时钟的计算方式。
always@(posedge clk or posedge reset)
if(reset)
bps_DR <= 16'd324;
else begin
case(baud_set)
0:bps_DR <= 16'd324;
1:bps_DR <= 16'd162;
2:bps_DR <= 16'd80;
3:bps_DR <= 16'd53;
4:bps_DR <= 16'd26;
default:bps_DR <= 16'd324;
endcase
end
产生采样时钟,其为波特率频率的16倍
always@(posedge clk or posedge reset)
if(reset)
div_cnt <= 16'd0;
else if(uart_state)begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
当计数到1的时候,时钟频率拉高,其它的时刻时钟的频率为0
// bps_clk gen
always@(posedge clk or posedge reset)
if(reset)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
bps_counter 计数器累加到159时候说明已经串口已经将所有的数据接收完成了。我们进行累加采样的时候只要累加采样点的中间频段,下一位采样的时候只要加16,也就是这个字所占用的总的clk时钟,如果bps_counter 计数器开始采样的时候,也就是第12个时钟沿到来的时候,此时start
字中高电平的采样值大于2的时候,说明start_bit 字的电平为高电平,而实际上start_bit应该为低电平此时说明收到了干扰采样的信息是不准确的。
//bps counter
always@(posedge clk or posedge reset)
if(reset)
bps_cnt <= 8'd0;
else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && (START_BIT > 2)))
bps_cnt <= 8'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
rx_done 采样完成
always@(posedge clk or posedge reset)
if(reset)
rx_done <= 1'b0;
else if(bps_cnt == 8'd159)
rx_done <= 1'b1;
else
rx_done <= 1'b0;
2.2.4 采样数据接收模块设计
采样思路,当数据线上出现下降沿,采取数据的中间段,并分为6次采用,如果采样的数值的总数大于2,说明该数据出现3次或者三次以上的高电平,那么就不可能符合采样起始数据要求的持续的低电平要求,说明此时的下降沿看作是干扰信号,而不是采样信号。
always@(posedge clk or posedge reset)
if(reset)begin
START_BIT <= 3'd0;
data_byte_pre[0] <= 3'd0;
data_byte_pre[1] <= 3'd0;
data_byte_pre[2] <= 3'd0;
data_byte_pre[3] <= 3'd0;
data_byte_pre[4] <= 3'd0;
data_byte_pre[5] <= 3'd0;
data_byte_pre[6] <= 3'd0;
data_byte_pre[7] <= 3'd0;
STOP_BIT <= 3'd0;
end
else if(bps_clk)begin
case(bps_cnt)
0:begin
START_BIT <= 3'd0;
data_byte_pre[0] <= 3'd0;
data_byte_pre[1] <= 3'd0;
data_byte_pre[2] <= 3'd0;
data_byte_pre[3] <= 3'd0;
data_byte_pre[4] <= 3'd0;
data_byte_pre[5] <= 3'd0;
data_byte_pre[6] <= 3'd0;
data_byte_pre[7] <= 3'd0;
STOP_BIT <= 3'd0;
end
6 ,7 ,8 ,9 ,10,11:START_BIT <= START_BIT + uart_rx_sync2;
22,23,24,25,26,27:data_byte_pre[0] <= data_byte_pre[0] + uart_rx_sync2;
38,39,40,41,42,43:data_byte_pre[1] <= data_byte_pre[1] + uart_rx_sync2;
54,55,56,57,58,59:data_byte_pre[2] <= data_byte_pre[2] + uart_rx_sync2;
70,71,72,73,74,75:data_byte_pre[3] <= data_byte_pre[3] + uart_rx_sync2;
86,87,88,89,90,91:data_byte_pre[4] <= data_byte_pre[4] + uart_rx_sync2;
102,103,104,105,106,107:data_byte_pre[5] <= data_byte_pre[5] + uart_rx_sync2;
118,119,120,121,122,123:data_byte_pre[6] <= data_byte_pre[6] + uart_rx_sync2;
134,135,136,137,138,139:data_byte_pre[7] <= data_byte_pre[7] + uart_rx_sync2;
150,151,152,153,154,155:STOP_BIT <= STOP_BIT + uart_rx_sync2;
default:
begin
START_BIT <= START_BIT;
data_byte_pre[0] <= data_byte_pre[0];
data_byte_pre[1] <= data_byte_pre[1];
data_byte_pre[2] <= data_byte_pre[2];
data_byte_pre[3] <= data_byte_pre[3];
data_byte_pre[4] <= data_byte_pre[4];
data_byte_pre[5] <= data_byte_pre[5];
data_byte_pre[6] <= data_byte_pre[6];
data_byte_pre[7] <= data_byte_pre[7];
STOP_BIT <= STOP_BIT;
end
endcase
end
2.2.5数据状态判断模块
因为数据是进行的六次采样,因此判断数据采样的总和是否大于3就可以判断出其是否是有效的数据,对预先存放的数据data_byte_pre[]存放的数据进行判断。直接令其的最高位作为数据判断的依据,如果为1 ,说明采样总值大于或者等于4,如果为0 ,说明采样的总值小于4。从而可以判断出数据的状态是0还是1.
always@(posedge clk or posedge reset)
if(reset)
data_byte <= 8'd0;
else if(bps_cnt == 8'd159)begin
data_byte[0] <= data_byte_pre[0][2];
data_byte[1] <= data_byte_pre[1][2];
data_byte[2] <= data_byte_pre[2][2];
data_byte[3] <= data_byte_pre[3][2];
data_byte[4] <= data_byte_pre[4][2];
data_byte[5] <= data_byte_pre[5][2];
data_byte[6] <= data_byte_pre[6][2];
data_byte[7] <= data_byte_pre[7][2];
end
always@(posedge clk or posedge reset)
if(reset)
uart_state <= 1'b0;
else if(uart_rx_nedge)
uart_state <= 1'b1;
else if(rx_done || (bps_cnt == 8'd12 && (START_BIT > 2)) || (bps_cnt == 8'd155 && (STOP_BIT < 3)))
uart_state <= 1'b0;
else
uart_state <= uart_state;
3 testbench测试
将之前uart_tx放入仿真文件中进行例化,测试输入数据aa ,bb 两个数据是否能够正确的发送和接收
`define CLK_PERIOD 20 //时钟周期20ns
module uart_byte_rx_tb( );
//input signal
reg clk ; //时钟
reg reset_n ; //复位信号
reg [2:0] baud_set ;
reg [7:0] data_byte_tx ; //等待传输的8bit数据
reg send_en ; //发送使能
wire tx_done ; //发送完毕
wire uart_state ;
wire [7:0] data_byte_rx ; //等待接收的8bit数据信号
wire rx_done ; //接收完毕
wire uart_tx_rx ;
//例化模块
uart_byte_tx uart_byte_tx_inst1(
.send_en ( send_en ) ,
.data_byte ( data_byte_tx ) ,
.baud_set ( baud_set ) ,
.clk ( clk ) ,
.reset_n ( reset_n ) ,
.uart_tx ( uart_tx_rx ) ,
.tx_done ( tx_done ) ,
.uart_state ( uart_state)
);
uart_byte_rx uart_byte_rx_inst1(
.clk(clk),
.reset_n(reset_n),
.baud_set(baud_set),
.uart_rx(uart_tx_rx),
.data_byte(data_byte_rx),
.rx_done(rx_done)
);
initial clk = 1 ;
always # (`CLK_PERIOD / 2 ) clk = ~clk ;
initial begin
send_en = 1'b0 ;
data_byte_tx = 8'd0 ;
baud_set = 3'd4 ;
reset_n = 1'b0 ;
#(`CLK_PERIOD *20 + 1) ;//延时20个时钟周期后
reset_n = 1'b1 ; //将复位信号拉高
#(`CLK_PERIOD *50 ) ;
//send frist byte
data_byte_tx = 8'haa ;
send_en = 1'b1 ;
#`CLK_PERIOD
send_en = 1'b0 ;
@(posedge tx_done )
#(`CLK_PERIOD * 5000 ) ;
//send second byte
data_byte_tx = 8'hbb ;
send_en = 1'b1 ;
#`CLK_PERIOD ;
send_en = 1'b0 ;
@(posedge tx_done )
#(`CLK_PERIOD * 5000) ;
$stop ;
end
endmodule
仿真结果图
从仿真结果图上来看,系统设计符合预期设想,当发送数据aa,bb时接收端读可以实现数据的读取。
总结
串口异步通信接收端设计采用了多次重复采样的思路,对于干扰信号而言,应用多次信号采样是否大于平均值来决定采样的阈值。