查看: 1275|回复: 0
打印 上一主题 下一主题

利用PCA捕获捕获红外发射脉冲高、低电平时间,送串口显示

[复制链接]
跳转到指定楼层
沙发
发表于 2016-4-3 21:54:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
直接上图

(原文件名:TP3.jpg)


(原文件名:TP0.jpg)


(原文件名:TP1.jpg)


(原文件名:TP2.jpg)


程序如下:
/***************************************************************
        作品:捕获红外发射脉冲高、低电平时间,送串口显示
  单片机:STC12C5410
    晶振:12M
编译环境:Keil uVision4 V9.00
***************************************************************/
//  说明:1、适用于:1T系列含有PCA捕获的STC单片机
//        2、捕获引脚PCA2(也就是P2.0),3字节存放一个电平时间数据。
//        3、串口显示脉冲高低电平时间数据(串口:字符 57600bps 校验位N 数据位8 停止位1),
//        4、含NEC、RC5解码,如需其它解码请自己加入。
//
//  NEC码:(芯片有 市场上用量最大的HT6121/6122及其兼容的IC芯片等)
//        RC5码:(芯片有 SAA3006、SAA3010、SAA3027、PCA8521、PT2210 等)

#define uchar unsigned char   
#define uint  unsigned int
#define ulong unsigned long
#include <STC12C5410AD.h>
#include <CKA.H>

sbit IR = P2^0;                        //捕获引脚PCA2

uchar xdata v[486];               
uchar N[4];
uint  t;
ulong nn;

bit   VT;                                //捕获完成标志
bit   B_Z;                                //丢弃第一次捕获标志

void  ChuanKou();            //串口发送主程序
void  IR_RC5();                        //RC5解码



/********************************************
函数:10ms × n 延时程序   STC 1T@12MHz
*********************************************/
void YS10ms(uchar n)
{
  uchar i,j,k;
  for(i=n;i!=0;i--)
  for(j=198;j!=0;j--)
  for(k=150;k!=0;k--);
}
/********************************************
函数:接收初始化
*********************************************/
void JS_Init(void)
{
  uint i;
  
  B_Z = 1;
  t   = 0;
  for(i=0;i<486;i++)v=0; //存储区清0
                        
  EPCA_LVD = 1;                        //PCA模块中断和低压检测中断允许位
  CCAPM2  |= 0x31;                 //PCA模块2:16位捕获模式,由CCP2的跳变触发。ECCF2=1,使能CCF2中断。
  CMOD     = 0x01;                    //ECF=1(CMOD.0=1)使能CF(CCON.7)位产生中断
  EA       = 1;

  P21      = 0;                            //开始接收,指示灯打开
}
/********************************************
函数:主程序
*********************************************/
void main(void)
{
  UartInit(12,1);
  JS_Init();
  YS10ms(10);

  ZIFUC("\r\n\r\n\r\n                ****** 开始接收,请按遥控 ******\r\n");

  while(1)
  {  
        if(VT)
        {
          VT  = 0;
          P21 = 1;                        //接收完成,指示灯关闭
          ChuanKou();                        //串口显示

          YS10ms(200);
          YS10ms(200);
          YS10ms(200);                    //6秒后重新开始
      
          JS_Init();

          ZIFUC("\r\n\r\n\r\n                ****** 可以重新接收,请按遥控 ******\r\n");
        }  
  }
}

