OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4798|回复: 3

关于红外遥控实验的问题

[复制链接]

11

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
91
金钱
91
注册时间
2012-10-26
在线时间
0 小时
发表于 2013-9-22 20:46:46 | 显示全部楼层 |阅读模式
我这里的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()是前面定义的那个宏,则不能单步执行,死在这里了。。。 

以上三个问题我思考了一下午,确实没有想明白,希望大家不吝赐教,先在这里谢谢了。。。





正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-22 22:01:18 | 显示全部楼层
回复【楼主位】杨四郎:
---------------------------------
1,你用33.64us,(res>=100&&res<130),也是可以正常解码是么?那你可以示波器看一下遥控器接收波形么?
2,一个nop不确定是不是一个us,这我也不太清楚,呵呵。检查汇编代码,分析指令周期吧。
3,是程序死了?那你第二个问题,怎么测试的?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

11

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
91
金钱
91
注册时间
2012-10-26
在线时间
0 小时
 楼主| 发表于 2013-9-23 16:48:10 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
1.我用33.64us,(res>=100&&res<130),也是可以正常解码的,所以我才郁闷。。根据你的点拨,我用示波器看了一下波形。
 这里传不了图片,就说一下,得到的波形跟你书上讲解的完全惊人的一致。就是:同步码9ms低+4ms高,接着8个0,每个0是560us低+560us高,再接着8个1,每个1是560us低+1680us高。。。。最后的结束码是9ms低+2.5ms高+0.56ms低。

2.关于#define wait20us() {..12个~15个nop....} 为什么可以。似乎是因为在这个函数里面
       uchar check(void)
{
    uchar t=0;
    while(RDATA)
    {
        t++;
wait20us(); //12到15个nop 放在这里,作为一个整体加上前面和后面的语句,其实总共延时符合要求
        if(t==250)  
return t;                   //超时溢出
    }
    return t;
}     

3.现在只剩下最后一个问题:为什么用下面这个wait20us()也行??
   这个明显时间超出了啊?
        void wait20us(void)                   //②延时20us,其实真正调用这个函数耗时33.64us
{
   TMOD=0x01;                        //定时器0,工作方式1
           TH0=(65536-18)/256;
   TL0=(65536-18)%256;
   TR0=1;                                //开启定时器
   while(!TF0);                          //等待时间到    
}
回复 支持 反对

使用道具 举报

11

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
91
金钱
91
注册时间
2012-10-26
在线时间
0 小时
 楼主| 发表于 2013-9-23 18:10:58 | 显示全部楼层
回复【3楼】杨四郎:
---------------------------------
已经找到原因:
void wait20us(void)      //精确延时20us,其实真正调用这个函数耗时33.64us
{
   TMOD=0x01;            //定时器0,工作方式1
           TH0=(65536-15)/256;
   TL0=(65536-15)%256;
   TR0=1;                //开启定时器
   while(!TF0);          //等待时间到    
           TF0=0;                //TF0清零    
}    

  少了最后一句话,就是   ( TF0=0;      //TF0清零  )。。。
唉,粗心大意。。。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-12 16:47

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表