单片机实现PT2262解码示例代码

/************************************************************************************************************************
******* 文件名:Decode.c
******* 描  述:用一个外部中断IO脚配合定时器0实现对2262系列编码信号进行软解码, PT2262的输出信号经LM358整形放大后
		由单片机P3.2口输入,作为单片机的外部中断源。
******* 编  码:A0 -- A11 中的每bit用2bit表示:0码:00 ;1码:11
******* 硬  件:PT2262发射模块、LM358+R25.接收模块、STC89C52RC单片机
******* 晶  振:11.0592MHz
******* 日  期:2014-05-21 (zqjun@HK)
******* 说  明:
		1、PT2262输出编码包括8位地址码、4位数据码、1位同步码,共13位, 
		   顺序:A0 A1 -- A10 A11 + 同步码 + A0 A1 -- A10 A11 + 同步码,连续发四次。
		2、四个振荡周期为1个编码计时单位,记作T,除同步码外,编码中只有2种类别的组合脉冲取名长脉冲和短脉冲,
		   其中:长脉冲由3T高电平、1T低电平组成;短脉冲由1T高电平、3T低电平组成。
		3、同步码,由1T高电平31T低电平组合(实际测试同步码低电平宽度基本在10ms以上)。
		4、只需测量低电平或者高电平长短,即可知是长还是短脉冲,超过12T时间没有脉冲变化就有可能是同步码。
************************************************************************************************************************/

#include <reg52.h>    //8051系列单片机头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Decode.h" //各种宏定义、全局变量、全局结构体声明


/**************************************************
********* 功能:利用定时器1实现1ms延时 ************
**************************************************/
void T1_timer(void) interrupt 3 using 1
{
	TH1 = (65536 - DELAY)/256;
	TL1 = (65536 - DELAY)%256; //922:1ms   450:1us
	count++;
	//LED1 = ~LED1;//改变P1.1状态
}


/**************************************************
***************** 功能:xms延时 *******************
**************************************************/
void delayms(uint xms)
{
	uint i, j;
	for(i = xms; i > 0; i--) //延时xms
	{
		for(j = 110; j > 0; j--);
	}
}


#if 0
/*****************************************************
*********** 功能:数码管显示0 ~ F之间的值 ************
*****************************************************/
/*
void display(uint arry_index)
{	
	dula = 1; 		  //开段选
	P0 = table[ arry_index ]; //送段选数据	
	dula = 0; 		  //关段选
	P0 = 0xFF;		  //消影
	delayms(Display_DELAY);	  //延时
}
*/


/****************************************************************
 ************ 功能: 把十六进制数据转换为十进制数据 *************
 ************ 返回值:转换之后结果,即十进制数据    *************
 ***************************************************************/
/*
uint Hex2Decimal(unsigned long num)
{
	uint ret = 0;
	if( (0 <= num) && (num <= 15) ) //0 ~ F
	{
		ret = ( (num & 0x8) * 8 ) +
		      ( (num & 0x4) * 4 ) +
		      ( (num & 0x2) * 2 ) +
		      ( (num & 0x1) * 1 );

		return ret;
	}

	return 0;
}
*/


/********************************************************************
****** 功能:解析接收到的解码后的数据,送8段数码管显示解码结果 ******
********************************************************************/
/*
void Parse_DecData(unsigned long decdata)
{
	unsigned long temp = 0;

	temp = decdata & 0xF00000; //编码最高4位
	wela = 1;
	P0 = 0xFE; //第1位数码管
	wela = 0;
	//display( Hex2Decimal(temp >> 20) );
	display( temp >> 20 );

	temp = decdata & 0x0F0000;
	wela = 1;
	P0 = 0xFD; //第2位数码管
	wela = 0;
	//display( Hex2Decimal(temp >> 16) );
	display( temp >> 16 );

	temp = decdata & 0x00F000;
	wela = 1;
	P0 = 0xFB; //第3位数码管
	wela = 0;
	//display( Hex2Decimal(temp >> 12) );
	display( temp >> 12 );

	temp = decdata & 0x000F00;
	wela = 1;
	P0 = 0xF7; //第4位数码管
	wela = 0;
	//display( Hex2Decimal(temp >> 8) );
	display( temp >> 8 );

	temp = decdata & 0x0000F0;
	wela = 1;
	P0 = 0xEF; //第5位数码管
	wela = 0;
	//display( Hex2Decimal(temp >> 4) );
	display( temp >> 4 );

	temp = decdata & 0x00000F; //编码最低4位
	wela = 1;
	P0 = 0xDF; //第6位数码管
	wela = 0;
	//display( Hex2Decimal(temp) );
	display( temp );

	return;
}
*/
#endif