/***************************************************************
函数:PCA中断捕获程序(电位跳变捕获模式)
***************************************************************/
void PCA_isr(void) interrupt 6 using 1
{
         if(CF)                                           //是否是PCA定时器溢出
         {
            CF = 0;                       //必须软件清0 (PCA 定时器标志)
                v[t]++;                //PCA定时器溢出计数,保存数据最高字节
                if(v[t]>1)                            //设置允许溢出次数,>131ms 终止捕获
                { CR = 0;   
                  CF = 0;
                  CCAPM2 = 0;
              CCF2=0;
                  VT=1;                       //捕获完成标志
                  v[t]=0;
                  return;
                }
         }

         if(CCF2)                                   //是否是电位跳变
         {
                   CCF2 = 0;              //必须软件清0 (PCA 模块2标志)
                CL   = 0;                     //先赋值低位
        CH   = 0;            

        if(B_Z){ CR =1;                   //启动PCA定时器
                         B_Z=0;
                                 return; }     //丢弃第一次捕获数据
                t++;
                v[t]=CCAP2H;               //保存数据高字节
            t++;
        v[t]=CCAP2L;               //保存数据低字节
            t++;               
         }

     if(t >= 486)                   //捕获162个数据(1个电平时间3字节存放)
         {
                 CCAPM2 = 0;
                 CCF2=0;
                 CR = 0;
                 CF = 0;
                 VT = 1;                           //捕获完成标志
         }
}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:串口发送主程序
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void ChuanKou()
{
          uchar i;
          uint        j,T;
         
          ZIFUC("\r\n\r\n                ****** 接收完成 ******");
          ZIFUC("\r\n\r\n ( 以下是遥控器发射脉冲的波形数据 )");
          ZIFUC("\r\n\r\n  序号  高电平时间(us)  低电平时间(us)\r\n\r\n");

          i=0;

          for(j=0;j<486;)
          {
                          ((uchar *)&nn)[0] = 0;
                          ((uchar *)&nn)[1] = v[j++];
                          ((uchar *)&nn)[2] = v[j++];
                          ((uchar *)&nn)[3] = v[j++];

                          ZIFUC("  ");
                          JZ(i,10,2);                                //序号
                          ZIFUC("   ");                                    
                          JZ(nn,10,8);                            //高电平时间

                          ((uchar *)&nn)[0] = 0;
                          ((uchar *)&nn)[1] = v[j++];
                          ((uchar *)&nn)[2] = v[j++];
                          ((uchar *)&nn)[3] = v[j++];

                          ZIFUC("        ");                                                               
                          JZ(nn,10,8);                             //低电平时间

                      if( (i%8)==0 )ZIFUC("\r\n\r\n");
                          else ZIFUC("\r\n");
                          i++;
          }
                           
        ///////////////// NEC解码 ////////////////         
          j=9;                                                                                 //引导码丢弃
          for(i=0;i<32;i++)
          {
                          j++;
                          ((uchar *)&T)[0] = v[j++];
                          ((uchar *)&T)[1] = v[j++];
                          j += 3;
                             
                          N[i/8] >>= 1;
                           if((T<1900) && (T>1000))N[i/8] |= 0x80;
          }

          if(N[2] == ~N[3])         //校验NEC操作码。错误则尝试RC5解码
          {                     
                             ZIFUC("\r\n 【 NEC通用编码格式:引导码 + 32位编码(16位用户码+操作码正反码) 】\r\n");
                             ZIFUC("\r\n 用户码(高8位):0x");
                             JZ(N[0],16,1);      
                             ZIFUC("\r\n 用户码(低8位):0x");
                             JZ(N[1],16,1);
                                 
                                 ZIFUC("\r\n\r\n 操作码正码     :0x");
                             JZ(N[2],16,1);     
                                 ZIFUC("\r\n");

                                 if(N[0] == ~N[1])
                                 {
                                          ZIFUC("\r\n\r\n 经对比,16位用户码是正反码,用户码正码:0x");
                                          JZ(N[0],16,1);
                                 }

                                 return;                                                
          }           
                    
        ///////////////// 初略分析是否是RC5编码 ////////////////
          j=0;
          for(i=0;i<20;i++)                                         
          {
               j++;                                                                         //最高位丢弃(1个数据3字节);
                   ((uchar *)&T)[0] = v[j++];
                   ((uchar *)&T)[1] = v[j++];

              if(T<600 || T>1800)                                 //RC5码前20个脉冲数据600<nn<1800
                  {
                                  ZIFUC("\r\n 【 解码失败,再试一试或者分析波形数据 】");
                            return;
                  }
          }
        ///////////////// 将波形数据绘成图像 ////////////////
          ZIFUC("\r\n 【 RC5编码发射波形 】    发射顺序:(低位)<--(高位)\r\n");
          ZIFUC("\r\n___");
         
                j=0;
                for(i=0;i<26;i++)
                    {
                      j++;                                                                         //最高位丢弃(1个数据3字节);
                         ((uchar *)&T)[0] = v[j++];
                         ((uchar *)&T)[1] = v[j++];
                          if(T>2000)break;

                      if(i%2 != 1)                                                 //如果i是偶数
                          {
                                   if(T<1000)ZIFUC("▉");
                                   else       ZIFUC("▉▉");
                              }
                          else
                          {
                               if(T<950)ZIFUC("__");
                                   else       ZIFUC("____");
                              }
                    }

      ZIFUC("_____________");        
      ZIFUC("\r\n┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊  ┊\r\n");
          IR_RC5();                                                                       //RC5解码
      ZIFUC("\r\n┃起始位┃空┃      系统位      ┃        数据位        ┃\r\n");
          ZIFUC("\r\n\r\n 【 RC5通用编码格式:14位编码 】\r\n");

          ZIFUC("\r\n 起始位(2位):0x");
          JZ(N[0],16,1);      
          ZIFUC("    二进制:    ");
          JZ(N[0],2,2);
         
          ZIFUC("\r\n 控制位(1位):");
      if(N[1])ZIFUC("   1");
          else           ZIFUC("   0");

          ZIFUC("\r\n 系统位(5位):0x");
          JZ(N[2],16,1);      
          ZIFUC("    二进制: ");
          JZ(N[2],2,5);

          ZIFUC("\r\n 数据位(6位):0x");
          JZ(N[3],16,1);      
          ZIFUC("    二进制:");
          JZ(N[3],2,6);
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:根据收集的脉冲数据进行RC5解码
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void IR_RC5()
{         
         bit  B_v,BV;
         uchar x;
         uchar n;
         uint  t;
                                                                        
         BV = 1;                                //BV=1时检测(接收端)低电平时间,BV=0时检测(接收端)高电平时间。
         x  = 0;
         t  = 0;
         N[0]=N[1]=N[2]=N[3]=0;

         for(n=0;n<14;n++)            //14位位码解码
         {
                   x++;                            //最高位丢弃(1个数据3字节);
                ((uchar *)&t)[0] = v[x++];
                ((uchar *)&t)[1] = v[x++];

                /*┈┈┈ 确认位码值 ┈┈┈*/
                if(BV){ if(t < 950){B_v=1;x+=3;  } //BV=1时,如果t<950uS,下次还是检测(接收端)低电平时间,且跳过高电平时间。
                            else       {B_v=1;BV=0;} } //BV=1时,如果t>950uS,下次检测(接收端)高电平时间
                else  { if(t < 950){B_v=0;x+=3;}
                            else       {B_v=0;BV=1;} }

                /*┈┈┈ 装载位码值 ┈┈┈*/
                if(n < 2)    { N[0] >>= 1;
                           if(B_v)N[0] |= 0x02; }
                else if(n==2)  N[1] = B_v;
                else if(n<8) { N[2] >>= 1;
                               if(B_v)N[2] |= 0x10; }
                else if(n<15){ N[3] >>= 1;
                               if(B_v)N[3] |= 0x20; }
                                                   
                /*┈┈┈ 发射位码值 ┈┈┈*/                           
                ZIFUC("   ");   
                if(B_v)ZIFUC("1");
                else   ZIFUC("0");                                                
     }
}

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表