433模块-----HCS301单片机解码

工具购买:
stm32F070工具板

一、序言

最近在做433M无线模块的接收跟发送相关的模块,所以想做一些工具,方便以后使用。本文主要来介绍下433M无线的接收跟解码部分。我做了一个测试板。也做了上位机,现分享给大家。我的摇控器是用HCS301编码的。安全性比较高是用滚码的。还用了KEELOQ加密算法。对于一些固定码的433编码芯片来说,这个相对来说安全性比较高了。可以用在门锁上面,安全性要求比较高的应用上面。话不多说,下面就来介绍下这个实例吧。

二、HCS301编码芯片TX时序

时序如下图所示L:
在这里插入图片描述
这里有TP是前导码,了解433模块的应该都知道,433接收模块在静态时都会有一些噪声的干扰信号出来。前导信号起着开始发送的作用。他是占空比为50%的脉冲信号。TE是一个低电平信号。后面的是66bit的数据信号。

三、检测摇控器开始发送数据

由于433静态时存在干扰的特点。所以我们解码时就不能用中断方式进行。我们应该是检测到了发送信号的时候再来打开中断,在中断处理中配合定时器实现解码功能。433的干扰信号如下图所示:在这里插入图片描述
综合考虑后,我决定开一个100us的定时器来检测TG信号。当检测到低电平达到TG信号长度的时候。认为摇控器开始发送数据过来。下面是中断处理函数。

//100us定时调用
void RFMODLE_CheckStart(void)
{
    //接收数据时,检测停止
	if(WakeupEnable == 0)
	{
		return;
	}
	//读取电平状态
	CurrentPinStatus = xBSP_HCS301_GetPIn();

    //连续低电平累加
	if((LastPinStatus == CurrentPinStatus) && CurrentPinStatus == 0x00)
	{
		LowTimeCount++;
		if(LowTimeCountMax < LowTimeCount)
		{
			LowTimeCountMax = LowTimeCount;
		}
	}
	else
	{
		LowTimeCount = 0;

		//判断低电平脉冲是否符合TG
		if(LowTimeCountMax > 100 && LowTimeCountMax <257)
		{
            //启动接收数据
			WakeupEnable = 0;
			//配置为中断模式
			xBSP_HCS301_IoInt();
            
		}
        LowTimeCountMax = 0;
	}

	LastPinStatus = CurrentPinStatus;
}
四、中断中接数据

注意,IO中断是采用双边沿的中断方式。

