//*********************【 NEC解码头文件 】******************* 
// 
//     简介:本程序适用于NCE解码:(9ms+4.5ms)引导码+32位编码。 
//           兼容STC所有型号(包括 1T 和 12T 系列),可以定义任意I/O作红外接收脚, 
//                         自适应解码主频:6MHz ~ 40MHz。 
//  
// 使用条件:占用系统定时器0,开启定时器0中断(如使用其它定时器请自改IR_Init();初始化函数) 
//  
// 使用说明:填相关宏定义:USER_H、USER_L、Check_EN、CPU_Fosc、IR, 
//           上电初始化函数IR_Init(), 
//           在定时器0中断中调用IR_NEC()解码函数, 
//           解码有效时,IR_BT=2即短按,IR_BT=3即长按,由用户清0, 
//           解码存放:用户码高8位NEC[0],用户码低8位NEC[1],操作码NEC[2],操作码反码NEC[3]。 
// 
//【供用户调用的函数】 
//    IR_Init();                         //接收初始化,开启定时器0中断400us 
//    IR_NEC();                             //红外线解码(解NEC编码) 
//           
//***************************************************************/  
#ifndef __IR_NEC_H__ 
#define __IR_NEC_H__ 
 
 
//【用户必填项:USER_H、USER_L、Check_EN、CPU_Fosc、IR】 
#define  USER_H     0x80         //用户码高8位 
#define  USER_L     0x7F         //用户码低8位 
#define  Check_EN   0                    //是否要校验16位用户码:不校验填0,校验则填1         
#define  CPU_Fosc   12000000L    //输入主频,自适应解码(单位:Hz,范围:6MHz ~ 40MHz) 
#define  CA_S       8                    //长按时间设置,单位:108mS(即 108mS整数倍,10倍以上为宜) 
 
sbit IR = P3^6;                  //红外线接口(任意引脚)  
 
#define  Step       400          //红外采样步长:400us 
#define  TH_H      ((65536-Step*(CPU_Fosc/300)/40000)/256)  //定时器高8位基准赋值 
#define  TH_L      ((65536-Step*(CPU_Fosc/300)/40000)%256)  //定时器低8位基准赋值 
 
uint8   IR_BT;     //解码效果返回:0无效,1有效,2短按,3长按 
uint8   NEC[4];    //解码存放:16位用户码、操作码正反码 
uint8   cntCA;     //长按计数 
uint16  cntStep;   //步数计 
bit     IRa,IRb;   //接收脚电位状态保存 
bit     IRsync;    //同步标志 
uint8   BitN;      //位码装载数 
 
 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:红外线解码初始化 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void IR_Init() 
{ 
   TMOD &= 0xF0;           //清定时器0 
   TMOD |= 0x01;           //定时器0:16位定时器 
   TL0 = TH_L;           //每步时间 
   TH0 = TH_H; 
   ET0 = 1; 
   EA  = 1; 
   TR0 = 1; 
} 
 
