搜索
bottom↓
回复: 250

发一个红外线解码程序+仿真文件(可定义任意I/O作接收脚,支持长/短按,自适应主频6MHz~40

  [复制链接]

出0入0汤圆

发表于 2011-10-28 21:06:50 | 显示全部楼层 |阅读模式

(原文件名:TP0.jpg)




//*********************【 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;          //载波停止后,发射端口常态为高
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2011-10-28 21:25:03 | 显示全部楼层
mark 有空试试

出0入0汤圆

发表于 2011-10-28 22:53:25 | 显示全部楼层
发送部分代码看一下呀,只有解码

出0入0汤圆

发表于 2011-10-28 23:14:26 | 显示全部楼层
很不错

出30入0汤圆

发表于 2011-10-29 00:40:37 | 显示全部楼层
不错顶一下!

出0入0汤圆

发表于 2011-10-29 00:44:40 | 显示全部楼层
多任务的思想,不错

出0入0汤圆

发表于 2011-10-29 15:18:06 | 显示全部楼层
不错,mark一下

出0入0汤圆

发表于 2011-11-2 16:32:05 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-2 16:48:32 | 显示全部楼层
mark!!!

出0入0汤圆

发表于 2011-11-25 21:53:08 | 显示全部楼层
谢谢!

出0入0汤圆

发表于 2011-12-9 11:34:43 | 显示全部楼层
不错

出0入0汤圆

发表于 2011-12-9 23:15:07 | 显示全部楼层
好啊

出0入0汤圆

发表于 2011-12-12 21:14:59 | 显示全部楼层
还可以

出0入0汤圆

发表于 2011-12-20 10:45:13 | 显示全部楼层
实物怎么运行不了啊,1602无显示。

出0入0汤圆

 楼主| 发表于 2011-12-20 12:00:07 | 显示全部楼层
回复【13楼】pangjineng
-----------------------------------------------------------------------

1602的程序只是临时加进去,没经过实物验证

出0入30汤圆

发表于 2011-12-21 21:45:20 | 显示全部楼层
mark.有空再玩。学无止境啊

出0入0汤圆

发表于 2012-1-8 11:33:43 | 显示全部楼层
THX

出0入0汤圆

发表于 2012-1-13 12:06:12 | 显示全部楼层
不错,谢谢分享

出0入0汤圆

发表于 2012-2-2 19:04:22 | 显示全部楼层
回复【楼主位】BXAK
-----------------------------------------------------------------------

试了一下发射的,蛮不错的,测了发射的频率为38.6473K(低电平4.9375uS,脉宽25.875uS),请问一下要微调发射的频率,软件要咋改啊?谢谢

出0入0汤圆

 楼主| 发表于 2012-2-2 19:32:59 | 显示全部楼层
回复【18楼】tzsteel
-----------------------------------------------------------------------
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;
}

修改大括号里面的就可以,
频率有些高,降低添加适量的空操作“_nop_();”(注:不要放在大括号两侧)

(原文件名:TP0.jpg)

比如改成:

else while(1) //BT=1时,发射38KHz脉冲+延时;38KHz载波(低电平)占空比约5:26
{
          IR = 0;
          if(TF0)break;if(TF0)break;
          _nop_();
          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;
}

出0入0汤圆

发表于 2012-2-2 22:43:29 | 显示全部楼层
新人,表示有压力!

出0入0汤圆

发表于 2012-2-3 00:12:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-3 13:58:57 | 显示全部楼层
回复【19楼】BXAK
-----------------------------------------------------------------------

谢谢楼主解答,试了一下加NOP;是可以减少频率,加if(TF0)break;也是一样的,但加或减这些语句低电平4.9375uS是一直不变的,变的只是后面高电平的时间,请问一下要增加低电平的时间要咋改软件?谢谢

出0入0汤圆

发表于 2012-2-3 15:13:27 | 显示全部楼层
红外遥控 MARK

出0入0汤圆

 楼主| 发表于 2012-2-3 19:15:56 | 显示全部楼层
回复【22楼】tzsteel
-----------------------------------------------------------------------

调整低/高时间比例,比如

else while(1) //BT=1时,发射38KHz脉冲+延时;38KHz载波(低电平)占空比约5:26  
{  
          IR = 0;  
          if(TF0)break;if(TF0)break;
          if(TF0)break;if(TF0)break;
          _nop_();
          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;  
}

出0入97汤圆

发表于 2012-2-3 19:24:34 | 显示全部楼层
mark谢谢

出0入0汤圆

发表于 2012-2-3 23:23:59 | 显示全部楼层
好贴,好人,好思路!

出0入0汤圆

发表于 2012-2-4 08:33:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-4 17:14:55 | 显示全部楼层
谢了,下载试试

出0入0汤圆

发表于 2012-2-4 19:29:20 | 显示全部楼层
回复【24楼】BXAK
-----------------------------------------------------------------------

非常感谢

出0入0汤圆

发表于 2012-2-4 19:30:13 | 显示全部楼层
回复【24楼】BXAK
-----------------------------------------------------------------------

非常感谢

出0入0汤圆

发表于 2012-2-4 20:04:11 | 显示全部楼层
多谢分享,先留名再看

出0入0汤圆

