红外接收过程程序详解

本文围绕红外NEC协议程序展开,强调参看程序前需先了解红外NEC协议,介绍了NEC协议代码调制、逻辑0和1的电平时间特性,指出收发二进制数据段反向。还说明了中断触发和定时器计时原理,最后对两个重点程序段进行了详细解读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先理解以下知识点:

1.参看程序前,先参阅博文红外NEC协议,否则程序不好理解

2.NEC协议重点查看,代码调制过程,以及逻辑“0”,逻辑“1”的高低电平时间特性

3.另外需要注意的是发送的二进制数据段与接收的二进制数据段是反向的,什么意思呢,比如发送数据1001 0001,数据与38KHZ载波发送到接收端时,接收过程是1->0->0->0->1->0->0->1,所以程序段会将数据8位不断右移(>=)。

4.中断的产生是在低电平时触发,接收信号过程是,比如逻辑0与逻辑1,在0.56ms的高电平结束时,触发中断,定时器清零计时,在下次低电平时再次触发中断,记录时间,定时器则清零记录时间到下一个中断再记录并清零,也就是两个下降沿之间的时间。

5.在课件的基础上,我已经将几乎所有知识点注释清楚了,另外附录2个重点程序段的详解,稍微用点心看,应该都能理解,

附程序代码如下:

/*-----------------------------------------------
  名称:遥控器红外解码数码管显示
  内容:按配套遥控器上1-9会在数码管上对应显示
------------------------------------------------*/
#include<reg52.h>    //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义

sbit IR=P3^2;  //红外接口标志

#define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换
sbit wei1 = P2^4;   //定义第一位数码管
sbit wei2 = P2^5;   //定义第二位数码管
sbit wei3 = P2^6;   //定义第三位数码管
sbit wei4 = P2^7;   //定义第四位数码管
/*------------------------------------------------
                全局变量声明
------------------------------------------------*/

unsigned char code DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
							   0x07,0x7f,0x6f};// 显示段码值0~9,共阴极。
unsigned char  irtime;//红外用全局变量

bit irpro_ok,irok;
unsigned char IRcord[4];
unsigned char irdata[33];

/*------------------------------------------------
                  函数声明
------------------------------------------------*/

void Ir_work(void);
void Ircordpro(void);

/*------------------------------------------------
                  定时器0中断处理
------------------------------------------------*/

void tim0_isr (void) interrupt 1 using 1
{
  irtime++;  //用于计数2个下降沿之间的时间
}

/*------------------------------------------------
                  外部中断0中断处理
------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中断0服务函数,程序段不清楚见详解1
{
	static unsigned char  i;             //接收红外信号处理
	static bit startflag;                //是否开始处理标志位

	if(startflag)                         
	{
		if(irtime<63&&irtime>=33) //引导码 TC9012的头码,9ms+4.5ms(计数=定时*11.0592/12)计数=256,八位重装定时器
	    	i=0;			      //关于计算见博客定时器的定时时间计算,i=0,是保证接收到的是引导码即>=33,<63
		irdata[i]=irtime;         //存储每个电平的持续时间,用于以后判断是0还是1
		irtime=0;				  //每次重新计时,等待下一个中断计时,当一个逻辑0,逻辑1的下降沿产生一次中断,记录时间
		i++;					  //irdata[0]记录的是引导码
		if(i==33)
		{
		 irok=1;
		 i=0;
		}
	}
	else
	{
		irtime=0;
		startflag=1;
	}

}

/*------------------------------------------------
                定时器0初始化
------------------------------------------------*/
void TIM0init(void)//定时器0初始化
{

  TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
  TH0=0x00; //重载值
  TL0=0x00; //初始化值
  ET0=1;    //开中断
  TR0=1;    
}
/*------------------------------------------------
                  外部中断0初始化
------------------------------------------------*/
void EX0init(void)
{
 IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
 EX0 = 1;   //使能外部中断
 EA = 1;    //开总中断
}
/*------------------------------------------------
                  键值处理
------------------------------------------------*/

