UART串口接收模块设计

本文介绍了一种在工业环境中采用UART协议稳定接收数据的方法。重点在于通过多次采样提高数据接收的准确性,尤其是在存在电磁干扰的情况下。文章详细描述了实现过程,包括同步处理、下降沿检测及波特率产生等关键步骤。

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

设计要求:实现FPGA接收其他设备通过UART协议发送过来的数据

现象:在Quartus II中,使用In system sources and probes editor工具,查看UART接收模块接收到的数据,串口接收到的数据由PC机发出

知识点:UART通信协议工业环境下数据接收实现;

对于其中的每一位进行采样,一般每一位数据的中间点是最稳定的,因此一般应用中,采集中间时刻的数据即可。但在工业应用中,往往有很强的电磁干扰,只采样一次就作为该数据的电平判定,是不保险的,有可能恰好采集到被干扰信号导致出错,因此需要多次采样求概率的方式进行。

红色部分数据可能是不稳定的。绿色部分数据是稳定的,但不排除受电磁干扰出现错误的电平脉冲,因此对这一段电平进行多次采样,求高低电平发生的概率,6次采集结果中,取出现次数多的电平作为采样结果。当采样结果中0和1各占一半,则可判断当前 通信线路环境很恶劣,数据不具有可靠性。

1 串口发送模块包含两个主要组件:(1)Rs232_Rx属于外部输入信号,是异步信号,为避免亚稳态,需要对其进行同步处理;(2)起始位检测进程(检测到下降沿);(3)波特率产生模块(16*10,每位数据都要采集16次,共10位数据,若波特率时钟为9600Hz,应为9600*16);(4)数据接收进程

2 串口发送模块结构图

 3 波特率时钟计算

4 代码段

(1)起始位的检测,需先有下降沿的检测,和之前的按键检测一样

	reg s0_Rs232_Rx,s1_Rs232_Rx;//同步寄存器
	reg tmp0_Rs232_Rx,tmp1_Rs232_Rx;//数据寄存器
	wire nedege;
	//同步寄存器,消除亚稳态
	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
			tmp0_Rs232_Rx <= 1'b0;
			tmp1_Rs232_Rx <= 1'b0;
		end
	else
		begin
			tmp0_Rs232_Rx <= s1_Rs232_Rx;
			tmp1_Rs232_Rx <= tmp0_Rs232_Rx;
		end
	//下降沿检测
	assign nedege = (!tmp0_Rs232_Rx) & tmp1_Rs232_Rx;
module uart_byte_rx(Clk,Rst_n,baud_set,Rs232_Rx,data_byte,Rx_done);

	input Clk;
	input Rst_n;
	input baud_set;
	input Rs232_Rx;
	
	output reg [7:0]data_byte;
	output reg Rx_done;
	
	reg s0_Rs232_Rx,s1_Rs232_Rx;//同步寄存器
	reg tmp0_Rs232_Rx,tmp1_Rs232_Rx;//数据寄存器
	reg [15:0]bps_DR;//分频计数器最大值
	reg [15:0]div_cnt;//分频计数器
	reg uart_state;
	reg bps_clk;
	reg [7:0]bps_cnt;
	reg [2:0] r_data_byte [7:0];//左侧是位宽,一直加,加到最大是6,右侧是地址位宽度,一共有8位,每位存储的是3位的数据
	reg [2:0] START_BITE,STOP_BIT;
	reg [7:0] tmp_data_byte;
	wire nedege;
	//同步寄存器,消除亚稳态
	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
			tmp0_Rs232_Rx <= 1'b0;
			tmp1_Rs232_Rx <= 1'b0;
		end
	else
		begin
			tmp0_Rs232_Rx <= s1_Rs232_Rx;
			tmp1_Rs232_Rx <= tmp0_Rs232_Rx;
		end
	//下降沿检测
	assign nedege = (!tmp0_Rs232_Rx) & tmp1_Rs232_Rx;
	
