#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit ir=P3^2;            //红外接收头输出引脚位定义
uchar irtime;
uchar irdata[33]; 
uchar bitnum;
uchar startflag;
uchar irok;
uchar ircode[4];
uchar irprosok;
uchar disnum[8];
sbit dula=P2^6;  
sbit wela=P2^7;
uchar code table_du[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};  //数码管段选编码
uchar code table_we[]={0xfe,0xfd,0xff,0xff,0xef,0xdf};  //位选编码

void timer0init(void)  //定时器0工作方式2初始化，间隔0.256ms中断一次
{
	TMOD=0x02;  //定时器0工作方式2
 	TH0=0x00;    //自动重装初值
 	TL0=0x00;    //装初值
	ET0=1;       //开中断
	EA=1;
	TR0=1;
}

void irpros(void)  //红外码值处理函数，对外部中断0服务函数存放在数组irdata中的33个时
                   //间值进行处理，把它转换成相应的客户码1、客户码2、操作码、操作反码
{
	uchar mun,k,i,j;
	k=1;  //由于irdata数组中的第一个元素是引导码，那么我们是要从第二个元素开始提取
	for(j=0;j<4;j++) //进行4次循环，因为有4组编码：客户码1、客户码2、操作码、操作反码
	{
		for(i=0;i<8;i++)  //进行8次循环，因为每组编码均有8位
		{
			mun=mun>>1;  //对数据进行位右移，因为遥控器发送数据时低位在前、高位在后
			if(irdata[k]>6)  //如果第K中的元素满足条件，大于6说明该元素对应的码值是1
			{
				mun=mun | 0x80;  //num与0x80进行按位或运算，把最高位置1
			}
				k++;
		}
		ircode[j]=mun;  //提取出来的num值放在数组ircode中保存起来。
	}
	irprosok=1;  //设置一个标记志irprosok，表示红外处理已经结束了，方便主函数判断
}

void irwork(void)  //红外码值转换函数，把数组ircode中的4个16进制数值（即：客户码1、
                   //客户码2、操作码、操作码的反码）进行拆解开，方便在显示函数进行显示
{
	disnum[0]=ircode[0]/16;   //数组ircode第0个元素对16求模，并存放在数组disnum[0]中
	disnum[1]=ircode[0]%16;  //数组ircode第0个元素对16求余，并存放在数组disnum[1]中
	disnum[2]=ircode[1]/16;
	disnum[3]=ircode[1]%16;
	disnum[4]=ircode[2]/16;
	disnum[5]=ircode[2]%16;
	disnum[6]=ircode[3]/16;
	disnum[7]=ircode[3]%16;
}

delay(uchar x)   //延时
{
	uchar a,b;
	for(a=x;a>0;a--)
		for(b=200;b>0;b--);
}

display()   //数码管显示函数
{
	uchar i;
	for(i=0;i<6;i++)
	{
		P0=0xff;
		wela=1;
		wela=0;
		P0=table_du[disnum[i]];
		dula=1;
		dula=0;
		P0=table_we[i];
		wela=1;
		wela=0;
		delay(10);
	}
}

void int0init(void)  //外部中断0初始化，设置成下降沿触发
{
 IT0=1;
 EX0=1;
 EA=1;
}

void main()   //主函数
{
	timer0init();   //定时器0初始化，并始动
	int0init();    //外部中断0初始化，设置成下降沿触发
	while(1)
	{
		if(irok==1)  //判断外部中断0服务函数是否已完成一帧数据的接收
		{
			irpros();  //红外码值处理
			irok=0;   
		}
		if(irprosok==1)  //判断红外码值处理函数是否已完成一帧数据的处理
		{
			irwork();   //红外码值转换
			irprosok=0;
		}
		 display();  //在数码管上显示
	}	
}

void int0 () interrupt 0  //外部中断0服务函数，把收到的每一帧数据中的33个码值进行时间记录
{
    if(startflag)  //设置标记位startflag，当其等于1时，再进行判断
    {
  	 if(irtime>32&&irtime<63)  //在8~16ms之间，我们认为收到的是引导码
         {
	    bitnum=0; //设置标记位bitnum，用来表示是数组irdata的第几个元素
	 }
	 irdata[bitnum]=irtime;   //现在装的是第一个元素，引导码对应的时间值
         irtime=0;   //装完了之后，要把irtime清零，我们下一个数据，还要用到它
         bitnum++;  
         if(bitnum==33) //一帧的数据共有33位（即引导码，客户码1、2，操作码、操作码反码）
         {
	    bitnum=0;  //33位接收完后，bitmum清零
	    irok=1; //设置标记志位irok，表示一帧的数据接收完成，方便主函数判断
         }
     }
     else  //刚开始startflag没有赋值，默认为0，因此本中断服务函数从else语句开始运行
    {
       irtime=0;    //首先把irtime这个时间变量清0，以便于进行时间计算。
       startflag=1;  //然后再把startflag置1
     }
}

void timer0 () interrupt 1  //定时器0服务函数
{
	irtime++;  //定时器0中断一次，irtime自身加1，用于计算时间
}