CSDN博客初识&&红外通信(51)学习心得

CSDN博客初识

了解CSDN内容

笔者于2019年经历高考,在暑假末尾接触到csdn,一开始是因为搜索C语言的相关题目,然后进一步了解发现csdn是一个广阔的学习平台。正如它的广告语,成就一亿技术人,在这里你能接触到更多更前端的资讯,成为你大学学习的跳板。
csdn

看博客学习相关知识

因为技术上还是太萌新,关注的内容也不广,只是一些皮毛,现在正从一些大佬的博客中摸索学习,先模仿再内化成自己的东西。

入手写博客用来总结及初步规划

结合个人学习方法和嵌入式等学习内容的特色,笔者打算今后把一些理解以博客形式记录总结,方便自己回顾。这一期是第一次用markdown写博客,是用最近小比赛涉及的红外通信环节的一些学习练手,并打算在2020年1月11号之前再写一篇关于51EEPROM(IIC总线)的个人学习理解。鉴于笔者学校进入考试月,时间紧张,文章略显准备不充足,求大佬勿喷。

Mon 09 Mon 16 Mon 23 Mon 30 Mon 06 单片机大赛已完成 博客进行中 pta即将进行 高数英语期末考 时间表 2020考试月规划


可能一些专有名词的拿捏不是很准确,请原谅。

下面是正文内容

51单片机的红外通信

基本内容

红外线遥控

由残存的高中物理知识,红外线遥控就是利用波长为0.76~1.5微米之间的近红外线来传送控制信号的。

红外线系统的组成

红外线系统一般由红外发射装置和红外接收设备两大部分组成。红外发射装置又可以由键盘电路、红外编码芯片、电源和红外发射电路组成。红外接收设备可以由红外接收线路红外解码芯片、电源和应用电路组成。通常为了使信号更好的被发射端发送出去,经常会将二进制数据信号调制成为脉冲信号,通过红外发射管发射。常用的有通过脉冲宽度来实现信号调制的脉宽调制(PWM)和通过脉冲串之间的时间间隔来实现信号调制的脉冲调制(PPM)两种方法。

红外遥控器发射

通常红外遥控为了提高抗干扰性能和降低电源消耗,红外遥控器常用载波的方式传送二进制编码,常用的载波频率为38KHZ,这是由发射端所使用的455KHZ晶振(晶振知识不作详细介绍,有意点击链接)来决定的。通常的红外遥控器是将遥控信号(二进制脉冲码)调制在38KHZ的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去的。
图为封装好的红外接收器:
现常用封装好的红外接收器

关键环节

中断
  • 本环节涉及计时要求,现引入中断部分知识。

红外脉冲使得红外接收头由高电平变低电平,所以产生一个下降沿,使得产生外部中断。

  • 红外接收头对应I/0口的P3^2引脚

在这里插入图片描述

  • 部分中断源暨中断号
    在这里插入图片描述
    根据引脚(P3^2)和中断引起原因(下降沿),在这里使用外部中断0,对应中断号为0。
void IrInit() 
{ IT0=1;//下降沿触发 
  EX0=1;//打开中断 0 允许
  EA=1; //打开总中断
  IRIN=1;//初始化端口
}

PPM方式的红外通信

本次红外遥控器使用的是NEC协议
特征如下:

  • 8位地址和8位指令长度(相当于豌豆射手一次吐八个豌豆);
  • 地址和命令2次传输(确保可靠性);
  • 载波频率38KHZ;
  • 位时间为1.125ms或2.25ms;
    在这里插入图片描述
  • 记住开头起始码的9ms和4.5ms低高电平升落
  • 数据反码相当于双重保险
  • 地址码,地址反码、控制码、控制反码均是8位数据格式。按照低位在前,高位在后的顺序发送。
  • 摁一次相当于八个脉冲串

NEC 码的位定义:一个脉冲对应 560us 的连续载波,
一个逻辑 0 的传输需要 1.125ms(560us脉冲+560us 低电平)
一个逻辑 1 传输需2.25ms(560us 脉冲+1680us 低电平)

