学习红外遥控实验的时候的疑问

2019-07-21 00:45发布

在学习红外遥控实验的时候遇到了下面问题,发给原子哥,几天了也没回复我,可能比较忙吧!
再一次在这发帖求助,希望大家一起学习交流!
我用
探索者F4的红外遥控带代码,在主循环里扫描
if(Remote_Scan()) 
{
  GPIO_SetBits(GPIOF,GPIO_Pin_8);//BEEP
  delay_ms(20);
}
else  
   GPIO_ResetBits(GPIOF,GPIO_Pin_8);
也就是如果有按键动作蜂鸣器就会短暂响下,可是我结果我按下按键蜂鸣器就长鸣一下,如果按住按键不放就会一直响。
我仔细分析了代码
if(RmtSta&0x80)//上次有数据被接收到了

    RmtSta&=~0X10; //取消上升沿已经被捕获标记
    if((RmtSta&0X0F)==0X00)RmtSta|=1<<6;//标记已经完成一次按键的键值信息采集
    if((RmtSta&0X0F)<14)RmtSta++;
else
{
    RmtSta&=~(1<<7);//清空引导标识
    RmtSta&=0XF0; //清空计数器 
}   

发现如果没有连发码,在过140ms之后就认为完成一次完整的按键接收了,可是 RmtSta&=~(1<<7);//清空引导标识  
就不立即响应了,必须要等下次定时器溢出进入 if(RmtSta&0x80)里,进行按键信息采集完成标记,以让主循环响应,可是,之前超时的时候已经清空了引导标识,所有必须等到下一次按键开始捕获的时候才让执行上一次的动作。
如果收到连发码就会立即响应连发码,想问下我的分析对不对?我很纠结这。
按键完成一次信息收集最起码要100ms以上,收到完成标记之后,就算主循环扫描立即响应,打开蜂鸣器发声并延时20ms,在这20ms中如果又发生按键或者在接受连发码,接收连发码或者按键的时间至少100ms,也就是说假设是主循环很快开始也至少会是响20ms后停80ms,然后再响20ms.这与结果不服,我在Remote_Scan(void)里添加printf()打印按键的结果,波特率设置460800,每次按键总是打印好几次按键值。
想问下原子哥分析下告诉我,我自己在基础上修改,之前每次捕获上升沿就给定时器置零,我绝对如果定时还用在其他地方这样做不好,就取出当前值,在捕获下降沿是在做了防溢出处理值将得到值减去之前的值,得到脉冲时间。我的结果和我分析的相符,可是我却不知是我的这样结果正确还是你的是正确的。请原子个分析下,附上代码,初始化都和参数都一样的,就中断处理有些差异
u8 REMOTE_STA;
//u8 REMOTE_RES;
u16 REMOTE_CNT;
u32 REMOTE_VAL;
void TIM1_CC_IRQHandler(void)
{
if(TIM_GetITStatus(TIM1,TIM_IT_CC1)!=RESET)
{
if(RDATA)
{
REMOTE_CNT=TIM_GetCounter(TIM1);
TIM_OC1PolarityConfig(TIM1,TIM_ICPolarity_Falling);
REMOTE_STA|=0x40;
}
else

if((REMOTE_STA&0x1f)<3)//大于20ms以上不用计算
REMOTE_CNT=TIM_GetCapture1(TIM1)+((REMOTE_STA&0x1f)*10000)-REMOTE_CNT;
else REMOTE_CNT=0;
TIM_OC1PolarityConfig(TIM1,TIM_ICPolarity_Rising);
if(REMOTE_STA&0x40)//捕获完上升沿,完成下降捕获
{
if(REMOTE_STA&0x20)//收到引导码
{
if(300<REMOTE_CNT&&REMOTE_CNT<800)//560us
{
  REMOTE_VAL<<=1;
  REMOTE_VAL|=0;
}
else if(1400<REMOTE_CNT&&REMOTE_CNT<1800)//1680us
{
REMOTE_VAL<<=1;
REMOTE_VAL|=1;
}
else if(2200<REMOTE_CNT&&REMOTE_CNT<2700)//2500
{
//REMOTE_RES++;
REMOTE_STA|=0x80;

}
else if(4200<REMOTE_CNT&&REMOTE_CNT<4700)

  REMOTE_STA|=0x20; 
 // REMOTE_RES=0;
}

REMOTE_STA&=0xA0;//清除捕获上升沿标志及计数 
}
TIM_ClearITPendingBit(TIM1,TIM_IT_CC1);
}
}
void TIM1_UP_TIM10_IRQHandler(void)
{
if(TIM_GetITStatus(TIM1,TIM_IT_Update)!=RESET)
{
if(REMOTE_STA&0x40)
REMOTE_STA++;
if(REMOTE_STA&0x20)
{
if(14<(REMOTE_STA&0x1f))//当捕获的时间大于140ms认为已经没有按键动作了
{
REMOTE_STA=0x80;//标志接收完成
REMOTE_CNT=0;//清空前一次定时器的起始值
}

TIM_ClearITPendingBit(TIM1,TIM_IT_Update);
}
}
u8 Remote_Scan(void)
{
u8 t1=0,t2=0;
u8 sta=0;
if(REMOTE_STA&0x80)

t1=REMOTE_VAL>>24;
t2=REMOTE_VAL>>16;
if((u8)~t1==t2)
{
t1=REMOTE_VAL>>8;
t2=(unsigned char)REMOTE_VAL;
if(t1==(u8)~t2)
{
sta=t1;
printf("键值:%d ",sta);
}
}
REMOTE_STA&=0x7f;
}
return sta;
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
5条回答
lycreturn
1楼-- · 2019-07-21 04:36
 精彩回答 2  元偷偷看……
爱我别走
2楼-- · 2019-07-21 06:38
回复【2楼】lycreturn:
---------------------------------
看了你的解答我明白了,假设没有收到连发码,会在收到数据之后的10ms标记采样完成,当主函数扫描到之后进入20ms的延时,蜂鸣器会响,20ms延时过后,新的扫描到来,由于之前已经清楚收到数据标识位,主循环会关掉蜂鸣器,而此时中断在每隔10ms溢出进入中断,直到130ms过后,也就是说没有连发码,蜂鸣器会响20多ms,可是为啥会响的不止是20ms,如果收到连发码也是130ms左右会标记数据采集完成一次,而20ms,对于130ms来说,也就是说即使一直受到连发码也会想20ms,然后停80ms,之后又到底连发码标志数据接收完成,虽然在听的这80ms中蜂鸣器是不在响,中断也会进入退出,知道标记数据接收完成,蜂鸣器响。虽然明白了你们写的代码的原理,也觉得这样处理很好,可是为什么我的实验结果不是响20ms,停80ms,再停再响,时间可能会有些偏差,但至少响的不是20ms,而是20ms以上,以至于听不出中间有停顿过,我的代码如果一直是的连发码会每110ms标记一次,期间响20ms,停90ms,感觉你们的代码标记的速度比我的快,我会在分析下看具体的时间差异。
爱我别走
3楼-- · 2019-07-21 07:27
我发现了为什么问什么你的代码会是长响,我在你的代码的Remote_Scan(void)函数中加入了printf("键值:%d ",t1);如下:
u8 Remote_Scan(void)
{        
u8 sta=0;       
    u8 t1,t2;  
if(RmtSta&(1<<6))//得到一个按键的所有信息了

    t1=RmtRec>>24; //得到地址码
    t2=(RmtRec>>16)&0xff; //得到地址反码 
      if((t1==(u8)~t2))//检验遥控识别码(ID)及地址 
    { 
        t1=RmtRec>>8;
        t2=RmtRec; 
        if(t1==(u8)~t2)sta=t1;//键值正确  
printf("键值:%d ",t1);
}   
if((sta==0)||((RmtSta&0X80)==0))//按键数据错误/遥控已经没有按下了
{
  RmtSta&=~(1<<6);//清除接收到有效按键标识
RmtCnt=0; //清除按键次数计数器
}
}  
    return sta;
}
只有正确收到数据并被主函数扫描到的话,就会打印收到的数据,串口设置为460800一减小误差,下面是我连按收到的数据:
键值:162[2015-10-17 06:45:26.024]
键值:162[2015-10-17 06:45:26.059]
键值:162[2015-10-17 06:45:26.094]
键值:162[2015-10-17 06:45:26.129]
键值:162[2015-10-17 06:45:26.164]
键值:162[2015-10-17 06:45:26.200]
键值:162[2015-10-17 06:45:26.235]
键值:162[2015-10-17 06:45:26.271]
键值:162[2015-10-17 06:45:26.306]
键值:162[2015-10-17 06:45:26.341]
键值:162[2015-10-17 06:45:26.376]
键值:162[2015-10-17 06:45:26.411]
键值:162[2015-10-17 06:45:26.447]
键值:162[2015-10-17 06:45:26.482]
键值:162[2015-10-17 06:45:26.517]
键值:162[2015-10-17 06:45:26.553]
键值:162[2015-10-17 06:45:26.588]
键值:162[2015-10-17 06:45:26.623]
键值:162[2015-10-17 06:45:26.658]
键值:162[2015-10-17 06:45:26.694]
键值:162[2015-10-17 06:45:26.729]
键值:162[2015-10-17 06:45:26.764]
键值:162[2015-10-17 06:45:26.801]
键值:162[2015-10-17 06:45:26.840]
键值:162[2015-10-17 06:45:26.871]
键值:162[2015-10-17 06:45:26.907]
键值:162[2015-10-17 06:45:26.942]
键值:162[2015-10-17 06:45:26.977]
从结果可以看出没隔35ms左右打印一次,我用Jlink调试了下,发现没收到一次数据会进入5次Remote_Scan(void),分析代码也发现问题的差异出现在你们的代码即使收到数据,只要按键没有结束就不会清空数据采样完成位,也就造成了主循环没个35ms进入一次Remote_Scan(void),我的代码是进入一次,清除一次,也就是每次收到就才会响应,之间有110ms的间隔,蜂鸣器响20ms,停90ms,你们的代码是35ms的间隔,响20ms,停15ms,所有停声音才会有很大的差别。
不过有个问题,即使我的代码没110ms的间隔,可是我们按键,很容易发生连发码,也就造成执行多次,我不知道是遥控的问题,还是遥控都这样,我们实际使用很不方便,有没有要消抖,或者滤波的必要?
小败
4楼-- · 2019-07-21 12:57
回复【2楼】lycreturn:
---------------------------------
定时器不是10ms溢出一次吗,但是整个数据采集大于10ms啊



void TIM4_IRQHandler(void)
{        
 
if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET)
{
if(RmtSta&0x80) //上次有数据被接收到了
{
RmtSta&=~0X10; //取消上升沿已经被捕获标记
if((RmtSta&0X0F)==0X00)RmtSta|=1<<6; //标记已经完成一次按键的键值信息采集
if((RmtSta&0X0F)<14)RmtSta++;
else
{
RmtSta&=~(1<<7); //清空引导标识
RmtSta&=0XF0; //清空计数器
}      
}     
}
爱我别走
5楼-- · 2019-07-21 17:58
回复【5楼】小败:
---------------------------------
读整个数据采样是大于10ms,在110ms左右,接收一帧的数据时间也不会超过10ms,如果超过要么是数据接收完成了,要么是要接受到连发码了,总之大于10ms,就可以判断有数据了。

一周热门 更多>