无线433发送接收数据测试程序原理,有杂波解决方案

无线433发送接收测试程序

	433Mhz无线通信相关知识不做介绍,网上很多
		避坑:MCU的接收引脚Data脚,是否配置上拉要参考MCU内部上拉电阻的大小,使用时最好拿示波器测量高低电平对应的电压。

用轮询的方式解码:大多数情况接收端在没收到数据时也会有很多杂波,用中断的方式会造成MCU频繁进入中断,浪费资源;

此测试程序的433编码规则如下:
引导码:4.5ms低电平
逻辑1:560us高+1690us低
逻辑0:560us高 +560us低 ----- 只计算低电平时间可以判断逻辑
引导码—用户码—用户反码—键码—键码反码 --=实际数据32位有效
(和NEC协议差不多 ---- 程序也适合给NEC使用)

在50us定时器的中断服务函数中采样(在软件定时器中采样会收到部分干扰),根据实际波形做软件滤波处理。
	采样逻辑:
因为高电平时间一样,在引脚为低电平时计数变量++,50*x为低电平时间,当跳转到高电平时,"根据低电平的时间判断是否为引导码,确定引导码后,跳到接收数据的步骤",继续对低电平计数,完成32位后判断用户码,确定键值
			"本文分两部分写:接收解码和发送"   
			主要看注释部分

======================接收解码部分

1.低电平计数/滤波

接收解码扫描函数,每50us对433接收到的波形计数一次
		采样扫描程序
void Recevie433DecodeScan(void)  //放在50us定时器中断服务函数中
{
	static unsigned char Su8FilterCnt = 0;
	static bit SbJumpFlag = 0;		 		//高低电平跳变标志,记录上一次引脚的状态,来反应从高到低或从低到高
	if(bRfDecodeOk == 0)					//解码不成功的时候需连续解码,解码成功后延时150ms再次解码
	{
		if(!PIN_DATA)            			//引脚输入低电平
		{
			Gu8RfRxLowCnt++;				//计时低电平个数来算时间,只通过低电平时间判断逻辑1或逻辑0
			Su8FilterCnt = 0;				//高电平滤波计算
			if(SbJumpFlag && Gu8RfRxLowCnt >= 2)    //两个50us的低电平后才判断电平从高到低,忽略部分杂波
			{
				SbJumpFlag = 0;  					//高到低跳变
			//	Su8FilterCnt = 0;
			}
		}
		else  								  		//引脚检测到高电平时,判断高高电平是否有效,高电平有效后,计算进入解码程序
		{
			if(!SbJumpFlag && Su8FilterCnt++ >= 2)  //可滤波
			{
				SbJumpFlag = 1;  					 //低到高跳变
				Rf433SoftDecode();          		 //对上后解码,一次一位
				Gu8RfRxLowCnt = 0;
				Su8FilterCnt = 0;
			}    
		}
	}
}

2.接收步骤并判断用户类型

void Rf433SoftDecode(void)
{
	static uchar Su8RfRxBitCnt = 0;  //接收数据位
	static ulong Su32RfRxData  = 0;  //数据缓冲区

	if(bRfRecStartFlag == 0)		//第一步,检测引导码,获取到引导码后开始检测数据
	{
		if((Gu8RfRxLowCnt > RF_START_L_MIN)&&(Gu8RfRxLowCnt < RF_START_L_MAX))	//引导码判断4.5ms低电平
		{
			bRfRecStartFlag = 1;	 //下次循环跳过此if,开始接收数据 
			
			Su32RfRxData    = 0;   //数据缓存清零
			Su8RfRxBitCnt   = 0;   //数据长度清零
			Gu8RfRxUserCode = 0;
			Gu8RfRxKeyValue = 0;
		}
	}
	else if((bRfRecStartFlag == 1)&&(Su8RfRxBitCnt < RF_REC_BIT_LEN))  //用接收位数判断暂停        
	{
		if((Gu8RfRxLowCnt > RF_LOGIC0_L_MIN)&&(Gu8RfRxLowCnt < RF_LOGIC0_L_MAX))//逻辑0时长判断,低电平时间范围需稍微加宽
		{
			Su32RfRxData = Su32RfRxData<<1;  //LSB,从低位开始传数据,数据0直接位移
			Su8RfRxBitCnt++;		//总位数++																											
		}
		else if((Gu8RfRxLowCnt > RF_LOGIC1_L_MIN)&&(Gu8RfRxLowCnt < RF_LOGIC1_L_MAX))
		{
			Su32RfRxData = Su32RfRxData<<1;
			Su32RfRxData |= 1;         			//最低位赋值为1
			Su8RfRxBitCnt++;
		}
		else									//某一位的时长不符合协议要求,丢弃整个数据
		{
			bRfRecStartFlag = 0;
      		Su8RfRxBitCnt = 0;
		}
	}

	if(Su8RfRxBitCnt == 32)						//接受完32位后解析用户码
	{
		Su8RfRxBitCnt   = 0;					
		bRfRecStartFlag = 0;					//下一次重新检测引导码

		Gu8RfRxUserCode = Su32RfRxData >> 24;   //用户码的8位
		if(Gu8RfRxUserCode == RF_NEC_USER_CODE)
		{
			Gu8RfRxKeyValue = Su32RfRxData >> 8;     //按键值第二个8位,此处可以判断最低8位是否为其反码
			bRfRecCodeOk = 1;  					     //接收到一个NEC/433按键码,上报
		}
	    else if(Gu8RfRxUserCode == RF_433_USER_CODE)//另一种用户码
	    {
				Gu8RfRxKeyValue = Su32RfRxData >> 8;
				bRfRecCodeOk = 1;    
	    }
	}
}