void xSYS_HCS301_IRQHandler(void)
{
	static uint16_t CurrentTimeValue;		//当前定时器的值
	static uint16_t LastTimeValue;			//上次定时器的值
	static uint16_t DetaTimeValue;			//两次进入函数的时间差
	static uint32_t PwmCount;				//前导部分PWM的计数值
	static uint16_t DataBitReceiveIndex;	//接前接收位的位置


    //清除状态
    if(HCS301_DecodeStep == 0)
    {
        CurrentTimeValue = GET_TIMERCOUNT();
        LastTimeValue = GET_TIMERCOUNT();
        HCS301_DecodeStep++;
        PwmCount = 0;
    }

    //检测TP跟TH信号
    else if(HCS301_DecodeStep == 1)
    {
        CurrentTimeValue = GET_TIMERCOUNT();
        DetaTimeValue = CurrentTimeValue - LastTimeValue;
        LastTimeValue = CurrentTimeValue;
        
        //TP PWM信号
        if(DetaTimeValue > 260 && DetaTimeValue < 660)
        {
            PwmCount++;
        }
        //TG 信号
        else if(DetaTimeValue > 260*10 && DetaTimeValue < 660*10)
        {
            //实际TP 信号有23个脉冲
            if(DetaTimeValue > 20)
            {
                HCS301_DecodeStep++;
                DataBitReceiveIndex = 0;
            }
            else
            {
                goto error;
            }
        }
        else
        {
            goto error;
        }
    }
    //接收数据部分
    else if(HCS301_DecodeStep == 2)
    {
        DataBitReceiveIndex++;
        CurrentTimeValue = GET_TIMERCOUNT();
        DetaTimeValue = CurrentTimeValue - LastTimeValue;
        LastTimeValue = CurrentTimeValue;

        //通过时间来判断逻辑1或0
        if(DataBitReceiveIndex%2 == 0)
        {
            //记录位
            if(DetaTimeValue > (520) && DetaTimeValue < (1320))
            {
                WriteBit((DataBitReceiveIndex / 2) - 1 , 0x01);
            }
            else if(DetaTimeValue > (260) && DetaTimeValue < (660))
            {
                WriteBit((DataBitReceiveIndex / 2) -1 , 0x00);
            }
            else
            {
                //err;
                goto error;
            }

            //接收完成退出
            if(DataBitReceiveIndex == 128)
            {
                //解密
                Test_DECRYPT(EncryPortion);

                //判断识别码值是否跟我烧录时候相同
                if((EncryPortion_de & 0x03FF0000) == 0x01370000)
                {
                    Sync_Current = EncryPortion_de;
                    //两次同步值要不同才认为是新的按键按下
                    if(Sync_Last != Sync_Current)
                    {
                        FixedPortion_de = FixedPortion;
                        gHcs301Code1 = FixedPortion_de;
                        gHcs301Code2 = EncryPortion_de;
                        IsSendCodeToPc = 1;
                    }
                    
                    Sync_Last = Sync_Current;
                }
                goto error;
            }
        }
    }
		
	return;

error:
	//出错
	WakeupEnable = 1;
	HCS301_DecodeStep = 0;
	xBSP_HCS301_IoInput();
}


void WriteBit(uint8_t bit , uint8_t value)
{
	if(bit < 32)
	{
		if(value)
		{
			EncryPortion |=  (0x01 << bit);
		}
		else
		{
			EncryPortion &=  ~(0x01 << bit);
		}
	}
	else if(bit < 64)
	{
		bit -= 32;
		if(value)
		{
			FixedPortion |=  (0x01 << bit);
		}
		else
		{
			FixedPortion &=  ~(0x01 << bit);
		}
	}
	else
	{
		
	}
}
五、KEELOQ算法的软件实现
/*************************************************************************************************************************/
//以下是加密跟解密相关的函数了。

unsigned char NLF[2][2][2][2][2];

void init()
{
    NLF[0][0][0][0][0]=0;
    NLF[0][0][0][0][1]=1;
    NLF[0][0][0][1][0]=1;
    NLF[0][0][0][1][1]=1;
    NLF[0][0][1][0][0]=0;
    NLF[0][0][1][0][1]=1;
    NLF[0][0][1][1][0]=0;
    NLF[0][0][1][1][1]=0;
    
    NLF[0][1][0][0][0]=0;
    NLF[0][1][0][0][1]=0;
    NLF[0][1][0][1][0]=1;
    NLF[0][1][0][1][1]=0;
    NLF[0][1][1][0][0]=1;
    NLF[0][1][1][0][1]=1;
    NLF[0][1][1][1][0]=1;
    NLF[0][1][1][1][1]=0;
    
    NLF[1][0][0][0][0]=0;
    NLF[1][0][0][0][1]=0;
    NLF[1][0][0][1][0]=1;
    NLF[1][0][0][1][1]=1;
    NLF[1][0][1][0][0]=1;
    NLF[1][0][1][0][1]=0;
    NLF[1][0][1][1][0]=1;
    NLF[1][0][1][1][1]=0;
    
    NLF[1][1][0][0][0]=0;
    NLF[1][1][0][0][1]=1;
    NLF[1][1][0][1][0]=0;
    NLF[1][1][0][1][1]=1;
    NLF[1][1][1][0][0]=1;
    NLF[1][1][1][0][1]=1;
    NLF[1][1][1][1][0]=0;
    NLF[1][1][1][1][1]=0;
}

