ACX720开发板串口接收模块学习总结——参考教程小梅哥版本

本文介绍了串口接收模块的设计,包括单比特同步信号处理、边沿检测、采样时钟生成和数据状态判断。通过多次采样来抵抗电磁干扰,确保数据的可靠性,并通过testbench测试验证了设计的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1接收原理

对于每一位的采样点而言,一般认为每一位数据中心点采样是最稳定,下图是串口接收模块的时序图

但是在工业控制或者实际生产实践中单单采样一次往往是不可靠的,环境中充满了各种各样的电磁干扰,很可能由此而采样到错误的信号。使用改进型单比特采用 ,通过概率计算,来求出最优的采样信号的点。并且进行状态判断。

中间段灰色的实际是采样的信号点。

对这一段电平,进行多次采样,并求高低电平发生的概率,
6 次采集结果中,取出现次数多的电平作为采样结果。例如,采样 6 次的结果分别为
1/1/1/1/0/1/ ,则取电平结果为 1 ,若为 0/0/1/0/0/0, ,则取电平结果为 0 ,当 6 次采样结果中 1
0 各占一半(各 3 次),则可判断当前通信线路环境非常恶劣,数据不具有可靠性,不进行处理。

2串口异步通信接收模块设计和实现

2.1串口异步通信总模块封装

模块中接口部分的设计

rx_doneO读取字符串完成

 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时接收端读可以实现数据的读取。

总结

串口异步通信接收端设计采用了多次重复采样的思路,对于干扰信号而言,应用多次信号采样是否大于平均值来决定采样的阈值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值