/*┈┈┈┈┈┈┈┈┈┈ 基准 ┈┈┈┈┈┈┈┈┈┈┈*/ 
#define    Boot_Limit    ((9000+4500 +1000)/Step)   //引导码周期上限     
#define    Boot_Lower    ((9000+4500 -1000)/Step)   //引导码周期下限     
#define    Bit1_Limit    ((2250 +800)/Step)         //“1”周期上限 
#define    Bit0_Limit    ((1125 +400)/Step)         //“0”周期上限 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:红外线NEC周期采样解码法(定时中断,下降沿查询周期时间) 
全局变量:IR_BT = 0无效 
                  1有效,待继续判断长、短按(如不需要判断长、短按,则直接使用) 
                  2短按 
                  3长按 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void IR_NEC() 
{           
   TL0 = TH_L;   //重赋值 
   TH0 = TH_H;         
 
   cntStep++;    //步数累加 
   if(IR_BT==1)if(cntStep>300)IR_BT=2; //解码有效后,如果无长按,120ms(400us×300)后默认短按 
 
   IRb = IRa;    //保存上次电位状态 
   IRa = IR;     //保存当前电位状态 
 
   if(IRb && !IRa)    //是否下降沿(上次高,当前低) 
   { 
      if(cntStep > Boot_Limit)   //超过同步时间? 
      {         
          if(IR_BT==1)if(++cntCA>CA_S)IR_BT=3; //解码有效后,继续按住遥控>CA_S即长按 
          IRsync=0;                            //同步位清0 
      } 
      else if(cntStep > Boot_Lower){ IRsync=1; BitN=32; }   //同步位置1,装载位码数32                           
      else if(IRsync)            //如果已同步 
      { 
         if(cntStep > Bit1_Limit)IRsync=0;                    
         else 
         {         
            NEC[3] >>= 1;                                 
            if(cntStep > Bit0_Limit)NEC[3] |= 0x80;    //“0”与“1” 
            if(--BitN == 0)                                 
            { 
               IRsync = 0;    //同步位清0 
 
               #if (Check_EN == 1)                                         
               if((NEC[0]==USER_H)&&(NEC[1]==USER_L)&&(NEC[2]==~NEC[3]))    //校验16位用户码、操作码正反码 
               {  IR_BT=1; cntCA=0;  }     //解码有效,接下来判断:短按?长按? 
               #else 
               if(NEC[2]==~NEC[3]){ IR_BT=1; cntCA=0; }  //只校验操作码正反码 
               #endif                                         
            } 
            else if((BitN & 0x07)== 0)    //NEC[3]每装满8位,移动保存一次(即 BitN%8 == 0) 
            {   NEC[0]=NEC[1]; NEC[1]=NEC[2]; NEC[2]=NEC[3];   } 
         } 
      } 
      cntStep = 0;   //步数计清0 
   } 
}  
 
//取消相关宏定义 
#undef CPU_Fosc  
 
#endif 
 
 
 
 
 
主程序 
#include "INC\STC89C52RC.H" 
#include "INC\MY_SET.H" 
#include "INC\IR_NEC.H"        //调用NEC解码头文件 
 
sfr   SE   = 0x80;             //数码管段选 P0:0x80   P1:0x90  
sbit  WX1  = P2^0;                 //数码管位显 
sbit  WX2  = P2^1; 
sbit  WX3  = P2^2; 
sbit  WX4  = P2^3; 
sbit  WX5  = P2^4; 
sbit  WX6  = P2^5; 
sbit  WX7  = P2^6; 
sbit  WX8  = P2^7; 
 
uint8c tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0X88,0X83,0XC6,0XA1,0X86,0X8E,0xFF}; 
uint8  Xn,X1,X2,X3,X4,X5,X6; 
 
void KZ0();      //短按处理 
void KZ1();      //长按处理 
 
 
/***************** 主函数 ********************/ 
void main(void) 
{ 
   IR_Init();                           //红外线解码初始化 
 
   while(1) 
   {  
      //遥控检测 
      if((IR_BT==2)||(IR_BT==3))                           
      { 
         if(IR_BT==2)KZ0();      //短按处理                   
         else        KZ1();      //长按处理         
         IR_BT =0;               //清有效标志 
 
         X1 = NEC[0]/16;              //更新显示 
         X2 = NEC[0]%16; 
         X3 = NEC[1]/16; 
         X4 = NEC[1]%16; 
         X5 = NEC[2]/16; 
         X6 = NEC[2]%16;  
      } 
 
   } 
 
} 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:遥控短按处理 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void KZ0() 
{ 
   switch(NEC[2])              
   { 
          case 0x12: P10 = !P10; break; 
          case 0x05: break; 
          case 0x1E: break; 
          case 0x55: break; 
 
          case 0x01: break; 
          case 0x1B: break; 
          case 0x03: break; 
          case 0x6B: break; 
 
          case 0x07: break; 
          case 0x08: break; 
          case 0x09: break; 
          case 0x68: break; 
 
          case 0x22: break; 
          case 0xE6: break; 
          case 0x33: break; 
          case 0xE2: break; 
          default:break; 
   } 
} 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:遥控长按处理 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void KZ1() 
{ 
   switch(NEC[2])              
   { 
          case 0x12: P14 = !P14; break; 
          case 0x05: break; 
          case 0x1E: break; 
          case 0x55: break; 
 
          case 0x01: break; 
          case 0x1B: break; 
          case 0x03: break; 
          case 0x6B: break; 
 
          case 0x07: break; 
          case 0x08: break; 
          case 0x09: break; 
          case 0x68: break; 
 
          case 0x22: break; 
          case 0xE6: break; 
          case 0x33: break; 
          case 0xE2: break; 
          default:break; 
   } 
} 
/*********************数码管扫描*************************/ 
void XS(void) 
{  
  if(++Xn > 7)Xn=0; 
  switch(Xn)              
  { 
            case 0: WX8=1;  NOP;           //屏蔽上个位显 
                    SE=tab[X1];           //送段码 
                    WX1=0;           //开位显 
                    break; 
            case 1: WX1=1; NOP; SE=tab[X2]; WX2=0; break; 
            case 2: WX2=1; NOP; SE=tab[X3]; WX3=0; break;         
         case 3: WX3=1; NOP; SE=tab[X4]; WX4=0; break; 
         case 4: WX4=1; NOP; SE=tab[16]; WX5=0; break; 
         case 5: WX5=1; NOP; SE=tab[16]; WX6=0; break; 
         case 6: WX6=1; NOP; SE=tab[X5]; WX7=0; break; 
         case 7: WX7=1; NOP; SE=tab[X6]; WX8=0; break;                  
         default:break;                          
  } 
}  
 