//获取source第n个位数
unsigned char getBit(unsigned char source[],int n)
{
    unsigned char temp0=(unsigned char)1<<(n%8);
    unsigned char temp1=source[n/8]&temp0;
    if(temp1!=0)
    {
        return 1;
    }
    return 0;
}

//source带进位右移
unsigned char * RRC(unsigned char source[],char c,char n)
{
    int i=0;
    unsigned char temp;
    for(i=n-1;i>=0;i--)
    {
        temp=source[i];
        if(c!=0){
            source[i]=(source[i]>>1)|0x80;
        }else{
            source[i]=(source[i]>>1)&0x7f;
        }
        
        if((temp&0x01) != 0){
            c=1;
        }else{
            c=0;
        }
    }
    return source;
}

//source带进位左移
unsigned char * RLC(unsigned char source[],char c,char n)
{
    int i=0;
    unsigned char temp;
    for(i=0;i<n;i++)
    {
        temp=source[i];
        if(c!=0){
            source[i]=(source[i]<<1)|0x01;
        }else{
            source[i]=(source[i]<<1)&0xfe;
        }
        
        if((temp&0x80)!=0){
            c=1;
        }else{
            c=0;
        }
    }
    return source;
}

//加密
unsigned char* CRYPT(unsigned char *source,unsigned char key[])
{
    int i=0;
    unsigned char c=0;
    unsigned char nlf,y16,y0,k,result;
    init();
    for (i = 0; i < 528; i++)
    {
        nlf=NLF[getBit(source, 31)][getBit(source, 26)][getBit(source, 20)][getBit(source, 9)][getBit(source, 1)];
        y16=getBit(source, 16);
        y0=getBit(source, 0);
        k=getBit(key, i%64);
        result=nlf^y16^y0^k;
        if (result!=0) 
		{
            c=1;
        }
		else 
		{
            c=0;
        }
        source=RRC(source,c,4);
    }
    return source;
}

//解密
unsigned char*  DECRYPT(unsigned char *source,unsigned char key[])
{
    int i=0;
    unsigned char c=0;
    unsigned char nlf,y15,y31,k,result;
    init();
    for (i = 528; i >0; i--)
    {
        nlf=NLF[getBit(source, 30)][getBit(source, 25)][getBit(source, 19)][getBit(source, 8)][getBit(source, 0)];
        y15=getBit(source, 15);
        y31=getBit(source, 31);
        k=getBit(key, (i-1)%64);
        result=nlf^y15^y31^k;
        if ( result != 0)
		{
			c=1;
		}      
        else
		{
			c=0;
		}                 
        source=RLC(source,c,4);
    }
    return source;
}





/*
*********************************************************************************************************************

@ Brief  : 解密数据

@ Param  : NONE

@ Return : NONE

@ Author : YWJ(QQ:872180981)

@ Data   : 2020-08-29 17:23

*********************************************************************************************************************
*/
void Test_DECRYPT(uint32_t data)
{
    source[0]=(unsigned char)(data);
    source[1]=(unsigned char)(data>>8);
    source[2]=(unsigned char)(data>>16);
    source[3]=(unsigned char)(data>>24);

	//解密
    DECRYPT(source, HCS301_Decryptkey);

    EncryPortion_de = source[3];
    EncryPortion_de <<= 8;
    EncryPortion_de |= source[2];
    EncryPortion_de <<= 8;
    EncryPortion_de |= source[1];
    EncryPortion_de <<= 8;
    EncryPortion_de |= source[0];
}
六、硬件跟上位机参考

由于这次主要是介绍HCS301的解码程序。上位机部分只是作一个显示。还涉及到USB通讯、QT等相关。所以就不多讲解。

上位机:
在这里插入图片描述
硬件电路板,电路板可出售,后续会在上面做更多功能。比如说已经完成的HCS301烧录器。
在这里插入图片描述

七、资料下载信息

由于百度网盘会更新,可以进群看QQ公告.所以资料都会在同一个地址分享.
群号:339420387
在这里插入图片描述

  • 6
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值