3.任务处理

void Rf433RecevieDecodeTask(void)
{
	 static uchar Su8RfRxTimeCnt  = 0;     //接收时间计数
	 uchar u8KeyValueHigh = 0;
	 uchar u8KeyValueLow  = 0;
	
	 if(bRfRecCodeOk)						//发送接收到的命令即可
	 {
		  	bRfRecCodeOk = 0;
		  	
			switch(Gu8RfRxKeyValue)			//键值判断部分
			{
				UserTask()
			}
	   		Gu8RfRxKeyValue = 0;
	 }
	 
	 if(bRfDecodeOk)              //150ms后再次接受遥控码,可减小时间
	 {
			Su8RfRxTimeCnt++;
			if(Su8RfRxTimeCnt >= 150)     
			{
				Su8RfRxTimeCnt = 0;
				bRfDecodeOk = 0; 						
			}
	  }
}
///全局与宏
uchar Gu8RfRxLowCnt  = 0;   //低电平接收计时器
uchar Gu8RfRxHighCnt = 0; 	//高电平接收计时器
uchar Gu8RfRxUserCode = 0;  //客户代码
uchar Gu8RfRxUserCode1 = 0; //客户代码
uchar Gu8RfRxKeyValue = 0;  //按键值
bit bRfDecodeOk     = 0;    //解码是否成功标志位
bit bRfRecStartFlag = 0;    //接收同步码成功标志位   
bit bRfRecCodeOk    = 0;	


//引导码低电平时间,4.5ms低电平
#define RF_START_L_MAX    100      //100*50us=5ms
#define RF_START_L_MIN    75       //75*50us=3.9ms
#define RF_START_H_MAX    100      //100*50us=5ms
#define RF_START_H_MIN    75       //75*50us=3.9ms
#define RF_REC_BIT_LEN    32

//逻辑0:560us高+560us低
//逻辑1:560us高+1690us低   
#define RF_LOGIC0_L_MAX   18      //18*50us=900us
#define RF_LOGIC0_L_MIN   5       //5*50us=250us
#define RF_LOGIC1_L_MAX   40      //40*50us=2000us
#define RF_LOGIC1_L_MIN   25      //25*50us=1300us
#define RF_NEC_USER_CODE   0x55    //用户码
#define RF_433_USER_CODE   0x5A

//======================发送测试程序,需要连接433接收模块测试
1.发送的主要程序是计算 高和低电平的总时间,再分时间设置引脚的高/低电平;
2.部分宏定义可自定义;
3.根据MCU堆栈大小结构自行解耦,若资源多就用结构体,否则将结构体打散,单个位用位域和联合体解决;

typedef struct
{
	unsigned char State;				//步骤
	unsigned char TxEnable:1;			//发送使能位置	//可判断首字节是否为空替代
	unsigned char TxTimes;				//发送次数 		//可宏替代
	unsigned char TxTimesCnt;   		//次数计数器
	unsigned char TxBufLength;			//数据长度 		//可宏替代
	unsigned char TxCnt;				//高低电平计数、间隔时间计数
	
	unsigned char NowByte;
	unsigned char NowByteIndex;
	unsigned char NowBit:1;
	unsigned char NowBitIndex;			
	
	unsigned char FirstSegTime;			//第一段时间
	unsigned char AllTime;				//总时间
}RemoteNecObject_t;
extern RemoteNecObject_t xdata Rm433Info;

