打印
[应用方案]

红外遥控小车,实现松手检测程序

[复制链接]
571|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
everyrobin|  楼主 | 2023-10-22 15:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


需要在外部中断0,增加一个定时器,在确定是红外引导码之后,开启定时器,只要是定时器的时间超过130ms,那么就退出红外模式,因为红外有个重复码发送是108ms所以定时器的时间要大于108ms,这样可以实现红外遥控松手检测,长按也可以执行,松手就不执行 ,代码如下:
/*-----------------------------------------------
  名称:红外遥控
------------------------------------------------*/
#include "IR.h"
#include "delay.h"
#include "1602.h"
unsigned int num=0; //超时计数器
unsigned int ir_flag=0;//红外标志位
//用于存放地址码、地址反码、控制码、控制反码
unsigned char Ired_Data[4],Ired_Data1[4];
//红外遥控管脚位定义
sbit IRED=P3^2;
sbit IN1 =        P1^2; // 高电平1 后退(反转)
sbit IN2 =  P1^3; // 高电平1 前进(正转)
sbit IN3 =        P1^4; // 高电平1 前进(正转)
sbit IN4 =  P1^5; // 高电平1 后退(反转)
sbit EN1 =        P3^0;  // 高电平使能
sbit EN2 =  P3^1;        // 高电平使能
extern unsigned char S1,cunt;
void hongwai(void)
{      
        stoprun();//关闭电机,防止上电电机转动
        if(ir_flag) //判断是否接收到红外遥控器数据
  {
                switch(Ired_Data[2])
                        {
                                case 0x00:stoprun();break;
                                case 0x45:S1++;if(S1>=4)S1=1;LCD_Clear(); break;
                                case 0x46:LCD_Write_Char(15,1,'b'); break;
                                case 0x47:LCD_Write_Char(15,1,'c'); break;
                                case 0x44:LCD_Write_Char(15,1,'d'); break;
                                case 0x40:LCD_Write_Char(15,1,'e'); break;
                                case 0x43:LCD_Write_Char(15,1,'f'); break;
                                case 0x07:cunt--;if(cunt<=0)cunt=99;LCD_Write_Char(15,1,'g');  break;
                                case 0x15:cunt++;if(cunt>=100)cunt=0;LCD_Write_Char(15,1,'h'); break;
                                case 0x09:LCD_Write_Char(15,1,'i'); break;
                                case 0x16:LCD_Write_Char(15,1,'0'); break;
                                case 0x19:LCD_Write_Char(15,1,'j'); break;
                                case 0x0d:LCD_Write_Char(15,1,'k'); break;
                                case 0x0c:LCD_Write_Char(15,1,'1'); break;
                                case 0x18:LCD_Write_Char(15,1,'2');run(); break;
                                case 0x5e:LCD_Write_Char(15,1,'3'); break;
                                case 0x08:LCD_Write_Char(15,1,'4');leftrun(); break;
                                case 0x1c:LCD_Write_Char(15,1,'5');stoprun(); break;
                                case 0x5a:LCD_Write_Char(15,1,'6');rightrun();break;
                                case 0x42:LCD_Write_Char(15,1,'7'); break;
                                case 0x52:LCD_Write_Char(15,1,'8');backrun(); break;
                                case 0x4a:LCD_Write_Char(15,1,'9'); break;
                          default:break;
                        }      
    }
        else //未接收到红外遥控器数据时,电机停止
        {
                stoprun();
        }      
}


//小车前进函数
void run(void)
{
   IN1=0;                //左电机
         IN2=1;
         IN3=1;                //右电机
         IN4=0;
   EN1=1;
         EN2=1;
}

//小车后退函数
void backrun(void)
{
   IN1=1;                //左电机
         IN2=0;
         IN3=0;                //右电机
         IN4=1;
         EN1=1;
         EN2=1;
}
//小车左转函数
void leftrun(void)
{
   IN1=0;                //左电机
         IN2=0;
         IN3=1;                //右电机
         IN4=0;
         EN1=1;
         EN2=1;
}
  //小车右转函数
void rightrun(void)
{
   IN1=0;                //左电机
         IN2=1;
         IN3=0;                //右电机
         IN4=0;
         EN1=1;
         EN2=1;
}
   //小车停止函数
void stoprun(void)
{
   IN1=0;                //左电机
         IN2=0;
         IN3=0;                //右电机
         IN4=0;
         EN1=1;
         EN2=1;
}

