找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4284|回复: 16
打印 上一主题 下一主题
收起左侧

关于红外遥控器如何做长按识别问题,求大神指教一下

  [复制链接]
回帖奖励 30 黑币 回复本帖可获得 30 黑币奖励! 每人限 1 次
跳转到指定楼层
楼主
ID:607312 发表于 2021-7-6 09:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
//*********************************************************
/*  文件名:TEST_61F02x_Timer2.c
*        功能:  FT61F02x-Time2功能演示
*   IC:    FT61F023 SOP16
*   晶振:  16M/2T                    
*   说明:  当DemoPortIn悬空或者高电平时,
*                   DemoPortOut输出5KHz占空比50%的波形-Tm2实现
*                   当DemoPortIn接地时,DemoPortOut输出高电平.关定时器

*                  FT61F023  SOP16
*                 ----------------
*  VDD-----------|1(VDD)   (VSS)16|-----------GND     
*  NC------------|2(PA7)   (PA0)15|------------NC
*  NC------------|3(PA6)   (PA1)14|------------NC
*  NC------------|4(PA5)   (PA2)13|------------NC
*  DemoPortIn----|5(PC3)   (PA3)12|---DemoPortOut
*  NC------------|6(PC2)   (PC0)11|------------NC
*  NC------------|7(PA4)   (PC1)10|------------NC
*  NC------------|8(PC5)   (PC4)09|------------NC
*                              ----------------
*/
//*********************************************************
#include "SYSCFG.h"
//#include "Infrared_Rece_5104.h"

//**********************************************************


#define                REC                        PA4                                        //红外接收IO,用户请将相应IO设置为输入
#define         BootCode         0x0D                                //引导码

typedef union
{
    unsigned char  all;
    struct
    {
       unsigned b0:1;
       unsigned b1:1;
       unsigned b2:1;
       unsigned b3:1;
       unsigned b4:1;
       unsigned b5:1;
           unsigned b6:1;
       unsigned b7:1;
    }one;
}bits;


volatile unsigned char RecCode;                        //5104码除去引导码 后的用户码
volatile bits RecWork;                                        //工作位域
#define Rflag                        RecWork.all
#define        Flag_RecOne                RecWork.one.b0        //收到5104码标志位        

void RecServer();
void InfraredReception();                                //接收函数,在中断中调用


//***********************宏定义*****************************
#define  unchar     unsigned char
#define  unint      unsigned int
#define  unlong     unsigned long

//#define                GREEN                RA7                        //0开 1关
#define                Led1                PA7
#define                Led2                PC3                //1开 0关

volatile bit B_MainLoop;