//enum ENUM_RemoteNecStep{RF_IDLE,RF_REPEATED,RF_HEAD,RF_SDATA};  //状态表
void RfSendData(uchar KeyValue);
void RfTask_50uS(void);
//对象初始化
RemoteNecObject_t xdata Rm433Info = 
{
	0,//	unsigned char State;				//步骤
	0,//	unsigned char TxEnable:1;			//发送使能位置
	TX_433_REPEAT_TIMES+1,//	unsigned char TxTimes;				//发送次数 //可宏替代
	0,//	unsigned char TxTimesCnt;   		//次数计数器
	6,//	unsigned char TxBufLength;			//数据长度 //可宏替代
	0,//	unsigned char TxCnt;				//发送计数器	
	0,//	unsigned char NowByte;
	0,//	unsigned char NowByteIndex;
	0,//	unsigned char NowBit:1;
	0,//	unsigned char NowBitIndex;
	0,//	unsigned char FirstSegTime;			//第一段时间
	0,//	unsigned char AllTime;				//一位总时间
};

#if 1   //调用一次测试
uchar TxBuf[6] = {0xA2,0X55,0X55,0X55,0X00,0X5A};
void RfSendData(uchar KeyValue)
{
	uchar i = 0;
	TxBuf[i++] = 0xA2;			//头码
	
	TxBuf[i++] = 0x55;
	TxBuf[i++] = 0x55;
	TxBuf[i++] = 0x55;
	
	TxBuf[i++] = KeyValue;		//键值
	TxBuf[i] = 0x5A;			//尾码
	
	
	Rm433Info.State = RF_IDLE;  //强制发送
	Rm433Info.TxEnable = 1;     //使能发送
}

50us一次任务处理