时序图如下:(在低谷的时候是低电平,反之为高电平)在这里插入图片描述

位0位 1
低电平时间0.56ms0.56ms
高电平时间0.565ms1.69ms

由于红外接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,所以可以通过外部中断的下降沿触发中断,在中断内可以通过判断高电平时间来识别是位0还是位1

//延时函数
void delay(uint i)
{
delay(i--);        //延时儿~
}
//读取红外数值的中断服务函数
void ReadIr() interrupt 0 
{

   u8 j,k; 
   u16 YD; 
   Time=0;        //也可以定义静态变量static
   delay(700);    //7ms 
   if(IRIN==0)    //确认是否真的接收到正确的信号,接收到后电平由1到0      
   {
   YD=1000;      //1000*10us=10ms,超过说明接收到错误的信号 
/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环, 免得程序出错的时侯,程序死在这里*/
   while((IRIN==0)&&(YD>0))    // 等 待 前 面 9ms 的 低 电 平 过 去
       {
          delay(1);    //相当于特殊功能的延时
          YD--;
       } 
      if(IRIN==1) //如果正确等到 9ms 低电平。9ms:看红外时序图(NEC协议)
      { 
          YD=500; 
          while((IRIN==1)&&(YD>0))    //等待 4.5ms 的起始高电平过去
           {
             delay(1);
             YD--;
           }
          for(k=0;k<4;k++) //共有 4 组数据(时序图中用户码,数据码)
           { 
             for(j=0;j<8;j++) //接收一组数据           
              {
                 YD=60; 
                 while((IRIN==0)&&(YD>0))
                  //等待信号前面的 560us低电平过去
                  {
                    delay(1);
                    YD--;
                  }
                 YD=500; 
                 while((IRIN==1)&&(YD>0))   
                 //以下利用Time累加计算高电平的时间长度。
                  {
                    delay(10); //0.1ms 
                    Time++; 
                    YD--; 
                  if(Time>30)
                    { 
                     return; //大于,服务函数无效
                    }
                  }  
               IrValue[k]>>=1; //k 表示第几组数据 
               if(Time>=8) //如果高电平出现大于 565us,那么是 1 
               {
                 IrValue[k]|=0x80;    //据说用或运算稳健,其实也可以直接令其=1
               } 
                Time=0; //用完时间要重新赋值,笔者做c的题经常出错
              }
          }
   } 
             if(IrValue[2]!=~IrValue[3]) //控制码跟控制反码是否匹配
              { 
                return; //不匹配,服务函数无效
              }
  }
}
  • 用到的时间数据有,9ms,4.5ms,0.56ms,1.69||0.5625ms
  • 这里对时间的判断用到了模糊判断,毕竟机器的准确性和数值太小,难免有偏差,所以例如9ms我们采用一个10ms的延时去判断。
  • 对应逻辑位1和0对应高电平的时间0.565和1.69差别较大,我们可以采用一个中间数如0.8/0.9/1.0去区别
  • return的作用不太明显,这是因为服务函数没执行什么实体的工程,可以加一个动态数码管的按键读取或者是switch去遥控小车等来体现。

作品应用

实图

在这里插入图片描述
在这里插入图片描述

基本功能

红外循迹的传感器不够灵敏所以在这里改成了红外通信的遥控,也没啥花里胡哨的,就是用服务函数返回的参数来switch判断哪哪哪电机咋转