/*************************************************
********** 功能:十六进制数据比较大小 ************
*************************************************/
/*
int HexDataCompare(unsigned long data_recv, unsigned long data_base)
{
	if( (data_recv == 0) || (data_base == 0) )
	{
		return -1; 
	}

	unsigned int i;
	unsigned long temp = data_recv;
	for (i = 0; i < 4; i++)
	{
		temp = data_recv & 0xFF;
	}

	return 0;
}
*/


/**********************************************
************ 功能:全局变量预初始化 *************
**********************************************/
int PrevInitial(M433_Service *p433_srv)
{
    //g_Display = 0; //数码管显示全局控制标志

    uchar i;
    for (i = 0; i < NODE_MAX; i++)
    {
        memset( &p433_srv->m433CodeTable[i], 0, sizeof(p433_srv->m433CodeTable[i]) );
    }
    p433_srv->m433WorkMode = MODE_NORMAL; //1, 初始化为正常工作模式
    p433_srv->m433_DecData_Learn = 0x0; //新对码值
    p433_srv->m433_DecData_Curr = 0x0; //当前接收到的编码信号值
    //p433_srv->m433_DecData_Prev = 0x0; //以前接收到的编码信号值
    p433_srv->m433_DevCount = 0; //已经对码的设备计数器
    p433_srv->m433_LearnStart = 0; //学习对码开始
    p433_srv->m433_LearnOK = 0; //学习对码成功
    p433_srv->m433_Enable = 1; //使能433模块

    count = 0;
    g_Receive = 0x0; //数据接收buffer
    g_DecData = 0x0; //待解码buffer,数据接收buffer的备份
    g_RecvOK = 0;	 //接收完成标志
    g_DecOK = 1;	 //解码完成标志,第一次进来置1以获取接收后的数据

    g_Running = 1; //循环检测开启

    return 0;
}


/***************************************************************
******************** 功能:单片机中断系统初始化 **********************
***************************************************************/
void MCU_Int_Initial( void )
{
	TMOD = 0x11; //设置定时器0和1的工作方式1:16位定时器

	TH1 = (65536 - DELAY)/256;
	TL1 = (65536 - DELAY)%256; //1ms
	ET1 = 1; //使能定时器1
	TR1 = 1; //启动定时器1
		
	TH0 = 0; //定时器0装初值
	TL0 = 0; //11.0592MHz 计满最大值计数值的时间为:71111us
	ET0 = 1; //使能定时器0

	IT0 = 1; //设置外部中断0为跳变沿触发方式,从高到低的负跳变触发
	EX0 = 1; //开启外部中断0

	EA = 1;  //开启所有中断
}