/*-------------------------------------------------
*  函数名:POWER_INITIAL
*        功能:  上电系统初始化
*  输入:  无
*  输出:  无
--------------------------------------------------*/
//********************************************************
//**************中断处理**********************************
void interrupt ISR(void)           //PIC_HI-TECH使用
{
   static unsigned char times;
  //定时器2的中断处理**********************
        if(TMR2IE && TMR2IF)           //100us中断一次
        {
                TMR2IF = 0;
                if(++times >= 20)//20*125us = 2.5ms
                {
                        times = 0;
                        B_MainLoop = 1;
                }
               
                InfraredReception();                                        //调用红外接收函数

        }
}
/*-------------------------------------------------
*  函数名:POWER_INITIAL
*        功能:  上电系统初始化
*  输入:  无
*  输出:  无
--------------------------------------------------*/        
void POWER_INITIAL (void)
{
         
        OSCCON = 0B01110001;    //WDT 32KHZ IRCF=111=16MHZ/2=8MHZ,0.125US/T
                                                //Bit0=1,系统时钟为内部振荡器
                                                //Bit0=0,时钟源由FOSC<2:0>决定即编译选项时选择
        INTCON = 0;             //暂禁止所有中断
        PORTA = 0B00000000;
        TRISA = 0B00010000;            //PA输入输出 0-输出 1-输入
                                                    //PA3->输出         
        PORTC = 0B00000000;
        TRISC = 0B00000000;            //PC输入输出 0-输出 1-输入                                                  
        WPUA = 0B00010000;      //PA端口上拉控制 1-开上拉 0-关上拉
        WPUC = 0B00000000;      //PC端口上拉控制 1-开上拉 0-关上拉
        OPTION = 0B00001000;        //Bit3=1 WDT MODE,PS=000=1:1 WDT RATE
                                                        //Bit3 预分频器分配位 0-Timer0 1-WDT
                                                        //Bit7(PAPU)=0 ENABLED PULL UP PA
        MSCKCON = 0B00000000;   //Bit6->0,禁止PA4,PC5稳压输出
                                                //Bit5->0,TIMER2时钟为Fosc
                                                //Bit4->0,禁止LVR      
        CMCON0 = 0B00000111;    //关闭比较器,CxIN为数字IO口

}
/*-------------------------------------------------
* 函数名称:   TIMER2_INITIAL
* 功能:      初始化设置定时器2
* 相关寄存器: T2CON TMR2 PR2 TMR2IE TMR2IF PEIE GIE
-------------------------------------------------*/
void TIMER2_INITIAL (void)
{
        T2CON = 0B00000001; //Bit[1,0]=01,T2时钟分频 1:4
                                    //Bit[6-3]=0000,T2输出时钟分频1:1
        TMR2 = 0;           //TMR2赋初值
        PR2 = 200;          //设置TMR2输出比较值定时100us=(1/16000000)*2*4*200(PR2)
                                                //16M-2T-4分频
        TMR2IF = 0;         //清TIMER2中断标志
        TMR2IE = 1;         //使能TIMER2的中断
        TMR2ON = 1;         //使能TIMER2启动
        PEIE=1;             //使能外设中断
        GIE = 1;            //使能全局中断

}

/***********************************************
函数名称:RecServer
函数功能:5104红外接收按键处理
入口参数:无
出口参数:无
备注:
************************************************/
void RecServer()
{
        if(1 == Flag_RecOne)
        {
                Flag_RecOne = 0;
                switch(RecCode)
                {
                    
                        case 0x0A:        Led1 = ~Led1; break;//测试
            case 0x15:        Led1 = ~Led1; break;//测试
            case 0x19:        Led1 = ~Led1; break;//测试


                //case 0x82:        Led1 = ~Led1; break;//开/风速                        
         //case 0x81:        Led1 = ~Led1; break;//关机
                //        case 0x90:        Led2 = ~Led2; break;//摇头
                //        case 0x84:        Led1 = ~Led1; break;//风类
                //        case 0xc3:        Led1 = ~Led1; break;//彩灯
                //case 0x88:        Led2 = ~Led2; break;// 定时
                        default:break;
                }                                
        }        
}

/***********************************************
函数名称:InfraredReception
函数功能:5104红外接收解码
入口参数:无
出口参数:无
备注:
************************************************/
void InfraredReception()
{
        static unsigned char rlow = 0,rhigh = 0,rcount = 0,rdata = 0;
        
        if(!REC)
                rlow++;                                                                        //低电平计时
        else if(0 == rlow)
        {
                rhigh++;                                                                //高电平计时
                if(rhigh & (0x20))                                                //持续4ms高电平,重新接受引导码
                {
                        Rflag &= 0b11101111;
                        rdata = 0;
                        if(rhigh & (0x80))                                        //持续20ms高电平,重新收码
                        {
                                RecCode = 0;
                                rhigh = 0;
                                Rflag &= 0b01111111;                                
                        }
                }
        }
        else
        {
                rdata <<= 1;
                if(rlow >= (0x8))                                                //上升沿,判断码值,低电平大于1ms为1,否则为0
                        rdata |= 0x01;
               
                rlow = 0;
                rhigh = 0;
                if(0 == (Rflag & 0x10))                                        //是否已经收到了引导码
                {
                        if(BootCode == (rdata & 0x0f))                //还未收到引导码,判断是否是正确的引导码
                        {
                                Rflag |= 0x10;                                        //收到引导码标志
                                rcount = 0;                                                //准备接收数据码
                                rdata = 0;
                        }
                }
                else
                {
                        rcount++;
                        if(rcount & 0x8)                                        //8位数据码接收完成
                        {
                                if(RecCode == rdata)                        //收到2帧相同的码才处理
                                {
                                        if(0 == (Rflag & 0x80))                //已经响应过了,不再重复处理
                                        {
                                                Rflag |= 0x01;                        //收到按键码标志
                                                Rflag |= 0x80;                        //用于判断长按键的标志,持续20ms高电平才清零
                                        }
                                }               
                                else
                                        RecCode = rdata;
                        }
                }
        }
}


