52单片机做的红外学习遥控器学了按键可以发射.docx
- 文档编号:7513044
- 上传时间:2023-01-24
- 格式:DOCX
- 页数:18
- 大小:59.37KB
52单片机做的红外学习遥控器学了按键可以发射.docx
《52单片机做的红外学习遥控器学了按键可以发射.docx》由会员分享,可在线阅读,更多相关《52单片机做的红外学习遥控器学了按键可以发射.docx(18页珍藏版)》请在冰豆网上搜索。
52单片机做的红外学习遥控器学了按键可以发射
//中断函数注意养成指定寄存器组的习惯
//不同优先级的中断程序绝对不能使用同一组寄存器
/*****编程时防止中断把寄存器中的数据改变的解决方法是给中断指定寄存器,
同优先级的使用同一组没事。
1、写中断程序一定要用using语句指定寄存器组。
第1、2、3组都可以,不能是0.
2、51单片机的中断有两个优先级。
一个中断不会打断另一个相同优先级的中断。
这样相同级别中断可以使用同一个组。
比如:
低优先级的中断函数都
用using1,高优先级的中断都用using2。
这样不会冲突。
下面是一个正常的例子:
C程序:
voidint0()interrupt0using1
默认5个中断时同级的,不会冲突,但是最好养成好习惯
不指定中断要使用的寄存器,每次都要入栈保护数据,中断完还要出栈,代码会增加32字节
完整代码下载:
********************************************************************/
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
//少占鱼制作河北正定欢迎您长沙航空职业技术学院2010年QQ:
41165643
//
//定义Flash操作等待时间及允许IAP/ISP/EEPROM操作的常数
//#defineENABLE_ISP0x80//系统工作时钟<30MHz时,对ISP_CONTR寄存器设置此值
//#defineENABLE_ISP0x81//系统工作时钟<24MHz时,对ISP_CONTR寄存器设置此值
#defineENABLE_ISP0x82//系统工作时钟<20MHz时,对ISP_CONTR寄存器设置此值
//#defineENABLE_ISP0x83//系统工作时钟<12MHz时,对ISP_CONTR寄存器设置此值
//#defineENABLE_ISP0x84//系统工作时钟<6MHz时,对ISP_CONTR寄存器设置此值
//#defineENABLE_ISP0x85//系统工作时钟<3MHz时,对ISP_CONTR寄存器设置此值
//#defineENABLE_ISP0x86//系统工作时钟<2MHz时,对ISP_CONTR寄存器设置此值
//#defineENABLE_ISP0x87//系统工作时钟<1MHz时,对ISP_CONTR寄存器设置此值
unionunion_temp16
{
uintun_temp16;
ucharun_temp8[2];
}my_unTemp16;
ucharByte_Read(uintadd);//读一字节,调用前需打开IAP功能
voidByte_Program(uintadd,ucharch);//字节编程,调用前需打开IAP功能
voidSector_Erase(uintadd);//擦除扇区
voidIAP_Disable();//关闭IAP功能
sbitJIESHOU=P1^0;//接收指示灯
sbitFASHE=P1^1;//发射指示灯
sbitKEY=P3^5;
sbitcin=P3^2;//接收端
sbitcontrl=P3^0;//发射控制端
sbitkhz=P3^1;//38KHZ产生,由T1设置
/****************************************************************/
voiddelayms(uint);
voidADC();
voidInitADC();
voidinit1();
voidinit2();
voidfashe();
voidjieshou();
voiddelayus(uchari);
voidled(ucharx);
/******************************************************/
uintvoltage;
bitreceive=0;//接收标志
bitflag=0;//低电平记录完成标志
bitend=0;
bitfinish=1;
uchara[43]={121,1,3,4,44,55,24,156,35};//间接寻址的高128RAM,内部256RAM高128只能间接寻址
ucharj=0;
uintzu=0,addr=0;//扇区地址
uchark;//按键代号
ucharm=0;//写EEPROM时用来移动数组的
ucharb[6];//用来存储每一组数据的总字节数
/**********************************************************************/
/****************************************************************/
voidmain()
{
delayus(5);
delayms(1000);
InitADC();//这里对其他用到P1口的地方有影响,尽量放前面
contrl=0;//关闭38K输出
KEY=1;
Sector_Erase(0x0000);//擦除扇区1
Sector_Erase(0x200);
Sector_Erase(0x400);
Sector_Erase(0x600);
Sector_Erase(0x800);
Sector_Erase(0xa00);
Sector_Erase(0xc00);//擦除扇区7
addr=0xc00;
FASHE=0;
JIESHOU=0;
FASHE=1;
delayms(4900);
for(j=6;j>0;j--)//j是数据总长度,如此判断,不会存储多余的空位
{Byte_Program(addr,a
?
?
);//从本组数据对应扇区首地址开始写EEPROM
m++;//数组下移
addr++;//地址下移
delayms
(1);}//forend
m=Byte_Read(0xc00);
if(m==121)
{
JIESHOU=1;
delayms(6000);
}
m=0;//下面还要用,所以清0
addr=0;
zu=0;
FASHE=0;
KEY=1;
JIESHOU=0;
delayms(1000);
Sector_Erase(0x0000);//擦除扇区1
Sector_Erase(0x200);
Sector_Erase(0x400);
Sector_Erase(0x600);
Sector_Erase(0x800);
Sector_Erase(0xa00);
Sector_Erase(0xc00);//擦除扇区7
EX1=1;//开外部中断1
IT1=1;//外部中断1边沿触发,不然按住的时候一直中断
EA=1;
delayms
(1);
//等待按键时两个灯灭
while
(1)
{
if(receive)//外部按键中断1,正式进入接收函数
{
FASHE=0;//发射指示灯
JIESHOU=1;//接收指示灯
delayms(3000);
JIESHOU=0;
delayms
(2);
FASHE=1;
delayms(3000);
FASHE=0;
jieshou();//接收函数是T0定时开始后计数满溢出跳出的
}
if(!
KEY)//KEY为0时进入发射模式
{
JIESHOU=0;
delayms(200);
FASHE=1;
delayms(200);
KEY=1;
fashe();
}
}
}
/********************************************************************/
//接收函数初始化
voidinit1()//接收初始化
{
finish=1;
EA=0;//因为下面要写EEPROM,必须关闭EA
TMOD=0x01;//T0方式1
TH0=0x00;
TL0=0x00;
TR0=0;
EX0=1;
EX1=0;//关闭外部中断1按键,一旦进入接收函数,就关闭按键防止干扰
ET0=1;//开T0中断
IT0=1;//外部中断边沿触发
EA=0;
}
//
/********************************************************************/
//发射函数初始化
voidinit2()//发射初始化
{
contrl=0;//关闭发射端,由于它与38K输出端并联,所以拉低不输出
TMOD=0x21;//T0方式1,外部INTO唤醒,T1方式2
TH1=-(13/256);//定时13us翻转一次,即38KHZ(26us)
TL1=-(13%256);
ET1=1;//T1中断
TR1=1;
EA=1;
}
/************************************************************************/
//红外接收子程序
voidjieshou()
{
init1();//接收初始化
delayms(3000);
flag=0;
finish=1;
JIESHOU=1;//接收灯亮才可以开始按遥控
EA=1;//开中断
EX0=1;
//接收灯亮等待接收
while(finish)//退出接收循环检测
{
while(flag)//T0已启动标志,用完记得清0,由外部中断0启动,初次启动检测
{//第一次低电平测宽已经开始
while(!
cin);//等待高电平到来,T0中断不会在这里发生,因为低电平宽度不会有65MS这么长
{
TR0=0;
a[j]=TH0;//低电平宽度先存高8位数据
j++;
a[j]=TL0;//存储的是低电平宽度
j++;//数组下移
TH0=0;//重装T0
TL0=9;//补偿前面消耗的时间
TR0=1;//重新启动T0,计时高电平
}
//高电平测宽开始
while(cin&&flag);//等待cin低电平到来。
T0中断就是在这里等待的时候发生的,因为最后一个电平必然是高电平(无信号就是高)
//flag=1表示T0还没中断,还是接收有效
if(flag)//flag为1才表示计时有效,flag=0表示最后高电平很长结束了
{//加个flag才能退出这个等待
TR0=0;
a[j]=TH0;//先存高8位数据
j++;
a[j]=TL0;//存储的是低电平段
j++;//数组下移
TH0=0;//重装T0
TL0=0;
TR0=1;//重新启动T0,计时低电平
}
}
//判断是否退出接收
if(end)
{
receive=0;//用完接收启动标志要清0
flag=0;
FASHE=1;
delayms(122);
JIESHOU=1;//亮两个灯表示接收成功
j=0;
finish=0;
end=0;
}
}
//接收完亮两个灯
finish=1;
EX1=1;//开外部按键中断1
EA=1;
}
/***********************************************/
//红外发射子程序
voidfashe()//发射程序里没有安排推出操作,所以只有重启才能重新进入选择模式
{
while
(1)
{
ADC();
switch(k)
{
case1:
for(j=0 case2: for(j=0 case3: for(j=0 case4: for(j=0 case5: for(j=0 case6: for(j=0 default: k=0;break; } init2();//必须先读EEPROM再开定时器中断,不然会无法读EEPROM } } // /**********************************************************************/ voidled(ucharx) { j=0; x=x/2;//2个数组是一段电平,而且肯定是偶数个数组2*N是偶数嘛 while(x) { TH0=a[j]; j++; TL0=a[j]; j++; TR0=1;// while(! TF0);//等待T0溢出,因为没有采用T0中断 contrl=! contrl; x--; } } // /***************************************************************/ /*****编程时防止中断把寄存器中的数据改变的解决方法是给中断指定寄存器,同优先级的使用同一组没事。 1、写中断程序一定要用using语句指定寄存器组。 第1、2、3组都可以,不能是0. 2、51单片机的中断有两个优先级。 一个中断不会打断另一个相同优先级的中断。 这样相同级别中断可以使用同一个组。 比如: 低优先级的中断函数都用using1,高优先级的中断都用using2。 这样不会冲突。 下面是一个正常的例子: C程序: voidint0()interrupt0using1 默认5个中断时同级的,不会冲突,但是最好养成好习惯 不指定中断要使用的寄存器,每次都要入栈保护数据,中断完还要出栈,代码会增加32字节 ********************************************************************/ //中断函数要指定使用那组寄存器,使用同一组时可能会破坏了上次寄存器中的数据 //同一优先级的中断可以使用同一组寄存器 voidtime0()interrupt1using1//定时器0中断 { EA=0; EX0=0; EX1=0; ET0=0; FASHE=0; delayms(200); JIESHOU=0;//接收指示灯 delayms(1000); //有65MS以上了,表示接收完毕 b[zu/0x200]=j;//j是从0开始的,最后一次电平存完j自加1了,总长度正好是当前值 addr=zu;//因为下面zu值还要用,所以这里转移其数据 //zu是每个存储空间的起始地址 m=0; for(;j>0;j--)//j是数据总长度,如此判断,不会存储多余的空位 {Byte_Program(addr,a ? ? );//从本组数据对应扇区首地址开始写EEPROM m++;//数组下移 addr++;//地址下移 delayms (1);}//forend i<(zu<0xa00)//第一组代码完毕后,转到第二组,每组都是200个空间 zu+=0x200;//测完一组,扇区地址指向下一个扇区 else {zu=0x000;}//超过6组代码,内存重新指向第1组 flag=0; receive=0;//用完接收启动标志要清0 end=1;//退出接收函数最外层循环 } /******************************************************/ //发射频率38khz由T1产生 voidtime1()interrupt3using1//定时器1中断,因为默认是同优先级,所以可以使用同一组寄存器 { khz=! khz; } /******************************************************/ //外部中断存储高电平长度 voidinterint0()interrupt0using1//外部中断0 { if(flag==0)//flag=0表示是首次接收到脉冲 { TH0=0; TL0=10;//前面延时函数消耗的时间补上 TR0=1; EX0=0;//关闭外部中断0,以后的计数都在接收函数里 flag=1;//表示启动T0 } } // /************************************************************/ /******************************************************/ //外部按键中断1 voidinterint1()interrupt2using1//外部中断1 { receive=1; delayms(122);//等过抖动时间 EA=0; } /******************************************************/ //AD转换初始化----打开ADC电源 voidInitADC() { P1=0xff;//这里对其他用到P1口的地方有影响 ADC_CONTR|=0x80; delayms(30); //这两个寄存器用来设置P1口四种状态,每一位对应一个P1引脚,按状态组合操作 P1M0=0x08;//这两个寄存器用来设置P1口四种状态,每一位对应一个P1引脚,按状态组合操作 P1M1=0x08;//设置P1.3做AD } /******************************************************************/ //AD转换程序 voidADC() { ADC_DATA=0;//清除结果 ADC_CONTR=0x60;//转换速度设置0x60最快速度 ADC_CONTR=0xE0;//1110,0000清ADC_FLAG,ADC_START位和低3位 ADC_CONTR|=0x03;//选择A/D当前通道P1.3 delayus(100);//使输入电压达到稳定 ADC_CONTR|=0x08;//0000,1000令ADCS=1,启动A/D转换, while(! (ADC_CONTR&0x10));//! 的优先级比&高太多了 /*************** 这里while不能改成while(ADC_CONTR&0x10==0);就错误了,因为优先级==比&高,所以要加括号 while((ADC_CONTR&0x10)==0)或者非一下while(! (ADC_CONTR&0x10));//! 的优先级比&高太多了 ******************************/ ADC_CONTR&=0xE7;//1111,0111清ADC_FLAG位,关闭A/D转换, voltage=ADC_DATA; if(vol { k=1;//对应0X000扇区内容 } if(voltage>=40&&vol { k=2;//对应0X200扇区内容 } if(voltage>=80&&vol { k=3; } if(voltage>=110&&vol { k=4; } if(voltage>=130&&vol { k=5; } if(voltage>=148&&vol 默认是165电压AD值 { k=6; } } /******************************************/ /* ---STCInternationalLimited---------------- 一个完整的EEPROM测试程序,用宏晶的下载板可以直接测试 STC12C52xxAD系列单片机EEPROM/IAP功能测试程序演示 STC11xx系列单片机EEPROM/IAP功能测试程序演示 STC10xx系列单片机EEPROM/IAP功能测试程序演示 ---STCInternationalLimited------------------ ---宏晶科技设计2009/1/12V1.0-------------- ***********************************************/ //读一字节,调用前需打开IAP功能,入口: DPTR=字节地址,返回: A=读出字节 ucharByte_Read(uintadd) { ISP_DATA=0x00; ISP_CONTR=ENABLE_ISP;//打开IAP功能,设置Flash操作等待时间 ISP_CMD=0x01;//IAP/ISP/EEPROM字节读命令 my_unTemp16.un_temp16=add;//联合体变量赋值,这里是俩字节,因为公用内存,所以下面数组也是此内容 ISP_ADDRH=my_unTemp16.un_temp8[0];//设置目标单元地址的高8位地址 ISP_ADDRL=my_unTemp16.un_temp8[
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 52 单片机 红外 学习 遥控器 按键 可以 发射
![提示](https://static.bdocx.com/images/bang_tan.gif)