/*********************************************************************
************** 功能: 外部中断0服务函数,实现对2262解码 ***************
************** 中断功能开启后,下降沿触发中断进入此函数 **************
*********************************************************************/
void INT0_ISR(void) interrupt 0 using 1
{
	unsigned char i = 0;
	unsigned char j = 0;
	unsigned int Low_Level_Count = 0;  //低电平状态持续时间计数器
	unsigned int Wide_Low = 0;   //宽脉冲低电平持续时间
	unsigned int Narrow_Low = 0; //窄脉冲低电平持续时间

	EX0 = 0; //先关闭外部中断0

	while( WAVE_RECV ); //如果当前为高电平,则等待低电平的到来

	TH0 = 0;
	TL0 = 0; //11.0592MHz:71111us
	TR0 = 1; //启动定时器0,开始测量低电平的宽度,检测同步码
	while( ! WAVE_RECV ) //中断进入时当前为低电平状态
	{
		if( TF0 == 1 ) //如果定时器溢出,TF0位由硬件置1
		{
			goto DecExit; //定时器超时溢出则退出
		}
	}
	TR0 = 0; //电平状态发生变化,停止timer0计数,取得当前计数值

	Low_Level_Count = TH0;
	Low_Level_Count = Low_Level_Count << 8;
	Low_Level_Count = Low_Level_Count + TL0; //根据定时器计数值取得低电平的宽度
	//if( ((TIME_SYNC - TIME_SYNC_RANDOM) < Low_Level_Count) && (!g_RecvOK) ) //判断电平宽度,检测是否为同步码,事实上超过10ms即有可能为同步头
	if( ((TIME_SYNC_COMMON - TIME_SYNC_RANDOM) < Low_Level_Count) && (!g_RecvOK) ) //判断电平宽度,检测是否为同步码,超过8.5ms即有可能为同步头
	{
		//LED0 = ~LED0;
		Wide_Low = Low_Level_Count / 32; //根据同步码低电平宽度取得宽脉冲低电平宽度值
		Narrow_Low = Low_Level_Count / 11; //根据同步码低电平宽度取得窄脉冲低电平宽度值
		g_Receive = 0x0;

		for( i = 0; i < 24; i++ ) //循环24次解码
		{
			while( WAVE_RECV ); //如果当前高电平状态,则等待低电平到来

			TH0 = 0;
			TL0 = 0; //定时器重装初值
			TR0 = 1; //电平变化,开启定时器0 ,测量低电平的宽度
			while( ! WAVE_RECV ) 
			{
				if( TF0 == 1 ) 
				{
					goto DecExit; //如果定时0溢出则退出
				} 
			}
			TR0 = 0; //电平状态发生变化,停止计数
			Low_Level_Count = TH0;
			Low_Level_Count = Low_Level_Count << 8;
			Low_Level_Count = Low_Level_Count + TL0; //根据定时器0计数值取得低电平的宽度

			//if( ((TIME_BIT1 - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (TIME_BIT1 + TIME_BIT_RANDOM)) )//宽脉冲的低电平宽度:1表示
			if( ((Wide_Low - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (Wide_Low + TIME_BIT_RANDOM)) ) //宽脉冲的低电平宽度:1表示
			{
				g_Receive = g_Receive << 1;
				g_Receive = g_Receive + 0x01; //存入1
			}
			//else if( ((TIME_BIT0 - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (TIME_BIT0 + TIME_BIT_RANDOM)) ) //判断窄脉冲低电平宽度:0表示
			else if( ((Narrow_Low - TIME_BIT_RANDOM) < Low_Level_Count) && (Low_Level_Count < (Narrow_Low + TIME_BIT_RANDOM)) ) //窄脉冲低电平宽度:0表示
			{
				g_Receive = g_Receive << 1;
				//g_Receive = g_Receive + 0x00; //存入0
			}
			else 
			{
				goto DecExit; //在24个脉冲周期上,有一个在时间上匹配,则表明收到的为干扰波,丢弃掉
			}

			if( g_DecOK == 1 ) //如果接收到的数据已经解码处理完成,再重新获取新的数据
			{
				//LED1 = ~LED1;
				g_DecData = g_Receive;
			}
		}

		//g_Display = 0;//禁止向数码管送数据
		g_RecvOK = 1; //数据接收完毕,等待解析
		g_DecOK = 0;  //数据等待解析,重置解码标志
		Low_Level_Count = 0; //电平状态持续时间计数器归0
		return;
	}
	else 
	{
		goto DecExit;
	}

DecExit:
	{
		//LED3 = ~LED3; //改变P1.2状态
		TR0 = 0;
		EA = 1; //使能所有中断 
		EX0 = 1; //开外部中断0
		TF0 = 0; //溢出标志位软件清0
		return; 
	}		
} 


/************************************************
********** 功能:433模块退出,释放资源 **********
************************************************/
int m433_Exit(M433_Service *p433_srv)
{
    EA = 0;  //关闭所有中断 
    EX0 = 0; //关闭外部中断0
    TR0 = 0; //关闭定时器0
    TF0 = 0; //溢出标志位软件清0

    TH1 = 0; 
    TL1 = 0; 
    ET1 = 0; 
    TR1 = 0; //关闭定时器1

    count = 0;
    g_Receive = 0x0; //数据接收buffer
    g_DecData = 0x0; //待解码buffer,数据接收buffer的备份
    g_RecvOK = 0;	 //接收完成标志
    g_DecOK = 0;	 //解码完成标志,第一次进来置1以获取接收后的数据

    p433_srv->m433_Enable = 0;
    p433_srv->m433_LearnStart = 0;
    p433_srv->m433_LearnOK = 0;
    p433_srv->m433WorkMode = MODE_NORMAL; //1, 初始化为正常工作模式
    p433_srv->m433_DecData_Learn = 0x0; //新对码值
    p433_srv->m433_DecData_Curr = 0x0; //当前值
    //p433_srv->m433_DecData_Prev = 0x0; //以前接收到的编码信号值
    p433_srv->m433_DevCount = 0;

    g_Running = 0; //停止循环检测
    return 0;
}


/*********************************************************************
************************** main function *****************************
*********************************************************************/
int main(void)
{
    unsigned char i = 0;
    unsigned long dec_Data = 0x0; //解码后的24位编码
    M433_Service m433Serv; //struct.

    if( PrevInitial( &m433Serv ) ) //初始化全局变量
    {
        m433_Exit( &m433Serv );
        return -1; 
    }

    MCU_Int_Initial(); //中断、定时器/计数器初始化

    /**解析接收到的码值**/
    while( g_Running )
    {
        if( g_RecvOK ) //数据接收完成,等待解码
        {
            g_DecOK = 0; //置位0,表示数据解析还未完成

	#if 0
            P1 = g_DecData & 0xFF; 
            P1 = (g_DecData >> 8) & 0xFF;
            P1 = (g_DecData >> 16) & 0xFF; //此处可以通过点亮led来验证解码的结果,我的单片机板上只有8个led灯。

	#else

            m433Serv.m433_DecData_Curr = g_DecData;
            //if( 1 == m433Serv.m433_LearnStart ) //是否开始学习对码
            //{
            //    //m433Serv.m433_DecData_Prev = g_DecData; //开始对码,首先更新的之前保存的对码信号值 
            //    //m433Serv.m433_DecData_Learn = g_DecData; //新的编码信号值 
            //}

            if( m433Serv.m433_DecData_Curr == CTRL_KEY_ENABLE ) //======> 按键A:布防 <======
            {
                m433Serv.m433WorkMode = MODE_NORMAL; //1, 初始化为正常工作模式
                m433Serv.m433_Enable = 1; //使能433报警探测功能

                //LED0 = ~LED0;
            }
            else if( m433Serv.m433_DecData_Curr == CTRL_KEY_DISABLE ) //======> 按键B:撤防 <======
            {
                m433Serv.m433WorkMode = MODE_SLEEP; //睡眠模式,不输出报警信息
                m433Serv.m433_Enable = 0; //关闭433报警探测功能
                //LED1 = ~LED1;
            }
            else if( m433Serv.m433_DecData_Curr == CTRL_KEY_LEARNING ) //======> 按键C:学习对码 <======
            {
                m433Serv.m433WorkMode = MODE_LEARNING;//学习对码模式,把接下来收到的新编码存入码表
                //LED2 = ~LED2;
            }
            else if( m433Serv.m433_DecData_Curr == CTRL_KEY_TEST ) //======> 按键D:测试对码是否生效 <======
            {
                if( 1 == m433Serv.m433_LearnOK ) //学习对码成功,才可以测试新加入的设备是否生效
                {
                    m433Serv.m433WorkMode = MODE_TEST; //测试模式,匹配新报警设备的报警信号
                }
                else
                {
                    m433Serv.m433WorkMode = MODE_NORMAL; //对码不成功则依旧进入正常工作模式继续探测
                }
                //LED3 = ~LED3;
            }
            else //=============>四按键钥匙以外的编码信号到来<=============
            {	
                if( (1 == m433Serv.m433_LearnStart) && (0 == m433Serv.m433_LearnOK) )
                {
                    m433Serv.m433WorkMode = MODE_LEARNING; //如果对码模式已经开启,则进入对码模式开始学习新的编码信号值		
                }
                else
                {
                    m433Serv.m433WorkMode = MODE_NORMAL; //非对码模式则默认为正常工作模式
                }
                LED4 = ~LED4;
            }

            if( 0 == m433Serv.m433_Enable ) //如果未开启433布防功能
            {
                LED5 = ~LED5; 
            }
	#if 0
            if( m433_TaskSchedule( &m433Serv ) ) //433任务调度
            {
                printf("433 module task schedule error,exit!\n");
                m433_Exit( &m433Serv );
            }
	#endif
	#endif

            TF0 = 0; //定时器0溢出标志位清0
            EA = 1;  //开所有中断
            EX0 = 1; //重开外部中断0
            g_DecOK = 1;   //数据解码已经完成,可以接收新的数据了
            //g_Display = 1; //解析后的数据可以送数码管显示了 
            g_RecvOK = 0;  //解析完成,开始接收新的数据
        }

#if 0
        if (g_Display)
        {
            g_Display = 0;
            //Show_Data = 0x5555C0;
            Parse_DecData( Show_Data ); //解析编码数据,分位送8段数码管显示
        }

        //if (count == 250)//250ms间隔闪烁
        //{
        //	count = 0;
        //	LED0 = ~LED0;//改变P1.0状态
        //}	
#endif
    }

    m433_Exit( &m433Serv );
    return 0;
}

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值