发表于 2012-2-4 21:21:05 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-4 21:39:30 | 显示全部楼层
mark!

出0入0汤圆

发表于 2012-2-5 20:43:28 | 显示全部楼层
回复【24楼】BXAK
-----------------------------------------------------------------------

请问一下楼主,else while(1) //BT=1时,发射38KHz脉冲+延时;38KHz载波(低电平)占空比约5:26   
{   
          IR = 0;   
          if(TF0)break;if(TF0)break;  
          if(TF0)break;if(TF0)break;
          _nop_();  
          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;   
}  这段程序中,是怎么产生38KHz脉冲的?比如9mS时,定时器装的初值是65536-9000,计数满9000次TF0才为1,要产生5:26的38KHz载波不能理解,但用数字示波器看波型,9mS确实是由一串等分的38KHz载波组成.谢谢

出0入0汤圆

 楼主| 发表于 2012-2-5 22:42:39 | 显示全部楼层
回复【34楼】tzsteel
-----------------------------------------------------------------------

通过软件产生啊,你通过反汇编查看这段C的汇编代码看看,对照“51指令执行所用时钟表”就知道了

那9mS区间一直循环着while(1)
{                                   //12MHz时指令执行时间
          IR = 0;                   //1us
          if(TF0)break;             //2us
          if(TF0)break;   
          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;   
}
上面一个循环正好26us(传统51@12MHz晶振,比如STC89系列),周期26us则频率38.461KHz

出0入0汤圆

发表于 2012-2-6 20:45:56 | 显示全部楼层
回复【35楼】BXAK
-----------------------------------------------------------------------

谢谢,非常好的思路.

出0入0汤圆

发表于 2012-2-6 20:53:03 | 显示全部楼层
学习收藏,谢谢楼主

出0入0汤圆

发表于 2012-2-6 21:22:57 | 显示全部楼层
红外解码多任务思路

出0入0汤圆

发表于 2012-2-7 09:47:27 | 显示全部楼层
要学习

出0入0汤圆

发表于 2012-2-16 10:09:27 | 显示全部楼层
mark留用!

出0入0汤圆

发表于 2012-2-16 19:28:42 | 显示全部楼层
收藏,学习。

出0入0汤圆

发表于 2012-2-16 23:35:19 | 显示全部楼层
想搞红外很久了,以前学习的时候也试过,但是没有成功。楼主程序写的很不错,虽然看不太懂,但是楼主的解释很详细。
先收藏了,等有时间了,好好研究。非常感谢楼主分享。


还有个问题想请教楼主

  发射程序中&#160;&#160;

else&#160;while(1) //BT=1时,发射38KHz脉冲+延时;38KHz载波(低电平)占空比5:26
&#160;&#160;&#160;&#160;&#160;&#160;{
&#160;&#160;&#160;&#160;&#160;&#160;IR&#160;=&#160;0;
&#160;&#160;&#160;&#160;&#160;&#160;if(TF0)break;if(TF0)break;
&#160;&#160;&#160;&#160;&#160;&#160;IR&#160;=&#160;1;
&#160;&#160; &#160;&#160;&#160;&#160;if(TF0)break;if(TF0)break;
&#160;&#160;&#160; &#160;&#160;&#160;if(TF0)break;if(TF0)break;
&#160;&#160;&#160; &#160;&#160;&#160;if(TF0)break;if(TF0)break;
&#160;&#160;&#160; &#160;&#160;&#160;if(TF0)break;if(TF0)break;
&#160;&#160;&#160; &#160;&#160;&#160;if(TF0)break;if(TF0)break;
&#160;&#160;&#160;&#160;&#160;&#160;}
&#160;&#160;TR0=0; &#160;&#160;//关

占空比非得5:26左右吗?
只要占空比小于1,能行吗?


这个软件实现载波实在是不懂。

出0入0汤圆

 楼主| 发表于 2012-2-17 00:31:29 | 显示全部楼层
回复【42楼】vp110
-----------------------------------------------------------------------

晕,没规定一定是5:26,低占空比是为了节省能量的同时,通过接小限流电阻(2.2Ω ~ 4.7Ω)获得高峰值电流,

比如:像电视遥控器之类一般都是(高电平)占空比约1:3,用NPN三极管驱动。

这也是为什么不用可编程时钟输出 或者 定时器中断 产生38K载波的原因之一,而普通的51没有PWM,想获得低占空比的38K载波只好用软件实现了。


你看看下面的信息,会有收获的:

二、红外发射(接收)距离与哪些因素有关?怎样提高红外发射管的发射距离?

      常用的红外发射管,它的外形与普通的发光二极管(LED)相似,发出人眼不可见的近红外线,约0.93μm 。工作电流小于20ma,为了使其在不同的电路中正常使用,回路中常串有限流电阻。 使用红外线控制时,其控制的距离与发射功率成正比。
      红外发射管工作于脉冲状态,因为脉动光(调制光)的有效传送距离与脉冲的峰值电流成正比,只需尽量提高峰值Ip,就能增加红外光的发射距离。
      提高Ip 的方法:尽量减小脉冲占空比,即压缩脉冲的宽度т,比如家电红外遥控中,红外发射管的工作脉冲占空比约为1/4~1/3;一些电气产品红外遥控器,其占空比是1/10。减小脉冲占空比可使红外发射管的发射距离增大。
       常见的红外发射管,其功率分为小功率(1mW~10mW)、中功率(20mW~50mW)和大功率(50mW~100mW以上)三大类。要使红外发光二极管产生调制光,只需在驱动管上加上一定频率的脉冲电压。
       用红外发光二极管发射红外线去控制受控装置时,受控装置中均有相应的红外接收元件,现在常用的是一体化的红外接收头,一体化的红外接收头相关材料看这里:图解红外遥控的发射和接收原理。
       红外线发射与接收的方式有两种,其一是直射式,其二是反射式。直射式指红外发射管和红外接收头相对安放在发射与受控物的两端,中间相距一定距离,比如常见的红外遥控;反射式是指红外发射管和红外接收头在同一平面上,红外发射管发出的红外光经过物体反射回来,被红外接收头接收。