//波特率设置模块,查找表
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		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'd55;
			4:bps_DR <= 16'd26;
			default:bps_DR <= 16'd324;
		endcase
	end
	
	//计数器
	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;
		
//产生bps_clk
	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;
	
// bps counter 	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_cnt <= 8'd0;
	else if(Rx_done || (bps_cnt == 8'd12 && (START_BITE > 2)))//还有一种情况是起始位检测错误
		bps_cnt <= 8'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else
		bps_cnt <= bps_cnt;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Rx_done <= 1'b0;
	else if(bps_cnt == 8'd159)
		Rx_done <= 1'b1;
	else
		Rx_done <= 1'b0;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		data_byte <= 8'd0;
	else if(bps_cnt == 8'd159)
	begin //4:100 5:101 6:110只需判断最高位是0还是1,简化逻辑,3算到0里面
		data_byte[0] <= r_data_byte[0][2];
		data_byte[1] <= r_data_byte[1][2];
		data_byte[2] <= r_data_byte[2][2];
		data_byte[3] <= r_data_byte[3][2];
		data_byte[4] <= r_data_byte[4][2];
		data_byte[5] <= r_data_byte[5][2];
		data_byte[6] <= r_data_byte[6][2];
		data_byte[7] <= r_data_byte[7][2];
	end
	
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		START_BITE <= 3'd0;
		r_data_byte[0] <= 3'd0;
		r_data_byte[1] <= 3'd0;
		r_data_byte[2] <= 3'd0;
		r_data_byte[3] <= 3'd0;
		r_data_byte[4] <= 3'd0;
		r_data_byte[5] <= 3'd0;
		r_data_byte[6] <= 3'd0;
		r_data_byte[7] <= 3'd0;
		STOP_BIT <= 3'd0;
	end
	else if(bps_clk)
		begin
			case(bps_cnt)//求概率,应该把每一位数据中的1加起来,共6次,如果加起来的结果大于3则这一位的数据为1,否则为0
				0:
				begin
					START_BITE <= 3'd0;
					r_data_byte[0] <= 3'd0;
					r_data_byte[1] <= 3'd0;
					r_data_byte[2] <= 3'd0;
					r_data_byte[3] <= 3'd0;
					r_data_byte[4] <= 3'd0;
					r_data_byte[5] <= 3'd0;
					r_data_byte[6] <= 3'd0;
					r_data_byte[7] <= 3'd0;
					STOP_BIT <= 3'd0;
				end //注意它加的是同步之后的数据,需要测试一下,如果加的是数据寄存器输出的数据如何?????
				6,7,8,9,10,11:START_BITE <= START_BITE + s1_Rs232_Rx;//采样起始位
				22,23,24,25,26,27:r_data_byte[0] <= r_data_byte[0] + s1_Rs232_Rx;
				38,39,40,41,42,43:r_data_byte[1] <= r_data_byte[1] + s1_Rs232_Rx;
				54,55,56,57,58,59:r_data_byte[2] <= r_data_byte[2] + s1_Rs232_Rx;
				70,71,72,73,74,75:r_data_byte[3] <= r_data_byte[3] + s1_Rs232_Rx;
				86,87,88,89,90,91:r_data_byte[4] <= r_data_byte[4] + s1_Rs232_Rx;
				102,103,104,105,106,107:r_data_byte[5] <= r_data_byte[5] + s1_Rs232_Rx;
				118,119,120,121,122,123:r_data_byte[6] <= r_data_byte[6] + s1_Rs232_Rx;
				134,135,136,137,138,139:r_data_byte[7] <= r_data_byte[7] + s1_Rs232_Rx;
				150,151,152,153,154,155:STOP_BIT <= STOP_BIT + s1_Rs232_Rx;
				default;//对于这部分代码的理解:每计数一次,每一位上的数据r_data_byte[]就要加上6次中的一次,一共6次
			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 || (bps_cnt == 8'd12 && (START_BITE > 2)))//接收完成或接收错误都会停止接收
		uart_state <= 1'b0;
	else
		uart_state <= uart_state;
	
endmodule

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值