实验目的:利用计数器0和外部中断0进行红外解码,将20键红外遥控器键码显示在两位数码管上
遇到问题:将hex文件下载到单片机按下按键数码管显示键码与遥控器键码不一致。例如按下按键“+”,数码管显示41,但是正确键码为40;又如按下遥控器播放按钮,数码管显示1C,标准键码为15.
请论坛的各位前辈、大佬帮我看看是哪里出错误了,谢谢!
我的单片机程序代码如下:
#include <REGX52.H>
sbit IR_INPUT=P3^2; //红外接收引脚
unsigned char ircode[4]; //红外代码接收缓冲区
unsigned char NixeTable[]= //共阴数码管键码
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/*软件生成的延时函数,延时xms*/
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
/*数码管显示函数,用两位数码管显示红外控制码*/
void Nixie(unsigned char Location,Number)
{
switch(Location) //位选
{
case 1:
P2_4=1;P2_3=1;P2_2=1;break;
case 2:
P2_4=1;P2_3=1;P2_2=0;break;
}
P0=NixeTable[Number]; //段选
Delay(1); //这里没有延时数码管会很暗
P0=0x00; //消隐
}
/*计数器0初始化函数*/
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0; //设置定时初值
TH0 = 0; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0不计时
}
/*外部中断0初始化函数*/
void Int0_Init(void)
{
IT0=1; //设置INT0下降沿触发
IE0=0; //清空外部中断0中断请求标志位
EX0=1; //打开外部中断0
EA=1; //打开总中断开关
PX0=1; //设置外部中断优先级
}
/*获取高电平时间*/
unsigned int GetHighTime()
{
TH0=0; //清零T0计数器初值
TL0=0;
TR0=1; //启动T0计数
while(IR_INPUT) //红外输入引脚为1时循环检测等待,遇到下降沿时结束循环
{
if(TH0>=0x40) {break;} //当T0计数值大于18ms强制退出,避免程序死在这里
}
TR0=0; //停止计数
return(TH0*256+TL0); //计数值合成16位整形数
}
/*获取低电平时间*/
unsigned int GetLowTime()
{
TH0=0;
TL0=0;
TR0=1;
while(!IR_INPUT)
{
if(TH0>=0x40) {break;}
}
TR0=0;
return(TH0*256+TL0);
}
/*主函数*/
void main()
{
Timer0_Init();
Int0_Init();
while(1)
{
Nixie(1,ircode[2]>>4);
Nixie(2,ircode[2]&0x0F);
}
}
/*外部中断服务子函数,执行红外接收和解码*/
void Int0_Routine() interrupt 0
{
unsigned char i,j;
unsigned char byt;
unsigned int time;
//接收并判定引导码的9ms低电平
time=GetLowTime();
if((time<7833)||(time>8755)) //时间判定范围为8.5ms~9.5ms,超出范围则为误码
{
IE0=0; //退出前清零INT0中断标志
return;
}
//接收并判定引导码的4.5ms低电平
time=GetHighTime();
if((time<3686)||(time>4608)) //时间判定范围为4.0ms~5.0ms,超出范围则为误码
{
IE0=0; //退出前清零INT0中断标志
return;
}
//接收并判定后续的4字节数据
for(i=0;i<4;i++) //循环接收4个字节
{
for(j=0;j<8;j++) //循环接收判定每个字节的八位
{
time=GetLowTime();
if((time<313)||(time>718)) //时间判定范围为340us~780us,超出范围则为误码
{
IE0=0;
return;
}
time=GetHighTime();
if((time>313)&&(time<718)) //时间判定范围为340us~780us,在此范围内说明该位为0
{
byt>>=1; //低位在先,数据右移,高位置零
}
else if((time>1345)&&(time<1751)) //时间判定范围为1460us~1900us,在此范围内说明该位为1
{
byt>>1; //低位在先,数据右移
byt|=0x80; //高位置1
}
else
{
IE0=0;
return;
}
}
ircode[i]=byt; //接收完一个字节后保存到数组
}
IE0=0; //清零INT0标志
}