三、红外发射、接收遥控距离,轻松达到10米以上:

(1)发射载波一定要接近接收头的中心频率(最关键);
(2)提高发射电流峰值Ip:使用三极管驱动发射管,占空比1:3(或者1:4……等等),小限流电阻(2欧姆):
    ①使用NPN型三极管驱动时,用“高电平”占空比(如果是没有推挽输出的51,应加3K左右的上拉电阻
);
    ②使用PNP型三极管驱动时,用“低电平”占空比(没有推挽输出的51推荐用PNP)。                                
(3)选用 脉冲型 红外接收头。

出0入0汤圆

发表于 2012-2-17 18:06:44 | 显示全部楼层
基本上是了解了


谢谢楼主

出0入0汤圆

发表于 2012-2-23 00:04:20 | 显示全部楼层
感谢楼主的分享!我非常喜欢你的思路

在这里提一个问题:按说STC的1T单片机的定时器默认是12T分频的,所以这个程序应该可以直接移植到STC的1T单片机上,但我把程序移植到了STC11F04上,用红外一体头接受没有信号,吧红外LED换成普通LED,能看到闪烁,和正常遥控器遥控一体头的信号看不出什么区别,因为手头上没有示波器,所以无法抓红外的波形。

求解,楼主能不能放个STC1T的红外发射程序,就这个在网上还比较稀缺,谢谢!

出0入0汤圆

发表于 2012-2-23 00:15:01 | 显示全部楼层
mark,留名

出0入0汤圆

 楼主| 发表于 2012-2-23 00:45:39 | 显示全部楼层
回复【45楼】wangyz1997
-----------------------------------------------------------------------

因为那个发射程序的38K载波使用软件指令生成,所以上面的发射程序不兼容1T系列,

STC 1T系列换成下面的( 另:如果不喜欢用“goto”,就用“if(TF0)break;” )

/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:38KHz载波发射 + 延时
入口:(是否发射载波,约 X (uS))
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void TT0(bit BT,uint16 X)
{
   uint8 t;

   TH0 = ((uint8 *)&X)[0];        //X高8位
   TL0 = ((uint8 *)&X)[1];        //X低8位
   TF0=0;                                //清0
   TR0=1;                                //启动定时器0
                                                                 
   if(BT)                                //38KHz载波,(低电平)占空比约 9:(9+28)【12M: 1t <=> 1/12(uS),38KHz周期26.316uS <=> 316t 】
   {                                                 
          while(1)
          {
            IR_Out = 0;                                                 // 4t
        for(t=9;t;t--)if(TF0)goto TN;    // 2t + (4t+4t)*x
        if(TF0)goto TN;                                         // 4t
                IR_Out = 1;                                                 // 4t
        for(t=28;t;t--)if(TF0)goto TN;         // 2t + (4t+4t)*x
                if(TF0)goto TN;                                     // 4t
          }                                                                         
   }                                                                         
   else while(!TF0);

TN:TR0 =0;                                //关闭定时器0
   IR_Out =1;                            //38KHz载波停止后,发射端口常态=1
}

出0入0汤圆

发表于 2012-2-23 15:10:26 | 显示全部楼层
mark   研读。。。

出0入0汤圆

发表于 2012-2-23 18:33:41 | 显示全部楼层
回复【47楼】BXAK
-----------------------------------------------------------------------

BXAK大侠,你太厉害了!让我这个新手佩服不已啊!

就是注释里的// 2t + (4t+4t)*x   是什么意思?软延时计算吗?求教!

出0入0汤圆

 楼主| 发表于 2012-2-23 20:32:07 | 显示全部楼层
回复【49楼】wangyz1997
-----------------------------------------------------------------------

业余爱好罢了,闲时就折腾折腾

是延时计算,
你可以用keil反汇编看代码 对照 指令执行时间表 计算,
也可以用keil断点调试直接查看指令执行时间(适合STC 12T系列),
也可以用TKStudio断点调试直接查看指令执行时间(适合STC 1T、12T系列)

STC 12T系列(传统51) STC 1T系列 指令执行时间查询:点击此处下载 ourdev_721603SOZVXC.pdf(文件大小:1.38M) (原文件名:STC 1T 12系列 指令执行时间查询.pdf)

出0入0汤圆

发表于 2012-2-23 21:14:04 | 显示全部楼层
谢谢!长见识了!

出0入0汤圆

