//=====================================================================//// 红外遥控器解码程序演示 //// 本程序主要将现在比较常用PC9012遥控器进行解码,将解码后的数据通过P2端////口的数码管显示出来,为了更好的看到运行过程,特加了三个指示灯用来指示当 ////前运行状态.P10主要用来闪亮,表示程序正在运行,P11则用来表示接收到数据, ////P12表示触发内部的定时器操作.P13的闪亮表示正确接收完一个数据. //// 程序运行效果: 打开本机电源开关,可以看到P10不停的闪动,按下遥控器的数////字键,数码管则显示相应的数字键(1-9).可以看到P11,P12在显示后呈亮状态.则////可以接收下一个数据,在上面过程中可以看到P13闪亮了一下.表明上次正确接收////到数据. ////---------------------------------------------------------------------//// 开发日期: 2009/01/27 编写红外遥控器解码程序演示的最初代码 //// 修改日期: //// 程序作者: guojun 邮箱:Guojun2008a@126.com //// 程序备注: 此程序仅为表现本机功能而演示用,当用作实际工程时请慎用. ////=====================================================================//#include <AT89x51.h> //包含51单片机相关的头文件
unsigned char code LedShowData[]= //定义数码管显示数据 {0x9F,0x25,0x0D,0x99,0x49, //1,2,3,4,5, 0x41,0x1F,0x01,0x19,0x03}; //6,7,8,9,0,static unsigned char RecvData; //定义接收红外数据变量static unsigned char CountData; //定义红外个数计数变量static unsigned int AddData; //定义自增变量static unsigned int LedFlash; //定义闪动频率计数变量#define uint unsigned int //重定义无符号整数类型#define uchar unsigned char //重定义无符号字符类型
unsigned char LeadCode; //定义红外脉冲引导码标志unsigned char ReceiveBit; //定义接收位记数器unsigned char DataBuffer[4]; //定义接收数据缓存变量unsigned char RecvSuccess=0; //定义接收数据成功标志位uchar temp;sbit M1A=P0^0; //定义电机1正向端口sbit M1B=P0^1; //定义电机1反向端口sbit M2A=P0^2; //定义电机2正向端口sbit M2B=P0^3; sbit led=P1^6;sbit LeftLed=P2^0; //定义前方左侧指示灯端口sbit RightLed=P0^7; //定义电机2反向端口sbit RunLed=P1^0; //定义运行指示灯变量位sbit RecvLed=P1^1; //定义接收指示灯变量位sbit InTimeLed=P1^2; //定义定时器开始指示灯变量位sbit ReadyLed=P1^3; //定义就绪指示灯变量sbit IR1=P3^3; //定义红外接收端口#define ShowPort P2 //定义数码管显示端口void Delay() //定义延时子程序{ uint DelayTime=30000; //定义延时时间变量 while(DelayTime--); //开始进行延时循环 //子程序返回}void ControlCar(uchar CarType) //定义小车控制子程序{ M1A=0; //将电机1正向电平置低 M1B=0; //将电机1反向电平置低 M2A=0; //将电机2正向电平置低 M2B=0; //将电机2反向电平置低 LeftLed=1; //关闭前方左侧指示灯 RightLed=1; //关闭前方右侧指示灯 //将此状态延时一段时间 switch(CarType) //判断小车控制指令类型 { case 1: //前进 //判断是否是前进 { M1A=1; //将电机1正向端口置高 M2A=1; //将电机2正向端口置高 break; //退出判断 } case 2: //后退 //判断是否是后退 { M1B=1; //将电机1反向端口置高 M2B=1; //将电机2反向端口置高 break; //退出判断 } case 3: //左转 //判断是否是左转 { M1B=1; //将电机1反向端口置高 M2A=1; //将电机2正向端口置高 break; //退出判断 } case 4: //右转 //判断是否是右转 { M1A=1; //将电机1正向端口置高 M2B=1; //将电机2反向端口置高 break; //退出判断 } default: //默认情况下的判断 { break; //直接退出判断 } } }
void Timer0_IR1() interrupt 1 using 3 //定义红外定时器子程序{ TH0=0xFF; //向定时器定时间寄存器填入高八位值 TL0=0x49; //向定时器定时间寄存器填入低八位值 InTimeLed=!InTimeLed; //将定时器指示灯进行取反 AddData++; //自增变量加1 if(AddData>400) { ReceiveBit =0; //红外接收记数器清零 AddData =0; //计数器清零 LeadCode =0; //引导码记录器请零 TR0 =0; //关定时器0 ET0 =0; //关闭定时器0中断 }}
此帖出自
小平头技术问答
{
if(LeadCode ==0) //第一次处理红外脉冲引导码
{
if( (AddData > 35) && (AddData < 50) )
{ //判断红外计数器是否已到达最大值
LeadCode =0xff; //引导码记录器标志位定义
AddData =0; //计数器清零
return; //接收引导码成功
}
else //正常接收情况下开启定时器开时计数
{
TR0=1; //开启定时器0
ET0=1; //开定时器0
return; //接收引导码失败
}
}
else //在正常接收情况
{
RecvData >>=1; //接收到的数据右移1位
if((AddData > 3)&&(AddData < 7)) //判断计数时间
{
RecvData &= 0x7f; //对数据0置数
}
else //判断数据计数时间
{
if(AddData < 15) //对数据1置数
{
RecvData |= 0x80; //对数据1置数
}
}
ReceiveBit++; //数据位计数器加1
AddData =0; //时间计数清零
}
switch(ReceiveBit) //根据位计数器进行判断
{
case 8: //8位时用户编码
{
DataBuffer[0] = RecvData; //将用户编码放入数据缓存0
break;
}
case 16: //16位时用户编码
{
DataBuffer[1] = RecvData; //将用户编码放入数据缓存1
break;
}
case 24: //24位时按键编码
{
DataBuffer[2] = RecvData; //将按键编码放入数据缓存2
break;
}
case 32: { //32位时按键编码反码
DataBuffer[3] = RecvData; //将按键编码放入数据缓存3
ReceiveBit =0; //清零位标志计数器
AddData =0; //时间记录器清零
LeadCode =0; //引导标志位清零
RecvSuccess=0xff; //成功标志位置位
TR0 =0; //关定时器0
ET0 =0; //关闭定时器0
break;
}
default: break;
}
if(RecvSuccess==0xff) //判断接收数据成功标志位
{
RecvSuccess=0x00; //成功标志位清零
if(DataBuffer[0]!=DataBuffer[1]) //判断用户码是否相同
{return;}
if(DataBuffer[2]!=~DataBuffer[3]) //判断按键码是否正确
{return;}
P2=LedShowData[DataBuffer[2]]; //P2端口开始显示数据
//ControlCar(1);
led=!led;
DataBuffer[0]=0; //清零数据缓存0
DataBuffer[1]=0; //清零数据缓存0
DataBuffer[2]=0; //清零数据缓存0
DataBuffer[3]=0; //清零数据缓存0
}
}
void main() //主程序入口
{
bit ExeFlag=0; //定义可执行位变量
RecvData=0; //将接收变量数值初始化
CountData=0; //将计数器变量数值初始化
AddData=0; //将定时器计数器初始化
LedFlash=3000; //对闪灯数据进行初始化
ReceiveBit =0; //红外接收记数器清零
AddData =0; //计数器清零
LeadCode =0; //引导码记录器请零
RecvSuccess=0x00;
TMOD=0x01; //选择定时器0为两个16位定时器
TH0=0xFF; //对定时器进行计数值进行初始化
TL0=0x49; //同上,时间大约为25uS
TR0=1; //同意开始定时器0
EX1=1; //同意开启外部中断1
IT1=1; //设定外部中断1为低边缘触发类型
EA=1; //总中断开启
while(1) //程序主循环
{
while(LedFlash--) //闪灯总延时
{
if(IR1==0) //判断延时期间是否有红外信号输入
{ExeFlag=1; //将可执行标志位置1
}
}
RunLed=!RunLed; //运行指示灯取反
LedFlash=3000; //运行闪动时间重设定
if(ExeFlag==0) //判断可执行标志位
{
EX1=1; //开启外部中断1
}
ExeFlag=0; //可执行标志位置0
}
}
在外部中断中,只要在这个地方
P2=LedShowData[DataBuffer[2]]; //P2端口开始显示数据
//ControlCar(1);
led=!led;
DataBuffer[0]=0; //清零数据缓存0
DataBuffer[1]=0; //清零数据缓存0
DataBuffer[2]=0; //清零数据缓存0
DataBuffer[3]=0; //清零数据缓存0
不加ControlCar(1);程序就能正常运行,加了ControlCar(1); 程序进一次中断就不会再进第二次,请问这是什么问题呢?
一周热门 更多>