void Ir_work(void)//红外键值散转程序
{
       switch(IRcord[2])//判断第三个数码值
	         {
			 case 0x0c:DataPort=DuanMa[1];break;//1 显示相应的按键值
			 case 0x18:DataPort=DuanMa[2];break;//2
			 case 0x5e:DataPort=DuanMa[3];break;//3
			 case 0x08:DataPort=DuanMa[4];break;//4
			 case 0x1c:DataPort=DuanMa[5];break;//5
			 case 0x5a:DataPort=DuanMa[6];break;//6
			 case 0x42:DataPort=DuanMa[7];break;//7
			 case 0x52:DataPort=DuanMa[8];break;//8
			 case 0x4a:DataPort=DuanMa[9];break;//9
             default:break;
			 }

		  irpro_ok=0;//处理完成标志

  }
/*------------------------------------------------
                红外码值处理
------------------------------------------------*/
void Ircordpro(void)     //红外码值处理函数,处理32位的数据,这个程序段见详解2
{ 
  unsigned char i, j, k;
  unsigned char cord,value;

  k=1;				    //irdata[0]是引导码,不用考虑,故从irdata[1]开始解码
  for(i=0;i<4;i++)      //处理4个字节
     {
      for(j=1;j<=8;j++) //处理1个字节8位
         {
          cord=irdata[k];
          if(cord>7)    //大于某值为1,这个和晶振有绝对关系,这里使用12M计算,此值可以有一定误差
             value|=0x80;
          if(j<8)		 //处理八位数据首先处理的数据在低位,最后一位在高位
		    {
			 value>>=1;
			}
           k++;
         }
     IRcord[i]=value;
     value=0;     
     } 
	 irpro_ok=1;//处理完毕标志位置1
}

/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main(void)
{
  EX0init(); //初始化外部中断
  TIM0init();//初始化定时器

  wei1 = 1; //第一位数码管选通
  wei2 = 1; //第二位数码管选通
  wei3 = 1; //第三位数码管选通
  wei4 = 1;	//第四位数码管选通

 while(1)//主循环
   {
    if(irok)                        //32位数据接收完以后irok=1,在INT0中断函数内
	  {   
	   Ircordpro();
 	   irok=0;
	  }

    if(irpro_ok)                   //如果处理好后进行工作处理,如按对应的按键后显示对应的数字等
	  {
	   Ir_work();
  	  }
   }
}
  
  

详解1:void EX0_ISR (void) interrupt 0

理解这个程序段之前,先理解定时器T0,T0是8位自动重装的定时器,定时周期的计算为:计数=时间*11.0592/12,计数=256,因为是8位,不清楚见博文定时器的计算,得出T0计时器的irtime每0.2777ms进行+1;

数据传输过来起先是引导码,irdata[33],记录33位数据,其中irdata[0],存储的是引导码,解码是从irdata[1]开始的。

重点理解:中断的产生与定时器的计时时间,中断是下降沿后产生,此时计时器清零,并开始记录时间,知道下一次的下降沿,再次触发中断,定时器时间被记录下后,清零,再次计数。

 

 

详解2:void Ircordpro(void) 

 cord=irdata[k],irdata记录1个引导码+32位数据,

value期初值=0;0x80为二进制的1000 0000,cord>7   

crod=7*0.2777(计数(256)=定时*11.0592/12)=1.94ms

irdata中记录的t0时间分为两个时间,逻辑1与逻辑0高电平都是0.56ms,低电平一个为0.565ms,另一个1.69ms:

0.56+0.565=1.125ms

0.56+1.69=2.25ms

如果记录的时间>1.94ms则为逻辑“1”,否则为“0”

 所以当为逻辑“1”时,与0x80与位,然后右移,如果为0,继续右移,直到移动8次,得出8位的数据结果。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值