STC12CAD单片机万能学习遥控器记录波形方式Word文档格式.docx
《STC12CAD单片机万能学习遥控器记录波形方式Word文档格式.docx》由会员分享,可在线阅读,更多相关《STC12CAD单片机万能学习遥控器记录波形方式Word文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
![STC12CAD单片机万能学习遥控器记录波形方式Word文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/26/51123f8c-63bc-42c3-bf4e-c5e6352c15f8/51123f8c-63bc-42c3-bf4e-c5e6352c15f81.gif)
//#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;
ucharxdataa[111]={121,1,3,4,44,55,24,156,35};
//间接寻址的高128RAM,内部256RAM高128只能间接寻址
uintj=0;
uintzu=0,addr=0;
//扇区地址
uchark;
//按键代号
ucharm=0;
//写EEPROM时用来移动数组的
ucharb[6];
//用来存储每一组数据的总字节数
/**********************************************************************/
voidmain()
{
//默认STC12是1T运行模式。
时钟没有分频,为了兼容8051,定时器可以分频12.但是如果时钟也分频,就会影响他了。
AUXR=0x00;
//定时器T0T1,12分频。
兼容8051
delayus(5);
delayms(1000);
InitADC();
//这里对其他用到P1口的地方有影响,尽量放前面
contrl=0;
//关闭38K输出
KEY=1;
delayms(500);
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;
delayms(4900);
for(j=6;
j>
0;
j--)//j是数据总长度,如此判断,不会存储多余的空位
{Byte_Program(addr,a
);
//从本组数据对应扇区首地址开始写EEPROM
m++;
//数组下移
addr++;
//地址下移
delayms
(1);
}//forend
m=Byte_Read(0xc00);
/************************************************/
//C编程技巧:
判断恒等于==时,把常量写前面可以防止写成赋值语句
//把“==”写成“=”,会报错,常量不能赋值
/************************************************/
if(121==m)
JIESHOU=1;
delayms(6000);
}
m=0;
//下面还要用,所以清0
addr=0;
zu=0;
EX1=1;
//开外部中断1
IT1=1;
//外部中断1边沿触发,不然按住的时候一直中断
EA=1;
//等待按键时两个灯灭
while
(1)
if(receive)//外部按键中断1,正式进入接收函数
receive=0;
//只用一次,先清0,免得忘了
//发射指示灯
delayms(3000);
delayms
(2);
FASHE=1;
jieshou();
//接收函数是T0定时开始后计数满溢出跳出的
if(!
KEY)//KEY为0时进入发射模式
delayms(200);
fashe();
}
/********************************************************************/
//接收函数初始化
voidinit1()//接收初始化
finish=1;
flag=0;
end=0;
j=0;
EA=0;
//因为下面要写EEPROM,必须关闭EA
TMOD=0x01;
//T0方式1
TH0=0x00;
TL0=0x00;
TR0=0;
EX0=1;
EX1=0;
//关闭外部中断1按键,一旦进入接收函数,就关闭按键防止干扰
ET0=1;
//开T0中断
IT0=1;
//外部中断0边沿触发
//
/************************************************************************/
//红外接收子程序
voidjieshou()
//接收灯亮才可以开始按遥控
init1();
//接收初始化
//开中断
cin=1;
//接收灯亮等待接收
while(finish)//退出接收循环检测
while(flag)//T0已启动标志,用完记得清0,由外部中断0启动,初次启动检测
{//第一次低电平测宽已经开始
while(!
cin);
//等待高电平到来,T0中断不会在这里发生,因为低电平宽度不会有65MS这么长
_nop_();
a[j]=TH0;
//低电平宽度先存高8位数据
j++;
a[j]=TL0;
//存储的是低电平宽度
//数组下移
TH0=0;
//重装T0
TL0=9;
//补偿前面消耗的时间
TR0=1;
//重新启动T0,计时高电平
//高电平测宽开始
while(cin&
&
flag);
//等待cin低电平到来。
T0中断就是在这里等待的时候发生的,因为最后一个电平必然是高电平(无信号就是高)
//flag=1表示T0还没中断,还是接收有效
if(flag)//flag为1才表示计时有效,flag=0表示最后高电平很长结束了
{//加个flag才能退出这个等待
//先存高8位数据
//存储的是低电平段
//重装T0
TL0=0;
//重新启动T0,计时低电平
//判断是否退出接收
if(end)
//用完接收启动标志要清0
delayms(122);
//亮两个灯表示接收成功
finish=0;
//接收完亮两个灯
//开外部按键中断1
/***********************************************/
//发射函数初始化
voidinit2()//发射初始化
//关闭发射端,由于它与38K输出端并联,所以拉低不输出
TMOD=0x21;
//T0方式1,T1方式2
TH1=-(13%256);
//定时13us翻转一次,即38KHZ(26us)
TL1=-(13%256);
ET1=1;
//T1中断
ET0=0;
//禁止T0中断
TR1=1;
//T1启动38K载波开始
//红外发射子程序
voidfashe()//发射程序里没有安排推出操作,所以只有重启才能重新进入选择模式
ADC();
switch(k)
case1:
for(j=0;
j<
b[0];
j++){a[j]=Byte_Read(j);
}init2();
led(b[0]);
break;
//必须先读EEPROM再开定时器中断
case2:
b[1];
j++){a[j]=Byte_Read(j+0x200);
led(b[1]);
case3:
b[2];
j++){a[j]=Byte_Read(j+0x400);
led(b[2]);
case4:
b[3];
j++){a[j]=Byte_Read(j+0x600);
led(b[3]);
case5:
b[4];
j++){a[j]=Byte_Read(j+0x800);
led(b[4]);
case6:
b[5];
j++){a[j]=Byte_Read(j+0xa00);
led(b[5]);
default:
k=0;
//发射完毕要关闭38K载波
TR1=0;
//发射高电平。
接收端就是低电平。
而载波就是高电平有38KHZ载波,二极管反复38K亮灭。
低电平什么也没有,二极管不通。
voidled(ucharx)
x=x/2;
//2个数组是一段电平,而且肯定是偶数个数组2*N是偶数嘛
while(x)
_nop_();
//空操作不废时序。
就是没指令
//因为共有2N个数据。
第一个肯定是发射的高电平。
因为接收端首位肯定是0.
//红外二极管亮表示发射高电平。
接收的就是低电平。
高电平就是有38K载波,低电平什么也没有,二极管不通。
//所以,高电平发射38K波形,低电平不发射。
时间由contrl控制
/**********数组里存的是要定时的时间。
这里不能用256-a[j],因为对没有存入数据的EEPROM,
读出来数据都是1,即a[j]=0xff,用减法会定时65MS的,用负号就不会,已启动他就会溢出中断
************************/
TH0=-a[j];
//数组里存的是要定时的时间。
这里不能用256-a[j]
TL0=-a[j];
contrl=!
contrl;
//首次发射肯定是高电平,所以要翻转。
每个电平发完到第二个开始前多了一次翻转。
//
TF0);
//等待T0溢出,因为没有采用T0中断
//加空操作是为了防止在执行指令的时候发生中断,破坏38Khz频率。
x--;
//必须在清0溢出位TF之前关闭定时器。
不然会自动启动的
就是没指令
TF0=0;
//溢出位清0
//发射完毕,T0关闭
/***************************************************************/
//中断函数要指定使用那组寄存器,使用同一组时可能会破坏了上次寄存器中的数据
//同一优先级的中断可以使用同一组寄存器
voidtime0()interrupt1using1//定时器0中断
//有65MS以上了,表示接收完毕
EX0=0;
b[zu/0x200]=j;
//j是从0开始的,最后一次电平存完j自加1了,总长度正好是当前值
addr=zu;
//因为下面zu值还要用,所以下面不直接用ZU
//zu是每个存储空间的起始地址
for(;
if(zu<
0xa00)//第一组代码完毕后,转到第二组,每组都是200个空间
zu+=0x200;
//测完一组,扇区地址指向下一个扇区
else
{zu=0x000;
}//超过6组代码,内存重新指向第1组
end=1;
//退出接收函数最外层循环
//发射频率38khz由T1产生
voidtime1()interrupt3using1//定时器1中断,因为默认是同优先级,所以可以使用同一组寄存器
//38K翻转产生
//外部中断存储高电平长度
voidinterint0()interrupt0using1//外部中断0
if(0==flag)//flag=0表示是首次接收到脉冲
TL0=10;
//前面延时函数消耗的时间补上
//关闭外部中断0,以后的计数都在接收函数里
flag=1;
//表示启动T0
/************************************************************/
//外部按键中断1
voidinterint1()interrupt2using1//外部中断1
receive=1;
//等过抖动时间
//AD转换初始化----打开ADC电源
voidInitADC()
P1=0xff;
//这里对其他用到P1口的地方有影响
ADC_CONTR|=0x80;
delayms(30);
//这两个寄存器用来设置P1口四种状态,每一位对应一个P1引脚,按状态组合操作
P1M0=0x08;
P1M1=0x08;
//设置P1.3做AD
//AD转换程序
voidADC()
ADC_DATA=0;
//清除结果
ADC_CONTR=0x60;
//转换速度设置0x60最快速度
ADC_CONTR=0xE0;
//1110,0000清ADC_FLA