mTouch 发表于 2012-11-18 19:32:03

利用C8051F340的PCA捕获功能捕获红外电平进行红外解码


下面的代码 移植自http://www.amobbs.com/forum.php?mod=viewthread&tid=5004479&highlight=PCA
能顺利进入PCA捕获中断,但是无法解码, 不知道原因在哪里!
有知道,请多指教!


#define IRSIZE486

#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long

#define uint8   unsigned char   
#define uint16unsigned int
#define uint32unsigned long


sbit    IrInput = P3^0;                  //红外线接收头输出端口
sbit    IrOutput = P3^1;                //控制红外发射管


sbit    LED1=P2^2;//LED指示灯端口
sbit    LED2=P2^3;//LED指示灯端口

unsigned char byteData;
unsigned char xdata v;               
unsigned char xdataIrKeyVal=0;         //解码键值
bit   B_Z;                              //丢弃第一次捕获标志

bit vt = 0;                //解码完成标志位

unsigned intt;
unsigned long nn;

void delay(uint d)
{
uint i;
for(i=0;i<d;i++);
}

/********************************************
函数:10ms × n 延时程序@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 port_init(void)
{
//红外捕捉,P3.0红外输入,串口输出
   P0SKIP    = 0xCF;                          //跳过前面I/O端口
   P1SKIP    = 0xFF;                          //跳过前面I/O端口
   P2SKIP    = 0xFF;                          //跳过前面I/O端口
   P3SKIP    = 0xFE;
   
   XBR0   = 0x01;             // Enable UART on P0.4(TX) and P0.5(RX)
   XBR1   = 0x41;                  //交叉开关打开,将PCA输出配置到P3.0脚(CEX0)
   
   P0MDOUT |= 0x10;                  // Enable UTX as push-pull output
               
   //1 1 1 1       1 1 0 0
   P2MDOUT= 0xfc;
   P3MDOUT= 0x03;                          // 使能P3.0为推挽输出
}


/***************************************************************************************
**函数名称: PCA0_Init
**函数功能: PCA0初始化
**输入参数: 无
**输出参数: 无
***************************************************************************************/
void PCA0_Init(void)    //PCA0初始化
{
    int i;
    PCA0CN = 0x00;       // Stop counter; clear all flags
        PCA0L = 0;                       // PCA0 Counter
        PCA0H = 0;
        PCA0CPH0 = 0x00;       //PCA0 Capture 0
        PCA0CPL0 = 0x00;

    PCA0MD = 0x80; // 系统时钟

        EIE1       |=        0x10;    //EPCA0 = 1,允许PCA0中断       C8051F340
        PCA0CPM0=        0x11;    //模块0下降沿中断允许,        模块0负沿捕捉使能与配匹使能


   B_Z = 1;
   t = 0;
   for(i=0;i<IRSIZE;i++)
   {
   v=0; //存储区清0
   }
}