/*-------------------------------------------------
*  函数名: main
*        功能:  主函数
*  输入:  无
*  输出:  无
--------------------------------------------------*/
void main()
{
        POWER_INITIAL();            //系统初始化
        TIMER2_INITIAL();       //初始化T2
        
        while(1)
        {
                if(B_MainLoop)                                //2.5ms执行一次
                {
                        B_MainLoop = 0;
               
                        RecServer();                        //红外接收处理
                        //Led2 = 1;
                }
        }
}

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:607312 发表于 2021-7-6 09:16 | 只看该作者
代码是可以执行的遥控器短按,不过只能执行一次,如何做到长按递增或者递减呢
回复

使用道具 举报

板凳
ID:814525 发表于 2021-7-6 12:01 | 只看该作者
参考红外NEC通讯协议,有长按重复代码
回复

使用道具 举报

地板
ID:161164 发表于 2021-7-6 13:43 | 只看该作者
你先要知到短按和长按的红外编码的分别
回复

使用道具 举报

5#
ID:887202 发表于 2021-7-6 17:01 | 只看该作者
短按时发送一个完整的红外波形,包括引导码,用户码,键码,长按的时候会先发送一次完整的波形,然后就会一直发送重复码,不会再发送用户码和键码,所以区别长按和短按最好的方法就是去识别收到的波形时引导码还是重复码,因为引导码和重复码高电平分别为4.5ms和2.25ms,所以可在上升沿后定时器延时3.5ms,此时电平为高则是引导码,那么就可以正常解码,如果为低那么就是重复码
回复

使用道具 举报

6#
ID:887202 发表于 2021-7-6 17:02 | 只看该作者
短按时发送一个完整的红外波形,包括引导码,用户码,键码,长按的时候会先发送一次完整的波形,然后就会一直发送重复码,不会再发送用户码和键码,所以区别长按和短按最好的方法就是去识别收到的波形时引导码还是重复码,因为引导码和重复码高电平分别为4.5ms和2.25ms,所以可在上升沿后定时器延时3.5ms,此时电平为高则是引导码,那么就可以正常解码,如果为低那么就是重复码
回复

使用道具 举报

7#
ID:607312 发表于 2021-7-6 17:41 | 只看该作者
sadv 发表于 2021-7-6 17:01
短按时发送一个完整的红外波形,包括引导码,用户码,键码,长按的时候会先发送一次完整的波形,然后就会一 ...

大神可以在我的代码上班修改一下吗?让代码实现长短按
回复

使用道具 举报

8#
ID:607312 发表于 2021-7-6 17:42 | 只看该作者
lkc8210 发表于 2021-7-6 13:43
你先要知到短按和长按的红外编码的分别

怎么区分呢,指教一下,
回复

使用道具 举报

9#
ID:887202 发表于 2021-7-7 09:06 | 只看该作者
cdiyy 发表于 2021-7-6 17:41
大神可以在我的代码上班修改一下吗?让代码实现长短按

