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