单片机型号:AT89S52

红外接收模块:HX1838

红外编码模块:HT6222

程序作者:szy0syz

本程序将HT62222发送的波形用HX13838接收,再使用单片机软解码并将结果显示在8个数码段上。
显示内容包括:用户编码8bit*2,按键编码bit*2

算法:通过延迟检测宽窄正脉冲,直接跳过负脉冲,和网上流传那个即卡上升沿又卡下降沿的算法精简了许多。
关于如何设置延迟请用示波器检测波形。

程序代码如下:

////////////////////////////////////////////
//程序名:HT62222红外发送,51单片机软解码
//作者:szy0syz
//时间:2010.7.18
/////////////////////////////////////////////
////////////////////////////////////////////
//定义数组ir_rec[],分别装解码后得到的数据
//ir_rec[0]~ir_rec[7]     低8位地址码
//ir_rec[8]~ir_rec[16]    高8位地址码
//ir_rec[17]~ir_rec[24]   8位数据码
//ir_rec[24]~ir_rec[31]   8位数据码的反码
/////////////////////////////////////////////
#include
sbit IRIN = P3^2;         //红外接收器数据线
#define uchar unsigned char
#define uint unsigned int

unsigned char const dofly[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//段码值01234567
unsigned char code  seg[]={0,1,2,3,4,5,6,7};//分别对应相应的数码管点亮,即位码

unsigned int ir_rec[32]={0};

/*--------------------------------------------------------------------
子程序名称:50us 延时
--------------------------------------------------------------------*/
void delay_50us(uint t)
{
	uchar j;
	for(;t>0;t--)
		for(j=19;j>0;j--)
			;
}

void delay(unsigned int cnt)
{
 while(--cnt);
}

///////////////
//初始化
////////////
void IR_init(void)
{
   EA=1;
   EX0=1;              //允许总中断中断,使能 INT0 外部中断
   IT0=1;              //触发方式为脉冲负边沿触发
   //IRIN=1;           //I/O口初始化
}

//////////
//解码过程
//////////////
void IR_CODE(void) interrupt 0   //在外部中断子程序中解码
{

    uchar j,k,n=0;
    EX0 = 0;            //关闭外部中断1
	delay_50us(273);    //延时273*0.05=13.65ms>9+4.5 ,直接跳过两个前导码
	//注意:这里的值最好接近13.5,否则会对地址码检测产生严重的干扰
	//否则检测成功率只有50%左右
	if(IRIN==1)         //检测是否是干扰
    {                   //确认IR信号出现
			EX0 =1;     //是干扰就重新开启INT0中断
			return;
    }
    //while(!IRIN) ;    //等IRIN变为高电平,开始解码
    for (j=0;j<4;j++)   //收集4组数据
    {
            for (k=0;k<8;k++)  //每组数据有8位
            {
					while(!IRIN) delay_50us(1);  //等待高电平
					delay_50us(16); //延时0.8ms,减少误差尽量跳到边缘即可
					if(IRIN==1)
					{
						ir_rec[n]=1;
						delay_50us(20);          //延时1ms
					}
					else ir_rec[n]=0;
                    n++;
            }
    }
    EX0=1;
}

void main(void)
{
    int i;
	IR_init( );                    //初始化外部中断0
	for(i=0;i<32;i++) ir_rec[i]=0; //初始化接受数组
	i=0;
    while(1)
    {
		 P0=dofly[ir_rec[i+16]];  //取显示数据,段码
		 P2=seg[i];               //取位码
		 delay(100);              //扫描间隙延时,时间太长会闪烁
		 i++;         //太短会造成重影,这里使用长时间方便了解显示原理
		 if(i>=8) i=0;            //检测8位扫描完全?
    }
}