无线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;
	}
}
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