/***************************************************************************************
**函数名称: PCA0_INT
**函数功能: PCA0中断处理, PCA中断捕获程序(电位跳变捕获模式)
**输入参数: 无
**输出参数: 无
***************************************************************************************/
void PCA_ISR (void) interrupt 11
{       
        if (CF == 1)        //计数器溢出中断,是否是PCA定时器溢出
        {
                CF = 0;        //计数器溢出标志清零,必须用软件清零,硬件不能自动清零
       
      v++;                //PCA定时器溢出计数,保存数据最高字节
      if( v>1 )                            //设置允许溢出次数,>131ms 终止捕获
      {
                   CR = 0;   
         CF = 0;
          // CCAPM2 = 0;
                   PCA0CPM0= 0;
         CCF0=0;
         vt = 1;                     //捕获完成标志
         v=0;
                   LED1 = 0;
         return;
         }       
               
        }

        if (CCF0) //是否是电位跳变, If Module 0 caused the interrupt   
    {   
      CCF0 = 0;// Clear module 0 interrupt flag.必须软件清0 (PCA 模块0标志)   

      //CL   = 0;                     //先赋值低位
      //CH   = 0;            
                PCA0L = 0;                       // PCA0 Counter
          PCA0H = 0;
      if(B_Z)
                {
                   CR =1;                   //启动PCA定时器
         B_Z=0;
         return;
                }   //丢弃第一次捕获数据
      t++;
      v = PCA0CPH0;               //保存数据高字节
      t++;
      v = PCA0CPL0;               //保存数据低字节
      t++;   
               LED1 =~LED1;            
       }

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

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:HEX转ASCII
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
unsigned char HEX2ASCII(unsigned char dat)
{
         dat &= 0x0f;
         if(dat <= 9) return(dat+'0');      //数字0~9('0' 0x30)
         return (dat-10+'A');                        //字母A~F('A' 0x41,'a' 0x61)
}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:串口发送
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void TxS(uint8 i)
{
    SBUF0=i;
    while(!TI0);
    TI0=0;
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:字符串发送
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void ZIFUC(uint8 code *p)                  //发送一串字符串
{
   for(; *p != 0; p++) TxS(*p);         //遇到停止符0结束
}


/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:整形数据送串口显示
入口:tem = 整形数据(送入1~4字节整形数据)
         num = 以什么进制显示,2:二进制,10:十进制,16:十六进制
         i   = 显示低几位          (以二进制显示时)
                   = 显示个位算起几位数(以十进制显示时)
                   = 显示几字节          (以十六进制显示时)
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void JZ(uint32 tem,uint8 num,uint8 i)
{
    unsigned int j,z;
    bit   BT=0;

   switch(num)
    {
      case2: /* tem = _lror_(tem,i-1); //以二进制显示
                     while(i--)
                     {
                     if(tem & 1)ZIFUC("1");
                                  else                  ZIFUC("0");
                      tem = _lrol_(tem,1);
                     } */
                              //* 【 另一种算法 】
                                 tem <<= (32-i);
                              while(i--)
                                 {
                                 if(tem & 0x80000000)ZIFUC('1');
                                  else                           ZIFUC('0');
                                 tem <<= 1;
                                 }
                                 break;

         case 10:
                     for(j=0;j<i;j++)//以十进制显示
               {
                     z = tem%10;                                        //nv=个位,nv=十位,······
                     tem /= 10;
               }
               
               while(i--)
               {
                  if(z || (i==0))BT=1;                //数据有效标志
                  if(BT)TxS(HEX2ASCII(z));             //数据有效前的“0”不显示,
                  elseZIFUC(" ");                                    //用空格替换。
               }
               break;

         case 16:
                  for(j=4-i;j<4;j++)//十六进制显示
            {
            z = ((unsigned int *)&tem);
            TxS(HEX2ASCII(z>>4));                        //发送高4位
            TxS(HEX2ASCII(z));                              //发送低4位
            }
             break;
    }
}


/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:串口发送主程序
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void ChuanKou()
{
    unsigned char i;
    unsigned int 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<IRSIZE;)
    {
       ((uchar *)&nn) = 0;
       ((uchar *)&nn) = v;
       ((uchar *)&nn) = v;
       ((uchar *)&nn) = v;

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

       ((uchar *)&nn) = 0;
       ((uchar *)&nn) = v;
       ((uchar *)&nn) = v;
       ((uchar *)&nn) = v;

       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) = v;
   ((uchar *)&T) = v;
   j += 3;
                              
   byteData >>= 1;
   if((T<1900) && (T>1000))byteData |= 0x80;
}

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

      if(byteData == ~byteData)
      {
         ZIFUC("\r\n\r\n 经对比,16位用户码是正反码,用户码正码:0x");
         JZ(byteData,16,1);
      }
      return;                                                
   }         
                     
