这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 单片机实现PT2262解码示例代码

共2条 1/1 1 跳转至

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

高工
2018-06-21 08:34:14     打赏
  1. /************************************************************************************************************************ 
    ******* 文件名: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;  
    }



管理员
2018-06-21 08:43:01     打赏
2楼

谢谢楼主分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]