主要代码部分
void IrInit() //中断函数
{ IT0=1;//下降沿触发 
  EX0=1;//打开中断 0 允许
  EA=1; //打开总中断
  IRIN=1;//初始化端口
}
void delayms(u8 i)//延时函数
{   i*=1000i;
    while(i--);                                       //延时1ms
}
void ReadIr() interrupt 0//红外键值中断服务函数                      
{
    u8 j,k,YD=0;                                        //相关临时变量
    EX1 = 0;                                            //关闭外部中断,防止再有信号到达   
    delayms(15);                                        //延时时间,进行红外消抖
    if (IRIN==1)                                        //判断红外信号是否消失,真则无效重来
     {  
      EX1 =1;                                          //外部中断1开
	  return;                                          //返回
     } 
                           
     while (!IRIN)                                       //等IR变为高电平,跳过9ms的前导低电平信号。
     {
        delayms(1);                                     //延时等待,稍作改进,不再盲等,见机行事
     }

  for (j=0;j<4;j++)                                   //采集红外遥控器4组数据
  { 
    for (k=0;k<8;k++)                                 //分次采集8位数据
    {
       while (IRIN)                                   //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
       {
         delayms(1);                                  //延时等待
       }
       
       while (!IRIN)                                  //等 IR 变为高电平
       {
         delayms(1);                                  //延时等待
       }
   
       while (IRIN)                                   //计算IR高电平时长
       {
         delayms(1);                                  //延时等待
         YD++;                                        //计数器加加
         if (YD>=30)                                   //判断计数器累加值
	     { 
           EX1=1;                                     //打开外部中断功能
	       return;                                    //返回
         }                   
       }
                                       
      IrValue[j]=IrValue[j] >> 1;                       //进行数据位移操作并自动补零
     
      if (YD>=8)                                       //判断数据长度 
      {
         IrValue[j] |= 0x80;                           //数据最高位补1
      } 
      YD=0;                                            //清零位数计录器
    }
  }
   
  if (IrValue[2]!=~IrValue[3])                            //判断地址码是否相同
  { 
     EX1=1;                                           //打开外部中断
     return;                                          //返回
  }

  for(j=0;j<10;j++)                                   //循环进行键码解析,比上面多的部分
   {
      if(IrValue[2]==controlduan[j])                       //进行键位对应,红外遥控器用数组controlduan,相应的8位二进制数对应特殊功能
      /*u8 code controlduan[]={0x19,0x46,0x15,0x44,0x43,0x40,0x0D,0x0E,0x00,0x0F}这是摁键二进制数的库*/
      {
        ControlCar(j);                                          //控制相应电机顺便用数码管显示方便判断摁键功能
      }
   }
   EX1 = 1;                                           //外部中断开,准备下一次 
} 
void ControlCar(u8  ConType)    //采集键值实现功能函数
{
 
  tingzhi();
 switch(ConType)                             //判断摁键对应模式
 {
  case 1:  //前进                            //形式1
  { 
    
	tingzhi();						        //进入前进之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位(从别处学来,不过可以不用)
	Delay1ms(240);					  
	qianjin();
    break;
  }
  case 2: //后退                              //形式2
  { 
    tingzhi();							      //进入后退之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
	Delay1ms(240);	 
	houtui();                                //M2电机反转
    break;
  }
  case 3: //左转                              //形式3
  { 
    tingzhi();								  //进入左转之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
	Delay1ms(240); 
	zuozhuan90(0);                            //M2电机正转
	break;
  }
  case 4: //右转                              //形式4
  { 
    tingzhi();								  //进入右转之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
	Delay1ms(240);
	youzhuan90(0);                                //M1电机正转  //M2电机反转
	break;
  }
  case 6:                                      //形式6
  { 
    tingzhi();								  //进入右转之前 先停止一段时间  防止电机反向电压冲击主板 导致系统复位
	Delay1ms(240);
	youzhuan30(0);                                //M1电机正转  //M2电机反转
	break;
  }	

  case 5: //停止                          //形式5
  {
    tingzhi();
	break;                                //退出当前选择
  }
 }
}
  • 相关引脚的注释和一些浅易函数名作用不再给出,关键是代码部分。

疑问&改善

  • 对于误差模糊处理想法很好,但是不知道这个误差的积累会不会对连续判断产生影响。
  • 功能太过简单,自己说萌新菜鸡其实是给自己不求上进找借口,求学长大佬放过。
  • 回归上文,这次以练手为主,写的太过冗长,不精炼
  • 听学长说可以加个PID实现闭环更加牛批的效果,小生还需努力,弥补差距。
  • 借老爸一句话:奋斗吧,少年!
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值