///////////////// 初略分析是否是RC5编码 ////////////////
j=0;
for(i=0;i<20;i++)                                       
{
      j++;//最高位丢弃(1个数据3字节);
      ((uchar *)&T) = v;
      ((uchar *)&T) = v;

      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) = v;
       ((uchar *)&T) = v;
       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(byteData,16,1);      
    ZIFUC("    二进制:    ");
    JZ(byteData,2,2);
         
    ZIFUC("\r\n 控制位(1位):");
    if(byteData)ZIFUC("   1");
    else         
          ZIFUC("   0");

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

    ZIFUC("\r\n 数据位(6位):0x");
    JZ(byteData,16,1);      
    ZIFUC("    二进制:");
    JZ(byteData,2,6);
}

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:根据收集的脉冲数据进行RC5解码
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void IR_RC5()
{         
    bitB_v,BV;
    uchar x;
    uchar n;
    uintt;
                                                                        
    BV = 1;                              //BV=1时检测(接收端)低电平时间,BV=0时检测(接收端)高电平时间。
    x= 0;
    t= 0;
    byteData=byteData=byteData=byteData=0;

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

       /*┈┈┈ 确认位码值 ┈┈┈*/
       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)   
   {
      byteData >>= 1;
      if(B_v)
             byteData |= 0x02;
   }
   else if (n==2)
      byteData = B_v;
   else if (n<8)
   {
           byteData >>= 1;
       if (B_v)
             byteData |= 0x10;
        }
    else if (n<15)
        {
           byteData >>= 1;
       if(B_v)
             byteData |= 0x20;
    }
                                                   
   /*┈┈┈ 发射位码值 ┈┈┈*/                           
      ZIFUC("   ");   
      if(B_v)ZIFUC("1");
      else   ZIFUC("0");                                                
   }
}

void SYSCLK_Init(void)
{
   int i = 0;

// 内部高频使能,内部高频输出(不分频)
   OSCICN |= 0x83;                      // Set internal oscillator to run   
                                       // at its maximum frequency   

   CLKSEL = 0x00;                      // Select the internal osc. as   
                                       // the SYSCLK source   
   CLKMUL= 0x00;                     // Select internal oscillator as
                                       // input to clock multiplie

   for (i = 0; i < 3000; i++);         //延时等待振荡器起振防止读标志位错误

   RSTSRC= 0x04;                     // Enable missing clock detector
}

void UART0_Init(void)
{
   SCON0 = 0x10;                     // SCON0: 8-bit variable bit rate
                                       //      level of STOP bit is ignored
                                       //      RX enabled
                                       //      ninth bits are zeros
                                       //      clear RI0 and TI0 bits
   if (SYSCLK/BAUDRATE/2/256 < 1) {
      TH1 = -(SYSCLK/BAUDRATE/2);
      CKCON &= ~0x0B;                  // T1M = 1; SCA1:0 = xx
      CKCON |=0x08;
   } else if (SYSCLK/BAUDRATE/2/256 < 4) {
      TH1 = -(SYSCLK/BAUDRATE/2/4);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 01                  
      CKCON |=0x01;
   } else if (SYSCLK/BAUDRATE/2/256 < 12) {
      TH1 = -(SYSCLK/BAUDRATE/2/12);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 00
   } else {
      TH1 = -(SYSCLK/BAUDRATE/2/48);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 10
      CKCON |=0x02;
   }

   TL1 = TH1;                        // Init Timer1
   TMOD &= ~0xf0;                      // TMOD: timer 1 in 8-bit autoreload
   TMOD |=0x20;                     
   TR1 = 1;                            // START Timer1
   TI0 = 1;                            // Indicate TX0 ready
}

main()
{

   PCA0MD = 0x00;                      // Disable watchdog timer   
       
   SYSCLK_Init();
   port_init();                              //端口初始化

   UART0_Init();           //

   PCA0_Init();                                      //PCA初始化


    LED1 = 0;
        LED2 = 1;


   YS10ms(10);          
   CR =1;                  //启动PCA0计数器工作
   EA = 1;

        while (1)
        {
       

                if ( vt == 1)
                {
                  LED2=0;
                  vt = 0;
                        ChuanKou();                     //串口显示
                        YS10ms(200);
            //YS10ms(200);
            //YS10ms(200);                  //6秒后重新开始
                        PCA0_Init();
                        CR=1;
                        EA=1;
                        LED2=1;
                }       
        }       
}
页: [1]
查看完整版本: 利用C8051F340的PCA捕获功能捕获红外电平进行红外解码