发表于 2012-2-24 03:04:52 | 显示全部楼层
回复【楼主位】BXAK
-----------------------------------------------------------------------

mark

出0入0汤圆

发表于 2012-2-24 13:13:47 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-27 12:18:50 | 显示全部楼层
学习,谢谢分享。

出0入0汤圆

发表于 2012-2-28 20:41:41 | 显示全部楼层
能遥控电视吗?遥控电视需要改哪里?谢谢。

出0入0汤圆

 楼主| 发表于 2012-2-28 21:33:29 | 显示全部楼层
回复【55楼】chinasy519
-----------------------------------------------------------------------

是NEC编码格式(9ms高 + 4.5ms低 + 16位用户码 + 8位操作码正/反码)的就可以,换上你遥控器的用户码、操作码

出0入0汤圆

发表于 2012-2-28 22:18:41 | 显示全部楼层
回复【56楼】BXAK
回复【55楼】chinasy519  
-----------------------------------------------------------------------
是nec编码格式(9ms高 + 4.5ms低 + 16位用户码 + 8位操作码正/反码)的就可以,换上你遥控器的用户码、操作码
-----------------------------------------------------------------------

谢谢!遥控电视实验成功。

出0入0汤圆

发表于 2012-2-29 01:09:30 | 显示全部楼层
强大,实物简单测试了一下,发射成功,1602有显示,用户码控制码可以控制电视。

还有个问题,就是如果我用STC11F104E   1T单片机,没有P0 P2口,如何设置用户码?
比如用户码固定为 0xcced ,如何改呢?

出0入0汤圆

 楼主| 发表于 2012-2-29 01:39:53 | 显示全部楼层
回复【58楼】b60885262
-----------------------------------------------------------------------



#define  USER_H   P2              //用户码高8位
#define  USER_L   P0              //用户码低8位

改成

#define  USER_H   0xcc              //用户码高8位
#define  USER_L   0xed              //用户码低8位

实物直接去掉1602显示得了(把"INC\LCD1602_6IO.h"去掉,有关于1602的函数也去掉),
加入掉电模式,按键中断唤醒,一副电池用一年都可以,再加个指示灯,


(原文件名:20110819099.jpg)

出0入0汤圆

发表于 2012-2-29 01:50:13 | 显示全部楼层
回复【59楼】BXAK
-----------------------------------------------------------------------

谢谢指导,明天我试试!
楼主注意休息啊,呵呵!

出0入0汤圆

发表于 2012-2-29 01:59:57 | 显示全部楼层
回复【59楼】BXAK
-----------------------------------------------------------------------

刚看到你的图片,能不能把你的实物程序发给我 60885262@163.com

那么多按键,估计不好拿吧?我打算只用5个按键就可以了。常用的换台加减,音量加减,和静音键就好了。这样体积可以更小。

出0入0汤圆

发表于 2012-2-29 11:14:07 | 显示全部楼层
好思路学习一下。

出0入0汤圆

发表于 2012-3-28 15:18:42 | 显示全部楼层
顶一个!!

出0入0汤圆

发表于 2012-3-28 15:50:37 | 显示全部楼层
mark一下。

出0入0汤圆

发表于 2012-3-30 22:32:59 | 显示全部楼层
过了一遍 感觉很好,下次仔细研究下 谢谢

出0入0汤圆

发表于 2012-3-30 23:39:00 | 显示全部楼层
这么多人都说好!那好吧,我也马克吧。

出0入0汤圆

 楼主| 发表于 2012-3-31 12:15:18 | 显示全部楼层
以前写的有缺陷啊,
【1】
像:
uint16  cntStep;   //步数计
uint16 即 unsigned int ,其实用 uint8 (即 unsigned char)就够了,这样省了些运算提高了速度

