OpenEdv-开源电子网

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

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

[复制链接]

15

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2015-4-12
在线时间
13 小时
发表于 2015-10-14 22:25:37 | 显示全部楼层 |阅读模式
5金钱
在学习红外遥控实验的时候遇到了下面问题,发给原子哥,几天了也没回复我,可能比较忙吧!
再一次在这发帖求助,希望大家一起学习交流!
我用
探索者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\r\n",sta);
}
}
REMOTE_STA&=0x7f;
}
return sta;
}

最佳答案

查看完整内容[请看2#楼]

1. 按下遥控器, 在数据采集完之前, 定时器是不会溢出的,  等数据采集完成, 第一次溢出就标记完成一次红外捕获, 主循环已经可以使用这个数据,  如果没有连发码, 那么再过130ms, 就会清空引导标识, 红外采集结束, 等待下一次采集 2. 正如你说在20ms 期间,按下遥控器, 代码自然调到中断函数里面, 这时蜂鸣器一直在响的, 直到中断函数结束,&nbs ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

2164

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5757
金钱
5757
注册时间
2013-11-22
在线时间
1208 小时
发表于 2015-10-14 22:25:38 | 显示全部楼层
1. 按下遥控器, 在数据采集完之前, 定时器是不会溢出的,  等数据采集完成, 第一次溢出就标记完成一次红外捕获, 主循环已经可以使用这个数据,
 如果没有连发码, 那么再过130ms, 就会清空引导标识, 红外采集结束, 等待下一次采集
2. 正如你说在20ms 期间,按下遥控器, 代码自然调到中断函数里面, 这时蜂鸣器一直在响的, 直到中断函数结束,  代码跳回延时20ms处,而不是中间会停80ms, 这个是中断机制的结果
3. 这种想法挺好的, 一个定时器多个用途, 通往成功的路不止一条, 思路正确了, 自然会得到相应的结果
回复

使用道具 举报

15

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2015-4-12
在线时间
13 小时
 楼主| 发表于 2015-10-17 17:16:56 | 显示全部楼层
回复【2楼】lycreturn:
---------------------------------
看了你的解答我明白了,假设没有收到连发码,会在收到数据之后的10ms标记采样完成,当主函数扫描到之后进入20ms的延时,蜂鸣器会响,20ms延时过后,新的扫描到来,由于之前已经清楚收到数据标识位,主循环会关掉蜂鸣器,而此时中断在每隔10ms溢出进入中断,直到130ms过后,也就是说没有连发码,蜂鸣器会响20多ms,可是为啥会响的不止是20ms,如果收到连发码也是130ms左右会标记数据采集完成一次,而20ms,对于130ms来说,也就是说即使一直受到连发码也会想20ms,然后停80ms,之后又到底连发码标志数据接收完成,虽然在听的这80ms中蜂鸣器是不在响,中断也会进入退出,知道标记数据接收完成,蜂鸣器响。虽然明白了你们写的代码的原理,也觉得这样处理很好,可是为什么我的实验结果不是响20ms,停80ms,再停再响,时间可能会有些偏差,但至少响的不是20ms,而是20ms以上,以至于听不出中间有停顿过,我的代码如果一直是的连发码会每110ms标记一次,期间响20ms,停90ms,感觉你们的代码标记的速度比我的快,我会在分析下看具体的时间差异。
回复

使用道具 举报

15

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2015-4-12
在线时间
13 小时
 楼主| 发表于 2015-10-17 19:00:24 | 显示全部楼层
我发现了为什么问什么你的代码会是长响,我在你的代码的Remote_Scan(void)函数中加入了printf("键值:%d\r\n",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\r\n",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的间隔,可是我们按键,很容易发生连发码,也就造成执行多次,我不知道是遥控的问题,还是遥控都这样,我们实际使用很不方便,有没有要消抖,或者滤波的必要?
回复

使用道具 举报

21

主题

78

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2015-10-26
在线时间
32 小时
发表于 2015-12-6 15:25:45 | 显示全部楼层
回复【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; //清空计数器
}      
}     
}
我本自由身,谁敢高高在上
回复

使用道具 举报

15

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
158
金钱
158
注册时间
2015-4-12
在线时间
13 小时
 楼主| 发表于 2015-12-6 18:41:54 | 显示全部楼层
回复【5楼】小败:
---------------------------------
读整个数据采样是大于10ms,在110ms左右,接收一帧的数据时间也不会超过10ms,如果超过要么是数据接收完成了,要么是要接受到连发码了,总之大于10ms,就可以判断有数据了。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-25 18:06

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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