/********************** 定时器0中断函数************************/ 
void time0(void) interrupt 1 
{  
   IR_NEC();  
   XS();          
}  
 
 
 
接收源程序+仿真 
点击此处下载 ourdev_689713KCBR6N.rar(文件大小:111K) (原文件名:NEC(任意接收引脚,支持长短按).rar)  
 
 
 
遥控器源程序 
点击此处下载 ourdev_689745J4Z85P.rar(文件大小:94K) (原文件名:遥控器源程序.rar)  
 
/*************************************************************** 
    作品:红外线遥控发射(NEC编码) 
  单片机:STC89C52RC 
    晶振:12M 
***************************************************************/ 
// 
// 发射引脚(接PNP三极管b极) 
// PNP三极管e极接2Ω电阻,c极接红外发射管 
 
#include <REG51.h> 
#include "INC\MY_SET.h" 
#include "INC\LCD1602_6IO.h"   
 
sbit  IR  = P3^6;                  //发射引脚(接PNP三极管基极) 
 
#define  USER_H   P2              //用户码高8位 
#define  USER_L   P0              //用户码低8位 
uint8c tab[16] = {                  //操作码 
0x12,0x05,0x1e,0x55, 
0x01,0x1b,0x03,0x6b, 
0x07,0x08,0x09,0x68, 
0x22,0xE6,0x33,0xe2}; 
 
#define m9    (65536-9000)           //9mS 
#define m4_5  (65536-4500)           //4.5mS 
#define m1_6  (65536-1650)           //1.65mS 
#define m_56  (65536-560)           //0.56mS 
#define m40   (65536-40000)       //40mS 
#define m56   (65536-56000)       //56mS 
#define m2_25 (65536-2250)        //2.25mS 
 
void  SanZhuan(); 
uint8 KEY(void); 
void  ZZ(uint8 x);                  //NEC编码发送程序 
void  Z0(uint8 temp);                  //单帧(8位数据)发送程序 
void  TT0(bit BT,uint16 x);          //38KHz载波发射 + 延时程序 
 
 
 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:主程序 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void main(void) 
{  
  TMOD = 0x01;         //T0 16位工作方式 
  IR=1;                  //发射端口常态为高电平 
  L1602_Init();  
  L1602_clr(); 
  L1602_xy(0,0); 
  L1602_ZIFUC("UserCode :0x");  
  L1602_xy(0,1); 
  L1602_ZIFUC("Opcode   :0x"); 
 
  while(1)  
  {            
   L1602_xy(12,0); 
   L1602_JZ(USER_H,16,1); 
   L1602_JZ(USER_L,16,1); 
   SanZhuan(); 
  } 
} 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:4×4矩阵键盘 
                      【 线翻转法键值表 】                     
