串口波特率自适应算法(仿真通过)

最近在整理串口通信的时候,敲完程序,想到能不能实现波特率自适应功能(起初想实现任意频率的波特率识别,后来发现能力不够,那就转为常见波特率识别吧)。
第一步查阅资料看看别人这是咋做的:波特率自适应常见方法:
1.硬件检测波特率,一些硬件设备自带波特率检测功能例如一些STM32的单片机(硬件检测没啥好说的)。
2.软件检测波特率:
(1):特征值匹配:收发双方约定一个特殊字符,接收方根据接受的数据查表确定波特率。
李斌斌,冯涛,谷丽. 串口波特率与数据位参数自适应算法的研究与实现[J]. 计算机光盘软件与应用,2014(3):279-280.
(2):发送方发送超宽低电平脉冲,使接收方进入波特率调整状态,并对下一帧数据0x00确定新的波特率。
孙夫文,郑采君,刘昕卓,等. 基于FPGA串口波特率自适应功能的设计与实现[J]. 电子设计工程,2019,27(9):69-73. DOI:10.3969/j.issn.1674-6236.2019.09.016.
上述两种波特率调整方法都需要提前约定检测条件,那么如何设计一套不需要发送特殊字符也能正确调整波特率的算法呢?虽然波特率未知,但是起始位是确定可测的,如果我们采用0校验方式,则每帧数据的0校验位一直为低电平。那么我们已知起始位置,已知校验位点平,我们通过检验校验位位置电平即可知道当前波特率是否合适,如果不合适,则遍历已知波特率直到达到合适。通过这种方法就可以在更改波特率时不需要发送特殊字符给接收方,而接收方可以自动调节的功能。
特点:更改波特率前不需要通知接收方,接收方自动调整、把0校验位作为判断依据,不需要改变帧结构、最重要是没看到有人这样做(可能没啥实用性吧,不过能够和别人不一样就行)。

/*整体实现功能和串口接收程序一样只不过是多检测了一个0检验位,可以直接整合进串口接收程序,这里为了实现模块化,所以把波特率自适应功能单独做一个模块,方便直接添加进串口收发顶层文件中*/
module bps_DR_detect(
	input clk, 
	input rst_n,
	input rs232_rx,
	output reg [2:0]baud_set
);
//同步寄存器,消除亚稳态
reg s0_rs232_rx,s1_rs232_rx;
reg temp0_rs232_rx,temp1_rs232_rx;
always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			s0_rs232_rx<=1'b0;
			s1_rs232_rx<=1'b0;
		end
		else begin
			s0_rs232_rx<=rs232_rx;
			s1_rs232_rx<=s0_rs232_rx;
		end
//检测下降沿-帧起始位
always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			temp0_rs232_rx<=1'b0;
			temp1_rs232_rx<=1'b0;
		end
		else begin
			temp0_rs232_rx<=s1_rs232_rx;
			temp1_rs232_rx<=temp0_rs232_rx;
		end
wire nedege;
assign nedege=!temp0_rs232_rx & temp1_rs232_rx;
reg bps_clk;
reg [15:0]div_cnt;
reg uart_state;
reg [15:0]bps_DR;
//分频计数
always@(posedge clk or negedge rst_n)
		if(!rst_n)
		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;
always@(posedge clk or negedge rst_n)
		if(!rst_n)
			bps_clk<=1'b0;
		else if(div_cnt==16'd1)
			bps_clk<=1'b1;
		else 
		   bps_clk<=1'b0;
reg [3:0]bps_cnt;
always@(posedge clk or negedge rst_n)
		if(!rst_n)
		bps_cnt<=4'd0;
		else if(bps_cnt==4'd10)
				bps_cnt<=4'd0;
		else if(bps_clk)
				bps_cnt<=bps_cnt+1'b1;
		else 
				bps_cnt<=bps_cnt;
reg Rx_done;
//一帧接收完成
always@(posedge clk or negedge rst_n)
		if(!rst_n)
			Rx_done<=1'b0;
		else if(bps_cnt==4'd10)
			Rx_done<=1'b1;
		else
			Rx_done<=1'b0;
//读校验位电平
reg r_data_bit;
always@(posedge clk or negedge rst_n)
		if(!rst_n)
		r_data_bit<=1'b0;
		else if(bps_cnt==4'd10)
		r_data_bit<=s1_rs232_rx;
		else
		r_data_bit<=1'b0;
//调整波特率
reg [2:0]DR_cnt;
always@(posedge clk or negedge rst_n)
		if(!rst_n)
		DR_cnt<=3'd0;
		else if(DR_cnt==3'd4)
		DR_cnt<=3'd0;
		else if(r_data_bit)
		DR_cnt<=DR_cnt+1'b1;
always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
		baud_set<=3'd0;
		bps_DR<=16'd5207;
		end
		else begin
				case(DR_cnt)
				   0:begin baud_set<=3'd0;bps_DR<=16'd5207;end
					1:begin baud_set<=3'd1;bps_DR<=16'd2603;end
				   2:begin baud_set<=3'd2;bps_DR<=16'd1301;end
					3:begin baud_set<=3'd3;bps_DR<=16'd867;end
					default:begin baud_set<=3'd0;bps_DR<=16'd5207;end
				endcase
		end
//状态判断
always@(posedge clk or negedge rst_n)
		if(!rst_n)
		uart_state<=1'b0;
		else if(nedege)
		uart_state<=1'b1;
		else if(Rx_done)
		uart_state<=1'b0;
		else
			uart_state<=uart_state;
endmodule

仿真波形如下图所示,通过三帧数据实现了接收波特率等于发送波特率,实现了波特率自动调节和数据的正确接收。理论上最大调整时间为已有波特率数量-1;
在这里插入图片描述

  • 9
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值