红外操作免去了和机器接触。第一是方便,第二也很自然的可以将用户与管理着分离(使用功能在遥控上,调试功能在机器上)。所以免不了在自己的电子钟设计中加入了红外。加的多,学得也多嘛。
虽然重点在后面,但是先上个程序
参考总结后,第一次参考归纳出源程序如下:
#include
#include
#include
////////////////////////////////////////////////
sbit ir=P3^2;//红外接口标志
////////////////////////////////////////////
unsigned char irtime;//电平宽度(以定时器来记录)
bit irpro_ok,irok;
unsigned char ircord[4];
unsigned char irdata[33];
//////////////////////////////////////////////
void ir_work(void);
void ircordpro(void);
//////////////////////////////////////////////////////////////////
void tim0_isr (void) interrupt 1 using 1//定时器0中断服务函数
{
irtime++;
}
///////////////////////////////////////////////////////////////////////
void ex0_isr (void) interrupt 0 using 0//外部中断0服务函数
{
unsigned char i;
bit startflag;
if(startflag)
{
TR0=0;
if(irtime<38&&irtime>=34)//引导码判断(9MS)
i=0;
TR0=1;
//确认为引导码,初始为新的32位编码开始
irdata[i]=irtime;//i=0是引导码,后面是其余码。每次记录的是每次高低电平一起的脉冲宽度。
//收到到一个码算一次中断,中断结束前清零宽度计时
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
}
}
//第一次进入中断开启startflag,用于第二次进入中断计时比对
else
{irtime=0;startflag=1;}
}
////////////////////////////////////////////////////////////////////
void TIM0init(void)//定时器0初始化
{
TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
TH0=0;//reload value
TL0=0;//initial value
ET0=1;//开中断
TR0=1;
}
///////////////////////////////////////////////////////////////////
void EX0init(void)
{
IT0 = 1;
EX0 = 1;
EA = 1;
}
void ir_work(void)//红外键值散转程序
{
switch(ircord[2])//判断第三个数码值(数据码,后面是反码,前面是引导码和地址码)
{
case 0:P1=0x00;break;//1 LED显示相应的按键值
case 1:P1=0xfe;break;//2
case 2:P1=0xfd;break;//3
}
[page]
irpro_ok=0;//处理完成标志清零
}
void ircordpro(void)//红外码值处理函数
{
unsigned char i, j, k;
unsigned char cord,value;
k=1;//从1开始,是引导码以后的一帧所有数据
for(i=0;i<4;i++)//处理4个字节
{
for(j=0;j<8;j++) //处理1个字节8位
{
cord=irdata[k];
if(cord>7)//电平宽度大于某个值,可以判断为1(2.25ms) 时间范围要大点,否则重复按键出现混乱
{
value|=0x80;//若为1则赋值
}
//其余情况可以判断为0(是不是证明了,irdata接收的是引导码之后的一帧所有电平?)
else
{
value=value;//若判断为0则不变(移位后自然为0)
}
if(j<7)
{
value>>=1;//为什么|0X01 与<<1配合,不行。因为最后完成值要求最先写入的最低位,用这个想法会反过来。
}
k++;
}
ircord[i]=value;
value=0;
} irpro_ok=1;//处理完毕标志位置1
}
/////////////////////////////////////////////////////////////////
void main(void)
{
EX0init(); // 初始化中断
TIM0init();//初始化定时器0
while(1)//主循环
{
if(irok)
{
ircordpro();//码值处理
irok=0;
}
if(irpro_ok)//step press key
{
ir_work();//码值识别散转
}
}
}
程序基础来自已有程序,在看完下面的说明后,就可以移植了,毕竟同一个解码标准,都是大同小异,甚至就算不同解码标准也仅仅是判断编码的时间要求上长短不同。但为什么这是经过我自己消化的呢,这里有个非常有趣的问题。
在我单独实验红外模块的时候(也就是上面的源程序),能够正常运行。但是移植入开启了T2中断的大程序里之后,红外部分一点反应也没有。在接下来的调试过程中,因为不会使用DEBUG进入外部中断,在不断地比对程序中浪费了许多时间。当我使用LED调试法时(把P1=0x55;插入任意想要检验的程序行,亮了就证明程序走到了这里),亮与不亮在这里分界了(红色标记):
void ex0_isr (void) interrupt 0 using 0//外部中断0服务函数
{
unsigned char i;
bit startflag;
if(startflag)
{
TR0=0;
if(irtime<38&&irtime>=34)
i=0;
TR0=1;
irdata[i]=irtime;
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
}
}
恰好最近有重温static定义变量的特点,不然可能死得不明不白。因为抱着单独运行正常,移植整合之后也正常的想法,源程序的static unsigned char i;被我改为了uchar i;(我在自己程序里已做#define uchar unsigned char)。
答案清楚了:因为我不允许任何配角程序打扰T2时钟工作,所以设置了最高优先级(PT2=1;),这样每次外部中断0里面局部变量i的累加会被打断,如果不能保值,就每次都被撤销和重新构建,或许永远达不到(i==33)要求。static按我的理解,最大的作用就是能够保持上一次的值,至于其他作用印象就不大深刻了。
哈哈,有意思,记住 中断里的局部变量定义 unsigned char i;要改为static unsigned char i;