别人跟你改你是学不到东西的啦,要自己思考,理解红外协议,理解为一行代码作用是什么,这样子才算学到了。给你一份我用过的代码,因为我主函数里面处理的东西比较多,所以这里是直接在中断中解码的,低电平触发进中断。TR0,TL0是什么不用我说了,test[]这个数组主要是为了TH0<=X中X的值具体取多少而设置的,实际解码用不到的,把X的值都填上去以后可以注释掉。仔细看看吧,我觉得还是写的挺详细的了
       UINT8 i,j;
        TR0=0;  
        TL0=0;
        TH0=0;
        TR0=1;
        test[3]=P2;
        while((P2&0x20) ==0&&TH0<=0x4E);                //等待9ms低电平过去       
        test[4]=P2;
        test[1]=TH0;
        test[1] =test[1]<<8;
        test[1] |=TL0;
        if((P2&0x20))
        {
                TR0=0;
                TL0=0;
                TH0=0;
                TR0=1;
                while((P2&0x20)&&TH0<0x14);                //等待3ms高电平
                if(!(P2&0x20))                //查看IR电平状态,为低说明是重复码,退出函数
                {
                        return;
                }       
                TR0=0;
                TL0=0;
                TH0=0;
                TR0=1;
                while((P2&0x20)&&TH0<0xF);                //等待2ms高电平
                test[5]=P2;
                test[2]=TH0;
                test[2] =test[2]<<8;
                test[2] |=TL0;
                for(i=0;i<4;i++)
                {
                        for(j=0;j<8;j++)
                        {
                                TR0=0;
                                TH0=0;
                                TL0=0;
                                TR0=1;

                                while((P2&0x20)==0&&TH0<=5);                //等待560us低电平过去
                                while((P2&0x20));                               
                                IR_DATA>>=1;
                                if(TH0>=13)
                                {
                                        IR_DATA|=0x80;
                                       
                                }
                        }
                }
                it_flag=1;
        }
        else
                error1=1;
回复

使用道具 举报

10#
ID:607312 发表于 2021-7-7 10:48 | 只看该作者
sadv 发表于 2021-7-7 09:06
别人跟你改你是学不到东西的啦,要自己思考,理解红外协议,理解为一行代码作用是什么,这样子才算学到了 ...

感谢大神,在你这个参考上我完美的解决长按了,不过还不是很灵敏,我再调试一下,感谢感谢
回复

使用道具 举报

11#
ID:951816 发表于 2021-7-11 16:28 | 只看该作者
简单点的话,其实也可以用定时器,比如你定时器记一个time的数,那么在整个遥控的过程中,time不会大于( 隔110ms左右发一次引导码(重复),并不带任何数据(全部为高电平))150/256us约等于600,那么你在一个循环里就可以写 ps:定时器我用的8位自动重装
if(time<600)
回复

使用道具 举报

12#
ID:548551 发表于 2021-7-11 16:41 | 只看该作者
FMD 的单片机?
回复

使用道具 举报

13#
ID:61261 发表于 2021-7-12 07:46 | 只看该作者
添加计时器也是不错的办法
回复

使用道具 举报

14#
ID:781863 发表于 2021-7-29 14:01 | 只看该作者
长按的话,可以用mode的形式,定义一个mode全局变量,正点原子那个有参考的
回复

使用道具 举报

15#
ID:954677 发表于 2021-7-29 19:17 | 只看该作者
定时器和按键触发延时
回复

使用道具 举报

16#
ID:607312 发表于 2021-7-31 09:27 | 只看该作者
1024153202 发表于 2021-7-29 14:01
长按的话,可以用mode的形式,定义一个mode全局变量,正点原子那个有参考的

用链接吗?
回复

使用道具 举报

17#
ID:948865 发表于 2021-7-31 23:19 | 只看该作者
增加定时器程序,等到按键按下后监测按键时长,等到按键弹起停止计时,每次计数完成记得清零
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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