/*
	T = 50uS
*/
void RfTask_50uS(void)
{
	switch(Rm433Info.State)
	{
		case RF_IDLE:   //空闲,等待使能
			if(Rm433Info.TxEnable)
			{
				Rm433Info.State = RF_HEAD;
				
				Rm433Info.FirstSegTime = TX_HEAD_FIRST_SEG_TIME;		//Time/50			//所有时间
				Rm433Info.AllTime = TX_HEAD_ALL_FRAME_TIME;				//(Seg1+Seg2)/50 
				Rm433Info.TxCnt = 0;
				Rm433Info.NowByteIndex = 0;			//Buf[0]
				Rm433Info.NowBitIndex = 0;
				Rm433Info.TxTimesCnt = 0;			//次数:和重复段不同点
			}
			break;
//		case RF_INIT:
//
//			break;
			
		case RF_REPEATED:		// 重复码
			if(++Rm433Info.TxCnt >= TX_REPEAT_INTERVAL_TIME) //间隔时间
			{
				Rm433Info.TxCnt = 0;
				
				Rm433Info.State = RF_HEAD;
				Rm433Info.FirstSegTime = TX_REPEAT_FIRST_SEG_TIME;		//Time/50	此时间根据实际需求设置		
				Rm433Info.AllTime = TX_REPEAT_ALL_FRAME_TIME;			//(Seg1+Seg2)/50 //所有时间
				Rm433Info.TxCnt   = 0;
				Rm433Info.NowByteIndex = 0;			//Buf[0]
				Rm433Info.NowBitIndex  = 0;
			}
		break;
		case RF_HEAD:			// 头码
			//设置第一段时间,总时间,发送一位使能,等待发送完成
			if(Rm433Info.TxCnt < Rm433Info.FirstSegTime)
			{
				TX_GpioPIN = 1; // 预设
			}
			else
			{
				TX_GpioPIN = 0;
			}
			
			if(++Rm433Info.TxCnt > Rm433Info.AllTime)
			{
				Rm433Info.TxCnt = 0;
				//TX_GpioPIN    = 1;				//此处会占用一个周期 /******************/
				Rm433Info.State  = RF_SDATA;  	    //发送完头码发送数据域
				
				Rm433Info.NowByte = TxBuf[Rm433Info.NowByteIndex++];
				
				// MSB
				Rm433Info.NowBit  = (Rm433Info.NowByte&(0x80>>(Rm433Info.NowBitIndex++)))?1:0;
				// LSB  ---  NowBit = (NowByte&(0x01<<NowBitIndex++))?1:0;
				
				if(Rm433Info.NowBit)		//第一个bit牵引
				{
					Rm433Info.FirstSegTime = TX_FIRST_SEG_TIME_H;
				}
				else
				{
					Rm433Info.FirstSegTime = TX_FIRST_SEG_TIME_L;
				}
				Rm433Info.AllTime = TX_ONE_BIT_ALL_FRAME_TIME;    //之后不用改
			}
			break;
		case RF_SDATA:
			if(Rm433Info.TxCnt < Rm433Info.FirstSegTime)
			{
				TX_GpioPIN = 1;  // 预设
			}
			else
			{
				TX_GpioPIN = 0;
			}
			
			if(++Rm433Info.TxCnt >= Rm433Info.AllTime)   //发送完 1 bit
			{
				Rm433Info.TxCnt = 0;
				//TX_GpioPIN = 1;		//Alltime -1 此行省略//此处会占用一个周期 /******************/
				
				if(Rm433Info.NowBitIndex <= 0x07)    //判断是否发送完 1 byte
				{
					// MSB
					Rm433Info.NowBit = (Rm433Info.NowByte&(0x80>>(Rm433Info.NowBitIndex++)))?1:0;
					// LSB  --- Rm433Info.NowBit = (Rm433Info.NowByte&(0x01<<Rm433Info.NowBitIndex++))?1:0;
					if(Rm433Info.NowBit)
					{
						Rm433Info.FirstSegTime = TX_FIRST_SEG_TIME_H;
					}
					else
					{
						Rm433Info.FirstSegTime = TX_FIRST_SEG_TIME_L;
					}
					
				}
				else  //Next Byte
				{
					Rm433Info.NowBitIndex = 0;
					if(Rm433Info.NowByteIndex < Rm433Info.TxBufLength)//判断是否发送完数据域
					{
						Rm433Info.NowByte = TxBuf[Rm433Info.NowByteIndex++];
						// MSB
						Rm433Info.NowBit = (Rm433Info.NowByte&(0x80>>(Rm433Info.NowBitIndex++)))?1:0;
						// LSB  --- Rm433Info.NowBit = (Rm433Info.NowByte&(0x01<<Rm433Info.NowBitIndex++))?1:0;
						if(Rm433Info.NowBit)
						{
							Rm433Info.FirstSegTime = TX_FIRST_SEG_TIME_H;
						}
						else
						{
							Rm433Info.FirstSegTime = TX_FIRST_SEG_TIME_L;
						}
						
					}	
					else
					{
						Rm433Info.TxTimesCnt++;
						if(Rm433Info.TxTimesCnt < Rm433Info.TxTimes)  //次数
						{
							Rm433Info.State = RF_REPEATED;  //发送重复码
							Rm433Info.TxCnt = 0;
						}
						else
						{
							Rm433Info.TxTimesCnt = 0;
							Rm433Info.State = RF_IDLE;	//空闲,等待使能
							TX_GpioPIN = 0;
							Rm433Info.TxEnable = 0;	//一次发送完成
						}
					}
				}
			}
			//设置第一段时间,总时间,发送一位使能,等待发送完成,直到第6字节发送完成
			break;
	}
}
本人非专业人士,只是一个小小程序员,arduino纯属爱好,所发文章仅限于本人智商,如有问题,请大家指正。 近期对智能家居比较敢兴趣,其中存在几个无线传输的模块,起初选用的2.4G的nRL24L01模块,那个东西真是折腾死人,弄了一个星期都没找到问题点。最后在收拾元件箱子的时候,发现一套以前买的433Mhz模块,就想干脆用这个吧。在各种方式的search,找到了一个lib - RCSwitch,看了例子还比较好用,可以传输24bit的值。立刻装上测试。 315\433射频模块介绍: 当发射电压为3V时,空旷地传输距离约20~50米,发射功率较小,当电压5V时约100~200米,当电压9V时约300~500米,当发射电压为12V时,为最佳工作电压,具有较好的发射效果,发射电流约60毫安,空旷地传输距离700~800米,发射功率约500毫瓦。外接天线:10cm(发射模块天线:10cm,接收模块天线:30cm)多芯或单芯普通导线。 在实际测试中,随便接了跟电线,传输能达到5米,无丢包现象。这个射频模块的穿墙效果,应该会比2.4G的好很多。我家里以前一套315Mhz的报警器,全屋传输无压力。 接线很简单,只有三个脚,两个是电源,一个是数据。 发射端 VCC GND DATA- arduino 10脚(可以变更,在代码中调整) 接收端 VCC GND DATA- arduino 2脚(使用终端2则使用3脚,在代码中调整) 程序使用RCSwitch附带示例修改,传感器值使用随机数替代。 传输思路是将24bit的值分开,前12位为传感器ID,后12位为传感器值,12bit,可以到4096,应该够用了。 其他的控制编码器的例子还没有试,下次测试好了再来。 说明: 还忘了一个重要的东西,在lib中有个代码需要修改,不然会接受到4个重复的值。由于本人对中断不是很熟悉,不知道4个重复值造成的原因,只是测试出改了一个值,请各位大师给予解答。 [pre lang="arduino" line="1"]void RCSwitch::handleInterrupt() { if (repeatCount == 6) { // 需要将 2改为 6repeatCount == 2 if (receiveProtocol1(changeCount) == false){ if (receiveProtocol2(changeCount) == false){ if (receiveProtocol3(changeCount) == false){ //failed } } } repeatCount = 0; } }[/pre] RF射频模块发射端程序部分截图: RF射频模块接收端程序部分截图:
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MECHT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值