【2】
像:
{
    TL0 = TH_L;   //重赋值
    TH0 = TH_H;        

   cntStep++;    //步数累加
    if(IR_BT==1)if(cntStep>300)IR_BT=2; //解码有效后,如果无长按,120ms(400us×300)后默认短按

   IRb = IRa;    //保存上次电位状态
    IRa = IR;     //保存当前电位状态
……

接收端的电平查询应该放在前面合理些:
{
    TL0 = TH_L;   //重赋值
    TH0 = TH_H;

   IRb = IRa;    //保存上次电位状态
    IRa = IR;     //保存当前电位状态      

   cntStep++;    //步数累加
    if(IR_BT==1)if(cntStep>300)IR_BT=2; //解码有效后,如果无长按,120ms(400us×300)后默认短按
……



出0入0汤圆

发表于 2012-4-7 09:23:02 | 显示全部楼层
楼主给个联系方式

出0入0汤圆

发表于 2012-4-7 10:30:53 | 显示全部楼层

出0入0汤圆

发表于 2012-4-7 11:40:35 | 显示全部楼层
谢谢哦。是个好贴,学习了

出0入0汤圆

发表于 2012-4-10 22:29:07 | 显示全部楼层
强悍!

出0入0汤圆

发表于 2012-4-11 11:32:49 | 显示全部楼层
强悍啦,不错,顶顶

出0入0汤圆

发表于 2012-4-11 12:38:20 | 显示全部楼层
请教,为何要这个样
#define  TH_H      ((65536-Step*(CPU_Fosc/300)/40000)/256)  //定时器高8位基准赋值
#define  TH_L      ((65536-Step*(CPU_Fosc/300)/40000)%256)  //定时器低8位基准赋值
进行/300 再/40000??????????????

出0入0汤圆

发表于 2012-4-11 12:50:07 | 显示全部楼层
有空试试!!!

出0入0汤圆

发表于 2012-4-11 13:19:30 | 显示全部楼层
值得学习啊。。。

出0入0汤圆

发表于 2012-4-11 13:33:47 | 显示全部楼层
这么好的资料,对新手来说太好了。谢谢!

出0入0汤圆

 楼主| 发表于 2012-4-11 15:09:13 | 显示全部楼层
本帖最后由 BXAK 于 2012-4-11 15:10 编辑
hpdell 发表于 2012-4-11 12:38
请教,为何要这个样
#define  TH_H      ((65536-Step*(CPU_Fosc/300)/40000)/256)  //定时器高8位基准赋值 ...


编译软件是Keil,其它的不知有没有这种情况

其实原是:Step*CPU_Fosc/120000000       ①
为什么用:Step*(CPU_Fosc/300)/40000     ②

unsigned long  范围: 0 ~ 4,294,967,295

如果Step = 400,4294967295/400 = 10737418.2375,
当 CPU_Fosc < 10,737,418 时,用①没问题,因为 Step*CPU_Fosc < 4,294,967,295;
当 CPU_Fosc > 10,737,418 时,用①就会有溢出问题,因为 Step*CPU_Fosc > 4,294,967,295;

②缩小300倍后计算, Step*(CPU_Fosc/300) / (120000000/300) →  Step*(CPU_Fosc/300)/40000
   保证CPU_Fosc < 40,000,000 范围内,Step*(CPU_Fosc/300)  < 4,294,967,295,这样就不会有溢出问题

不过用 Step*(CPU_Fosc/100)/120000 应该够了,具体的,你可以编译后反汇编看看代码就知道其中的差异了

出0入0汤圆

发表于 2012-4-11 15:55:13 | 显示全部楼层
好人!赞!

出0入0汤圆

发表于 2012-4-11 16:40:50 | 显示全部楼层
本帖最后由 hpdell 于 2012-4-11 16:45 编辑
BXAK 发表于 2012-4-11 15:09
编译软件是Keil,其它的不知有没有这种情况

其实原是:Step*CPU_Fosc/120000000       ①


谢谢你的回复,现在有些明白了。兄台考虑的很全面啦。

出0入0汤圆

发表于 2012-4-11 16:49:51 | 显示全部楼层
  学习了

出0入0汤圆

发表于 2012-4-11 16:58:39 | 显示全部楼层
楼主的态度很值得学习.

软件也很棒.

出0入0汤圆

发表于 2012-4-11 19:37:28 | 显示全部楼层
学习收藏,谢谢楼主

出0入0汤圆

发表于 2012-4-12 22:22:31 | 显示全部楼层
效果不错哦

出0入0汤圆

发表于 2012-4-12 23:09:10 | 显示全部楼层
不错啊!有空试一下

出0入0汤圆

发表于 2012-5-4 18:25:17 | 显示全部楼层
你好:BXAK

         红外接收程序在51单片机试过效果很好,可是我把这思路移植到AVR上怎么就不行了,帮忙参考。

#include<avr\io.h>
#include<avr\interrupt.h>
#include<util\delay.h>




/*==================================
         遥控代码处理
==================================*/
unsigned char i,TEST_flag;
unsigned int TEST=0;


#define  USER_H     0x02             //用户码高8位
#define  USER_L     0xfd             //用户码低8位
#define  Check_EN   0             //是否要校验16位用户码:不校验填0,校验则填1   
#define  CA_S       8                //长按时间设置,单位:108mS(即 108mS整数倍,10倍以上为宜)
#define  IR      (PINB&_BV(PINB7))                  //PB4//红外线接口(任意引脚)
#define  Step      400           //红外采样步长:400us


//#define  TH_H       (65536-(8000000*0.0004)/256)  //定时器高8位基准赋值
//#define  TH_L       (65536-(8000000*0.0004)%256)  //定时器低8位基准赋值

unsigned char   IR_BT;               //解码效果返回:0无效,1有效,2短按,3长按
unsigned char   NEC[4];              //解码存放:16位用户码、操作码正反码
unsigned char   cntCA;               //长按计数
unsigned int    cntStep;             //步数计        
unsigned char  IRa , IRb  ;   //电位状态保存

unsigned char  IRsync   ;   //同步标志

unsigned char   BitN;                //位码装载数
/*┈┈┈┈┈┈┈┈┈┈ 基准 ┈┈┈┈┈┈┈┈┈┈┈*/
#define    Boot_Limit       (((9000+4500) +2000)/Step)    //引导码周期上限   
#define    Boot_Lower       (((9000+4500) -2000)/Step)    //引导码周期下限   
#define    Bit1_Limit       ((2250 +800)/Step)            //“1”周期上限800
#define    Bit0_Limit       ((1125 +400)/Step)            //“0”周期上限400
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:红外线NEC周期采样解码法(定时中断,下降沿查询周期时间)
全局变量:IR_BT = 0无效
                  1有效,待继续判断长、短按(如不需要判断长、短按,则直接使用)
                  2短按
                  3长按
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:遥控短按处理
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void KZ0(void)
{
    switch(NEC[2])
    {
    case 0x0D:        //音量加
        break;
    case 0x0E:        //音量减
        break;
    case 0x0A:        //上曲
        break;
    case 0x15:         //下曲
        break;
    case 0x0C:    PORTC=0XFF;      //播放
        break;
    case 0x66:         //单曲
        break;
    case 0x12:         //循环
        break;
    case 0x09:         //电源
        break;
    default:
        break;
    }
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:遥控长按处理
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
void KZ1(void)
{
    switch(NEC[2])
    {
    case 0x0D:        //音量加
        break;
    case 0x0E:        //音量减
        break;
    case 0x0A:        //上曲
        break;
    case 0x15:         //下曲
        break;
    case 0x0C:     PORTC=0XFF;    //播放
        break;
    case 0x66:         //单曲
        break;
    case 0x12:         //循环
        break;
    case 0x09:         //电源
        break;
    default:
        break;
    }
}
/*=================================
      红外遥控译码
=================================*/
void IR_NEC(void)
{
    cntStep++;         //步数采样
    if(IR_BT==1)if(cntStep>300)
        {
            IR_BT=2;    //解码有效后,如果无长按,120ms(400us×300)后默认短按
        }
    IRb = IRa;         //上次电位状态
    IRa = IR;          //当前电位状态
    if((IRb==1) &&(IRa==0))                   //是否下降沿(上次高,当前低)
    {
       if(cntStep > Boot_Limit)      //超过同步时间?38.75
        {
            if(IR_BT==1)if(++cntCA>CA_S)
                {
                    IR_BT=3;    //解码有效后,继续按住遥控>CA_S即长按
                }
            IRsync=0;                 //同步位清0
        }
        else if(cntStep > Boot_Lower)//28.75
        {
            IRsync=1;    //同步位置1,装载位码数
            BitN=32;
        }
        else if(IRsync)                                    //如果已同步
        {
            if(cntStep >Bit1_Limit)//7.6
            {if(TEST_flag==0){TEST=2;TEST_flag=1;}
                IRsync=0;       
            }
            else
            {
                NEC[3] >>= 1;
                if(cntStep >Bit0_Limit)//3.8
                {
                    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
    }
}
/*==================================
            主程序
===================================*/
int main()
{   
    DDRC=0XFF;
    cli();         //关总中断
    TCCR1B  = 0x00;//停止定时器
        OSCCAL=0XBF;  //内部时钟校准补尝
   TCNT1H =0XF3; //225;//初始值
   TCNT1L  =0X80; //225;//初始值
       
    TIMSK1 |= 0x01;//中断允许
    TCCR1B  = 0x01;//03启动定时器
    DDRB&=~_BV(DDB7);//PIN7输入
        PORTB&=~_BV(PORTB7);//PORTB7配置上拉电阻
        sei();   //开总中断
        for(;;)
        {
         
        if((IR_BT==2)||(IR_BT==3))
        {
            if(IR_BT==2)
            {
                KZ0();    //短按处理
            }
            else
            {
                KZ1();    //长按处理
            }  
                         IR_BT=0;
        }

/***********************************         
                 for(;TEST>0;)
                  {
                PORTC=0XFF;
            _delay_ms(1000);    调试用计算步
                         PORTC=0X00;
                   _delay_ms(1000);               
                   TEST--;
if(TEST==0){TEST_flag=0;}
                   }
   
        }
        return 0;

}
************************/
/*==================================
    定时中断
===================================*/
ISR(TIMER1_OVF_vect)
{
  TCNT1H=0XF3;//定时400US
  TCNT1L=0X80;
    IR_NEC();
        PORTC^=_BV(PORTC1);
}

出0入0汤圆

 楼主| 发表于 2012-5-4 20:35:47 | 显示全部楼层
本帖最后由 BXAK 于 2012-5-4 22:08 编辑
xyr 发表于 2012-5-4 18:25
你好:BXAK

         红外接收程序在51单片机试过效果很好,可是我把这思路移植到AVR上怎么就不行了,帮 ...


才开始学AVR,暂时帮不了,
有条件的话,你看看AVR定时器是否每400us定时中断,是否正确捕捉接收脚的电平……

补充:
我觉得问题可能是
51有可位寻址区,所以用 位 来保存接收脚状态很方便,
bit IRa,IRb;
if((IRb==1) &&(IRa==0))  下降沿判断没问题

但在AVR中用unsigned char IRa,IRb保存电位状态,
if((IRb==1) &&(IRa==0))  应该不适合了

出0入0汤圆

发表于 2012-5-5 09:08:28 | 显示全部楼层
用位域定义过位 IRb IRa if(IRb&&!IRa)不行,
在这测试(PORTC^=_BV(PORTC1);)频率为1.24K符正常的。

出0入0汤圆

 楼主| 发表于 2012-5-5 09:15:32 | 显示全部楼层
xyr 发表于 2012-5-5 09:08
用位域定义过位 IRb IRa if(IRb&&!IRa)不行,
在这测试(PORTC^=_BV(PORTC1);)频率为1.24K符正常的。 ...

这样改应该可以了,试试:

if( (IRb!=0) && (IRa==0) )                   //是否下降沿(上次高,当前低)

出0入0汤圆

发表于 2012-5-5 09:20:16 | 显示全部楼层
不错啊,这么强!

出0入0汤圆

发表于 2012-5-6 11:28:36 | 显示全部楼层
不错不错!!!!!!!正在学习中

出0入0汤圆

发表于 2012-5-6 14:50:05 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2012-5-6 20:29:26 | 显示全部楼层
本帖最后由 TIANKUANG52 于 2012-5-6 20:34 编辑

其中cnt的时间是怎么算的,9ms的cnt是多久,怎么算的,X1到X4的值怎么算的
我不懂,教下,谢谢
void exint0() interrupt 0
{          
   uint cnt;
   uchar i;

   EX0 = 0;
   cnt = 0;       
       
   while(!IR) cnt++;                               //记录引导码时间
   if(cnt < 1000){EX0=1;return;}                   //9ms的计数值(12MHz:1000< cnt <1500)
          
   cnt = 0;                         
   while(IR) if(cnt++ > 400){EX0=1;return;}        //防卡死,超时保护(12MHz: > 300)   
   if(cnt < 200){EX0=1;return;}                    //(12MHz不分频: <260)            

   for(i=0; i<32; i++)                             //读取32位位码
       {
         cnt = 0;                                                                                                                                               
         while(!IR);                       
         while(IR) if(cnt++ > 200){EX0=1;return;}  //超时保护(12MHz:>=200)
         N[i/8] >>= 1;
         if(cnt>60) N[i/8] |= 0x80;                //0和1的计数界线(12MHz:< 109)   
       }

         if(N[0] == ~N[1] && N[2] == ~N[3])            //校验识别码,操作码       
           {
                   X1 = N[0]/16;
                X2 = N[0]%16;
                X3 = N[2]/16;
                X4 = N[2]%16;
           }

        EX0 = 1;                 
}

出0入0汤圆

发表于 2012-5-7 09:18:26 | 显示全部楼层
本帖最后由 xyr 于 2012-5-7 14:04 编辑
BXAK 发表于 2012-5-5 09:15
这样改应该可以了,试试:

if( (IRb!=0) && (IRa==0) )                   //是否下降沿(上次高,当前 ...


不是软件的问题,我由原来AVR Studio 4改为ICC编译就好了,具体AVR Studio 4为什么不行我还未查清,

谢谢!

出0入0汤圆

 楼主| 发表于 2012-5-7 11:38:37 | 显示全部楼层
本帖最后由 BXAK 于 2012-5-7 21:31 编辑
TIANKUANG52 发表于 2012-5-6 20:29
其中cnt的时间是怎么算的,9ms的cnt是多久,怎么算的,X1到X4的值怎么算的
我不懂,教下,谢谢
void exint0 ...


好像是以前写的,但此法解码区间占用掉CPU,所以实用性有限。
原版的已经没了,修改版倒的还在,也贴出来算了,至于9ms的cnt是多久,怎么算,这涉及汇编,如果你不懂汇编……

while(!IR)cnt++;  //查询低电平时间 【1T系列指令周期】【12T系列指令周期】
C:0x000F    JB           IR(0xB0.2),C:0019           4 t                 2T
C:0x0012    INC        R7                                  3 t                 1T
C:0x0013    CJNE      R7,#0x00,C:0017             4 t                 2T
C:0x0016    INC        R6                                  3 t                 1T
C:0x0017    SJMP     C:000F                             3 t                 2T

【STC 1T系列】
time*12t = 14t*cnt + 3t*(cnt/256)
time*12 = 14*cnt + 3*cnt/256 = (14 + 3/256)*cnt
cnt= (time*12)/(14 + 3/256)≈7708 (12MHz @ 9000us,time=9000)

【STC 12T系列】
time*1T = 7T*cnt + 1T*(cnt/256)
time = 7*cnt + cnt/256 = (7+ 1/256)*cnt
cnt= time/(7 + 1/256)≈1285 (12MHz @ 9000us,time=9000)

修改版的已经将计数值公式化,直接使用就行了
                                                            以下计算公式只适合STC 1T系列                                      以下计算公式适合STC 12T系列 以及 其它传统51指令速度的MCU
  1. /*┈┈┈┈┈┈ 红外线NEC解码函数 ┈┈┈┈┈┈┈
  2. 检测接收端高电平时,采用超时保护,防信号终断卡死。
  3. ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
  4. #define  ms10        8571   //ms10 = 10000*CPU工频/14000000         //ms10 = 10000*CPU工频/12000000/7
  5. #define  ms8        6857   //ms8  =  8000*CPU工频/14000000         //ms8  =  8000*CPU工频/12000000/7
  6. #define  ms5        3000   //ms5  =  5000*CPU工频/20000000         //ms5  =  5000*CPU工频/12000000/12
  7. #define  ms4        2400   //ms4  =  4000*CPU工频/20000000         //ms4  =  4000*CPU工频/12000000/12
  8. #define  ms2        1200   //ms2  =  2000*CPU工频/20000000         //ms2  =  2000*CPU工频/12000000/12
  9. #define  ms1        600    //ms1  =  1000*CPU工频/20000000         //ms1  =  1000*CPU工频/12000000/12
  10.                         //以上计算公式只适合STC 1T系列         //以上计算公式适合STC 12T系列 以及 其它传统51指令速度的MCU
  11. void IR_NEC(void)
  12. {
  13.    uint  cnt=0;
  14.    uchar i;                           

  15.    while(!IR)cnt++;                                 
  16.    if((cnt < ms8)||(cnt > ms10))return; //<8ms || >10ms,则返回

  17.    cnt = 0;                         
  18.    while(IR)if(++cnt > ms5)return;      //超时保护,>5ms,则返回
  19.    if(cnt < ms4)return;                 //<4ms,则返回

  20.    for(i=32;i;)                         //读取32编码
  21.    {
  22.       cnt = 0;                                                                                                                                               
  23.       while(!IR);                       
  24.       while(IR)if(++cnt > ms2)return;   //超时保护,>2ms,则返回
  25.       NEC[3] >>= 1;
  26.       if(cnt > ms1)NEC[3] |= 0x80;      //1ms,“0”与“1”
  27.           
  28.           if((--i)&&(i%8==0)){ NEC[0]=NEC[1]; NEC[1]=NEC[2]; NEC[2]=NEC[3]; }
  29.    }

  30.    if((NEC[0]==YHM_H)&&(NEC[1]==YHM_L)&&(NEC[2]==~NEC[3]))  //校验16位用户码,操作码正反码       
  31.    {  IR_BT = 1; }                                                //解码有效标志  
  32. }
复制代码

出0入4汤圆

发表于 2012-5-7 15:11:27 | 显示全部楼层
好东西啊  这下省事了

出0入0汤圆

发表于 2012-5-7 20:46:48 | 显示全部楼层
本帖最后由 TIANKUANG52 于 2012-5-7 21:47 编辑
BXAK 发表于 2012-5-7 11:38
好像是以前写的,但此法解码区间占用掉CPU,所以实用性有限。
原版的已经没了,修改版倒的还在,也贴出来 ...


我用的是stc89c52的单片机,能不能麻烦你帮我算下cnt的时间,晶振是12m的,不是一个指令是1us的吗?
那个9ms的cnt和4ms等一些时间的cnt怎么算,汇编我懂一些,谢了

我用的是stc89c52的用的是下面的公式吗?我上面的9ms的cnt就是1285左右也就是在1000到1500之间
那 if(cnt < 200){EX0=1;return;}                    //(12MHz不分频: <260) 是4.5ms的判断吗?
按公式4ms的cnt不是571左右吗怎么小于200是什么意思
【STC 12T系列】
time*1T = 7T*cnt + 1T*(cnt/256)
time = 7*cnt + cnt/256 = (7+ 1/256)*cnt
cnt= time/(7 + 1/256)≈1285 (12MHz @ 9000us,time=9000)

出0入0汤圆

 楼主| 发表于 2012-5-7 21:26:14 | 显示全部楼层
TIANKUANG52 发表于 2012-5-7 20:46
我用的是stc89c52的单片机,能不能麻烦你帮我算下cnt的时间,晶振是12m的,不是一个指令是1us的吗?
那个 ...

晕,回复够详细,看的确不认真,
不是已经列成公式帖出来了,直接套用公式计算就可以了

看看上面给你的回复:
……
//以上计算公式只适合STC 1T系列         //以上计算公式适合STC 12T系列 以及 其它传统51指令速度的MCU
……


出0入0汤圆

发表于 2012-5-8 14:12:12 | 显示全部楼层
BXAK 发表于 2012-5-7 21:26
晕,回复够详细,看的确不认真,
不是已经列成公式帖出来了,直接套用公式计算就可以了


我用的是stc89c52的用的是下面的公式。我上面的9ms的cnt就是1285左右也就是在1000到1500之间
那 if(cnt < 200){EX0=1;return;}                    //(12MHz不分频: <260) 是4.5ms的判断吗?
按公式4ms的cnt不是571左右吗怎么小于200是什么意思
while(IR) if(cnt++ > 400){EX0=1;return;}        //防卡死,超时保护(12MHz: > 300)   
这是怎么防卡死的
【STC 12T系列】
time*1T = 7T*cnt + 1T*(cnt/256)
time = 7*cnt + cnt/256 = (7+ 1/256)*cnt
cnt= time/(7 + 1/256)≈1285 (12MHz @ 9000us,time=9000)
谢了

出0入0汤圆

 楼主| 发表于 2012-5-8 16:20:21 | 显示全部楼层
本帖最后由 BXAK 于 2012-5-8 16:25 编辑
TIANKUANG52 发表于 2012-5-8 14:12
我用的是stc89c52的用的是下面的公式。我上面的9ms的cnt就是1285左右也就是在1000到1500之间
那 if(cnt < ...


原版是 while(IR) if(cnt++ > ……
修改版是 while(IR)if(++cnt > ……
“cnt++” “++cnt ”指令执行时间的计算方式是不同的

用修改版的吧,修改版的都有公式,
原版的没了,也懒得重新反汇编计算

另:
也不一定要反汇编计算那么麻烦,
你可以先不加限制,按一下遥控将每个时间段cnt计数值保存下来后发送串口显示,就知道当前晶振下9ms、4ms……各时间段的cnt计数值
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 09:37

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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