[应用方案] 红外遥控小车,实现松手检测程序

[复制链接]
1267|0
 楼主| everyrobin 发表于 2023-10-22 15:00 | 显示全部楼层 |阅读模式


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


  58. //小车前进函数
  59. void run(void)
  60. {
  61.    IN1=0;                //左电机
  62.          IN2=1;
  63.          IN3=1;                //右电机
  64.          IN4=0;
  65.    EN1=1;
  66.          EN2=1;
  67. }

  68. //小车后退函数
  69. void backrun(void)
  70. {
  71.    IN1=1;                //左电机
  72.          IN2=0;
  73.          IN3=0;                //右电机
  74.          IN4=1;
  75.          EN1=1;
  76.          EN2=1;
  77. }
  78. //小车左转函数
  79. void leftrun(void)
  80. {
  81.    IN1=0;                //左电机
  82.          IN2=0;
  83.          IN3=1;                //右电机
  84.          IN4=0;
  85.          EN1=1;
  86.          EN2=1;
  87. }
  88.   //小车右转函数
  89. void rightrun(void)
  90. {
  91.    IN1=0;                //左电机
  92.          IN2=1;
  93.          IN3=0;                //右电机
  94.          IN4=0;
  95.          EN1=1;
  96.          EN2=1;
  97. }
  98.    //小车停止函数
  99. void stoprun(void)
  100. {
  101.    IN1=0;                //左电机
  102.          IN2=0;
  103.          IN3=0;                //右电机
  104.          IN4=0;
  105.          EN1=1;
  106.          EN2=1;
  107. }

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

  122. void Ired() interrupt 0    //外部中断 0 服务函数
  123. {
  124.         unsigned char Ired_Hight_Time=0;
  125.         unsigned char i,j;
  126.         unsigned int Time=0;
  127.                 if(IRED==0)
  128.         {
  129.                 Time=1000;
  130.                 while((IRED==0)&&(Time!=0))   //等待引导信号 9ms 低电平结束,若超过 10ms 强制退出
  131.                 {
  132.                         delay1(1);     //延时约 10us
  133.                         Time--;   
  134.                         if(Time==0)
  135.                                 return ;
  136.                 }
  137.                 if(IRED==1)    //引导信号 9ms 低电平已过,进入高电平,2.25ms的为重复码,4.5ms的为数据码
  138.                 {      
  139.                         ir_flag=1; //红外遥控器数据接收标志位开启
  140.                         ET0=1;//开启定时器
  141.                         num=0;//计时清0
  142.                         delay1(250);  //延时2.5ms判断红外口是不是低电平,如果是低电平则为重复码,如果是在2.5ms没有低电平则判断是不是到了4.5ms的数据码
  143.                         if(IRED==0)
  144.                         {
  145.                             Ired_Data[2]=Ired_Data1[2];//把上一次的值赋值到重复码这里
  146.                                    return ;//必须要加退出,不然进入中断会错误
  147.                         }
  148.                         Time=250;//再计算2.5ms判断是否有低电平产生,如果超时就退出,如果在2.5ms内有低电平则为数据码,因为之前已经延时了2.5ms,所以再加2.5ms判断
  149.                         while((IRED==1)&&(Time>=0))   //等待引导信号 4.5ms 高电平结束,如超过 5ms 强制退出
  150.                         {
  151.                                 delay1(1);
  152.                                 Time--;
  153.                                 if(Time==0)
  154.                                         return ;
  155.                         }
  156.                        

  157.         //地址码,反地址码,控制码,反控制码的收集
  158.                         for(i=0;i<4;i++)   //循环 4 次,读取 4 个字节数据
  159.                         {
  160.                                 for(j=0;j<8;j++)   //循环 8 次读取每位数据即一个字节
  161.                                 {
  162.                                         Time=600;
  163.                                         while((IRED==0)&&(Time!=0))    //等待数据 1 或 0 前面的 0.56ms 结束,若超过 6ms 强制退出
  164.                                         {
  165.                                                 delay1(1);
  166.                                                 Time--;
  167.                                                 if(Time==0)
  168.                                                         return;      
  169.                                         }
  170.                                         Time=20;
  171.                                         while(IRED)  //等待数据 1 或 0 后面的高电平结束,若超过 2ms 强制退出
  172.                                         {
  173.                                                 delay1(10);    //约 0.1ms
  174.                                                 Ired_Hight_Time++;
  175.                                                 if(Ired_Hight_Time>20)
  176.                                                         return ;
  177.                                         }
  178.                                         Ired_Data[i]>>=1;   //先读取的为低位,然后是高位
  179.                                         if(Ired_Hight_Time>=8)   //如果高电平时间大于 0.8ms,数据则为 1,否则为 0.
  180.                                                 Ired_Data[i]|=0x80;    //用或运算不影响其他位的数字
  181.                                         Ired_Hight_Time=0;   //重新清零,等待下一次计算时间
  182.                                 }
  183.                 }
  184.                 Ired_Data1[2]=Ired_Data[2];//把采集的数据同时保存到另外一个数组,为下一次的重复码赋值使用
  185.         }
  186.                 if(Ired_Data[2]!=~Ired_Data[3])   //校验控制码与反控制码,错误则返回
  187.                 {
  188.                         for(i=0;i<4;i++)
  189.                                 Ired_Data[i]=0;
  190.                         return ;
  191.                 }
  192.         }
  193. }

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


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

本版积分规则

35

主题

1658

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部