/*------------------------------------------------
                 中断初始化
------------------------------------------------*/
void Ired_Init()
{
        TMOD|=0x01; //定时器0工作在模式1(16位定时器模式)
  TH0=(65536-9173)/256; //设置定时器初值,需根据实际情况调整参数 定时10ms
  TL0=(65536-9173)%256; //设置定时器初值,需根据实际情况调整参数
  EA=1;     //打开总中断
  TR0=1; //启动定时器0
        IT0=1;    //下降沿触发
        EX0=1;    //打开中断 0 允许
        IRED=1;   //初始化端口
}

void Ired() interrupt 0    //外部中断 0 服务函数
{
        unsigned char Ired_Hight_Time=0;
        unsigned char i,j;
        unsigned int Time=0;
                if(IRED==0)
        {
                Time=1000;
                while((IRED==0)&&(Time!=0))   //等待引导信号 9ms 低电平结束,若超过 10ms 强制退出
                {
                        delay1(1);     //延时约 10us
                        Time--;   
                        if(Time==0)
                                return ;
                }
                if(IRED==1)    //引导信号 9ms 低电平已过,进入高电平,2.25ms的为重复码,4.5ms的为数据码
                {      
                        ir_flag=1; //红外遥控器数据接收标志位开启
                        ET0=1;//开启定时器
                        num=0;//计时清0
                        delay1(250);  //延时2.5ms判断红外口是不是低电平,如果是低电平则为重复码,如果是在2.5ms没有低电平则判断是不是到了4.5ms的数据码
                        if(IRED==0)
                        {
                            Ired_Data[2]=Ired_Data1[2];//把上一次的值赋值到重复码这里
                                   return ;//必须要加退出,不然进入中断会错误
                        }
                        Time=250;//再计算2.5ms判断是否有低电平产生,如果超时就退出,如果在2.5ms内有低电平则为数据码,因为之前已经延时了2.5ms,所以再加2.5ms判断
                        while((IRED==1)&&(Time>=0))   //等待引导信号 4.5ms 高电平结束,如超过 5ms 强制退出
                        {
                                delay1(1);
                                Time--;
                                if(Time==0)
                                        return ;
                        }
                       

        //地址码,反地址码,控制码,反控制码的收集
                        for(i=0;i<4;i++)   //循环 4 次,读取 4 个字节数据
                        {
                                for(j=0;j<8;j++)   //循环 8 次读取每位数据即一个字节
                                {
                                        Time=600;
                                        while((IRED==0)&&(Time!=0))    //等待数据 1 或 0 前面的 0.56ms 结束,若超过 6ms 强制退出
                                        {
                                                delay1(1);
                                                Time--;
                                                if(Time==0)
                                                        return;      
                                        }
                                        Time=20;
                                        while(IRED)  //等待数据 1 或 0 后面的高电平结束,若超过 2ms 强制退出
                                        {
                                                delay1(10);    //约 0.1ms
                                                Ired_Hight_Time++;
                                                if(Ired_Hight_Time>20)
                                                        return ;
                                        }
                                        Ired_Data[i]>>=1;   //先读取的为低位,然后是高位
                                        if(Ired_Hight_Time>=8)   //如果高电平时间大于 0.8ms,数据则为 1,否则为 0.
                                                Ired_Data[i]|=0x80;    //用或运算不影响其他位的数字
                                        Ired_Hight_Time=0;   //重新清零,等待下一次计算时间
                                }
                }
                Ired_Data1[2]=Ired_Data[2];//把采集的数据同时保存到另外一个数组,为下一次的重复码赋值使用
        }
                if(Ired_Data[2]!=~Ired_Data[3])   //校验控制码与反控制码,错误则返回
                {
                        for(i=0;i<4;i++)
                                Ired_Data[i]=0;
                        return ;
                }
        }
}

void INT_Timer0() interrupt 1 //定时器0中断函数
{
                TH0=(65536-9173)/256; //重新设定定时器初值10ms
                TL0=(65536-9173)%256; //重新设定定时器初值
          num++;
        if(num>=13)//130ms到了,没有红外按键按下,标志位清零,为什么要130ms,因为红外重复码是间隔108ms重发发送一次,所以要大于108ms,判断没有红外按下
                {
                        ir_flag=0; //清除红外遥控器数据接收标志位
                        num=0;//计时清0
                        ET0=0;//关闭定时器0中断
                }
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

1136

帖子

0

粉丝