P1.0  P1.1  P1.2  P1.3  P1.4  P1.5  P1.6  P1.7  
│     │    │    │    │    │    │    │     
│     │    │    └──7e    be    de   ee       
│     │    └─────7d    bd    dd   ed       
│     └────────7b    bb    db   eb       
└─────────── 77    b7    d7   e7     
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
uint8 KEY(void) 
{ 
  uint8 Key = 0; 
 
  P1 = 0xf0;           //键盘初始:行值=0,列值=1 
  NOP;                 //缓冲,待IO端口电位稳定 
  Key = P1&0xf0;       //得到行标志 
 
  P1  = 0x0f;          //翻转键盘接口输出 
  NOP; 
  Key |= (P1&0x0f);    //列标志 + 行标志 
 
  return Key;          //返回键值 
} 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:散转程序 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void SanZhuan() 
{ 
uint8 v; 
v = KEY();                           //键盘检测 
switch(v) 
{ 
  case 0x7e:ZZ(tab[0]);break;                 
  case 0xbe:ZZ(tab[1]);break;                 
  case 0xde:ZZ(tab[2]);break;                 
  case 0xee:ZZ(tab[3]);break;                 
  case 0x7d:ZZ(tab[4]);break;                 
  case 0xbd:ZZ(tab[5]);break;                 
  case 0xdd:ZZ(tab[6]);break;                 
  case 0xed:ZZ(tab[7]);break; 
  case 0x7b:ZZ(tab[8]);break;                 
  case 0xbb:ZZ(tab[9]);break;                 
  case 0xdb:ZZ(tab[10]);break;                 
  case 0xeb:ZZ(tab[11]);break; 
  case 0x77:ZZ(tab[12]);break;                 
  case 0xb7:ZZ(tab[13]);break;                 
  case 0xd7:ZZ(tab[14]);break;                 
  case 0xe7:ZZ(tab[15]);break;                                 
  default:break; 
} 
v=0; 
} 
 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:NEC编码发送程序 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void ZZ(uint8 Value) 
{  
  L1602_xy(12,1); 
  L1602_JZ(Value,16,1);    //更新显示 
 
  TT0(1,m9);             //高电平9mS 
  TT0(0,m4_5);             //低电平4.5mS 
 
  /*┈ 发送4帧数据┈*/ 
  Z0(USER_H);             //用户码高8位 
  Z0(USER_L);             //用户码低8位 
  Z0(Value);             //操作码 
  Z0(~Value);             //操作码反码 
 
  /*┈┈ 结束码 ┈┈*/ 
  TT0(1,m_56); 
  TT0(0,m40); 
 
  /*┈┈ 重复码 ┈┈*/ 
  while(KEY() != 0xFF) 
   { 
        TT0(1,m9); 
        TT0(0,m2_25); 
 
        TT0(1,m_56); 
        TT0(0,m40); 
        TT0(0,m56);                                   
    }                    
} 
 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:单帧(8位数据)发送程序 
入口:temp 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void Z0(uint8 temp) 
{  
  uint8 v; 
  for(v=0;v<8;v++)   
  {      
      TT0(1,m_56);                  //高电平0.65mS          
      if(temp&0x01) TT0(0,m1_6);  //发送最低位 
      else          TT0(0,m_56);      
      temp >>= 1;                 //右移一位  
  }     
} 
 
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 
函数:38KHz载波发射 + 延时程序 
入口:(是否发射载波,延时约 x (uS)) 
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ 
void TT0(bit BT,uint16 x) 
{ 
  TH0 = x>>8;                  //输入定时值 
  TL0 = x; 
  TF0=0;                        //溢出标志位清0 
  TR0=1;                        //启动定时器0 
  if(BT == 0) while(!TF0);        //BT=0时,不发射38KHz载波只延时; 
  else while(1)                //BT=1时,发射38KHz脉冲+延时;38KHz载波(低电平)占空比5:26 
       { 
              IR = 0; 
              if(TF0)break;if(TF0)break; 
              IR = 1; 
                if(TF0)break;if(TF0)break; 
                 if(TF0)break;if(TF0)break; 
                 if(TF0)break;if(TF0)break; 
                 if(TF0)break;if(TF0)break; 
                 if(TF0)break;if(TF0)break; 
       } 
  TR0=0;          //关闭定时器0 
  IR =1;          //载波停止后,发射端口常态为高 
} 
转载 
 
 |