我这里的51程序是根据原子老大的MINISTM32板上的红外遥控实验而改的,虽然效果已经做出来了。但是有两个问题没弄明白,希望大家指教:
/***晶振11.0592MHz******/
#include "common.h"
#include<intrins.h>
#define wait20us() { _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_(); \
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();} //①这里本应该是18个nop,也就是20us左右,但是只有15个的时候才行
sbit RDATA=P3^3; //红外接口
ulong key=0; //红外摇控的键值,无键按下时为0
uchar count; //按键次数
uchar receive=0;
/********** 红外初始化 ********/
void Red_Init(void)
{
RDATA=1; //P3^3输出高电平
EA=1; //开启总中断
EX1=1; //开启红外(外部中断1)中断
IT1=1; //负跳沿产生中断
}
/* void wait20us(void) //②延时20us,其实真正调用这个函数耗时33.64us
{
TMOD=0x01; //定时器0,工作方式1
TH0=(65536-18)/256;
TL0=(65536-18)%256;
TR0=1; //开启定时器
while(!TF0); //等待时间到
} */
/****** 检测脉冲宽度,最长脉冲宽度为5ms ******/
uchar check(void)
{
uchar t=0;
while(RDATA)
{
t++;
wait20us(); //延时20us
if(t==250)
return t; //超时溢出
}
return t;
}
/*-------------------------协议--------------------------
开始拉低9ms,接着是一个4.5ms的高脉冲,通知器件开始传送数据了,
接着发送4个8位二进制码,第一二个是地址码(遥控器识别码,REMOTE_ID),
接着的两个数据是键值,第一个为正码,第二个为反码。
发送完后过40ms,遥控器再发一个9ms低+2.5ms高的脉冲,表示按键的次数,
最后是一个0.56ms低+97.94ms高脉冲表示结束。
每个按键不同这处只在于那8位数据的原码和反码,因些只须要识别
8位原码就可以识别按键了
---------------------------------------------------------*/
/****** 外部中断1服务程序,按键处理 ******/
void int1(void) interrupt 2 using 1
{
uchar res=0;
uchar OK=0;
uchar RODATA=0; //红外传过来的数据
while(1) //注意是while(1)哦,也就是一次正常的中断后就接受32位数据
{
if(RDATA) //有高脉冲出现
{
res=check(); //获得此次高脉冲宽度
if(res==250)
break; //非有用信号
if(res>=130&&res<250)
OK=1; //获得前导位(4.5ms)
else if(res>=100&&res<130) //如果是2.5ms左右,结束信号,这个范围一定要控制好
{
receive=1; //接收到数据
count++; //按键次数加1
break;
}
else if(res>=50&&res<100) //高电平为1.68ms左右,发送的是1
RODATA=1;
else if(res>=10&&res<50) //如果是窄脉冲,则RODATA=0
RODATA=0; //560us
if(OK)
{
key <<= 1 ;
key += RODATA;
count=0; //按键次数清零
}
}
}
//中断标志自动硬件清零
}
/**** 把红外数据进行转换 ****/
uchar redchange(void)
{
uchar t1,t2;
t1=(uchar)(key>>24); //地址码
t2=(key>>16)& 0xff; //地址反码
receive=0; //清除接收标记
if(t1==((uchar)~t2 && t1)) //检验是否正确
{
t1=key>>8; //控制码
t2=key; //控制反码
if(t1==(uchar)~t2)
return t1;
}
return 0;
}
/***********主程序************/
void main(void)
{
uchar key1[3]={0,0,0};
uchar key_value;
uchar i,j=0;
uchar *t1;
// wait20us(); //③这个wait20us如果是宏定义则不能单步执行
Red_Init();
InitLCD(); //初始化
ClearScreen(0);
while(1)
{
if(receive)
{
key_value=redchange();
key1[0]=key_value/100;
key1[1]=key_value%100/10;
key1[2]=key_value%10;
for(i=0;i<3;i++)
{
switch(key1)
{
case 0:t1=shuzi[0];break;
case 1:t1=shuzi[1];break;
case 2:t1=shuzi[2];break;
case 3:t1=shuzi[3];break;
case 4:t1=shuzi[4];break;
case 5:t1=shuzi[5];break;
case 6:t1=shuzi[6];break;
case 7:t1=shuzi[7];break;
case 8:t1=shuzi[8];break;
case 9:t1=shuzi[9];break;
}
Display_datachar(2,2,j,t1); //这是12864的显示函数
j+=8;
}
delayms(1000);
ClearScreen(0);
j=0;
}
}
}
问题是:①因为我是改自原子的程序,所以检测脉冲宽度的时候也是用延时20us,而我实际写的那个函数经过仿真是33.64us,看起来似乎是没问题,可是这样一来,似乎与原子讲的不一致,比如原子讲的结束信号是高电平为2.5ms,而我上面是 (res>=100&&res<130) ,也就是3.364ms~4.373ms。。。。。
②本来想写一个精确一点的延时20us,用宏定义写#define wait20us() {......},本应该写18个nop比较接近,但是发现写18个nop怎么都不行,结果改成15个nop 马上就出效果了,现象正常,一算,发现15个nop约为16.28us,恰好是我用定时器写的那个 void wait20us(void) 【实测调用该函数是耗时33.64us】 函数的一半时间。。。。。。这我就更混乱了。。。
③为了测试 #define wait20us() {..18个nop....} 到底是不是19.6us左右,我在main函数里面故意放了一个wait20us(),在调用wait20us(); 这一行和其后面一行放上断点,看一下执行时间只差。。。结果是:如果这个wait20us()是前面定义的那个函数,则时间是 33.64us , 如果这个wait20us()是前面定义的那个宏,则不能单步执行,死在这里了。。。
以上三个问题我思考了一下午,确实没有想明白,希望大家不吝赐教,先在这里谢谢了。。。
|