• 51单片机学习笔记(清翔版)(23)——红外通讯


    DS18B20课后题:

    负数以补码形式存在的。

    如果是负数,那么S全为1,前面那些不看,我们只看最后一个S,当它为1时,那么就是0x08,所以只要高8位大于等于0x08,就是负数。

    其中s=0x40这里

    上面打错了,如果不是负数,则s=0,则不显示负号,如果是负数,就执行else的语句。

    温度达不到零下怎么显示呢?模拟

    这里是错的,所以中文手册会出错,要参照英文手册。

    错的是16进制,应该是FE6F


    开始红外通讯

    红外遥控广泛用于家庭中,体积小,抗干扰强,功能强,功耗低,成本低

    开发板带有红外接收和红外发射功能

    自学习型万能遥控器源代码,下载到开发板运行后,拿电视机遥控器对着开发板按下开关机键,开发板就能把开关机键代码解码,同时按下矩阵键盘某个按键,这个按键就有了电视机遥控器开关机键的功能,并且断电后学习到的数据不会丢失,因为程序把解码的程序储存到EEPROM中,只要是NEC协议的红外遥控器,开发板都可以解码,复制到开发板按键上。这就是万能遥控器。

     红外发射电路用的红外发射二极管,发红外光,特殊颜色的普通光,可见光谱之下,即眼看不到它发光。

    解码芯片用单片机解码。应用电路就随机了,例如遥控器按下后,流水灯亮,流水灯就是应用电路。

    上图右侧为一体化红外接收头。就是U6这个器件。

    1脚将接收到的红外信号放大解调后输出,我们把数据送给了P32,便于我们编写程序解码。

    可参考那个电路,也可参考芯片手册的电路:

    红外通讯没有射频模块做的好用,红外光会被东西挡到。

    红外通讯流程:

    红外发射装置:键盘编码调制,送给红外发射管,然后发射出去。例如我按下了CH-,右边是对应的键值码,即45,16进制,然后编码芯片就会对它进行编码、调制,然后送给发射管,在发射出去。

    红外接收装置:接收到信号后,放大、解调,然后输出给解码芯片解码。

    我们输出给P32,由单片机解码。

    信号的调制和解调是红外通讯的基本原理。

    将我们要发送的数据,也就是我们说的基带二进制信号,调制为38.41kHz的载波信号,然后发射出去。

    红外接收设备接收到信号后要还原为我们发射的数据,也就是解调。目前大部分红外接收设备都是用的一体化红外接收头进行解调。

    调制主要是像我们看的那个自学习型万能遥控器程序,编码和调制都需要通过单片机进行。

    接下来看看编码和解码:

    以我们目前这红外遥控系统为例,红外发射就不用考虑了,遥控器就是一个完整的红外发射器件,任意按下某个按键,遥控器就会把这按键的值进行编码调制发射。

    接收端我们用了一体化接收头,接收到信号后,把这个信号放大解调,输出给单片机,我们写程序解码。要解码我们首先要知道是如何编码的,我们遥控器使用的NEC编码协议,要解码这个发出的数据,我们要先了解这个NEC协议。如果不知道遥控器(红外发射器件)是NEC协议的该怎么知道呢?我们可以用示波器或逻辑分析仪,把红外信号通过一体化接收头解调后的信号,把编码抓出来,之后分析是哪种协议。这是用逻辑分析仪分析的。

    之前说了调制是为了信号更好的传输,那么为什么要编码呢?如果不编码,会出现这种情况,抽屉里有空调和电视机,我用空调的遥控器按下开机键,想打开空调,结果都打开了,这就是为了区分不同机器类型,才将信号按照一定规律进行编码传输。现在不论是业余还是专业制作,都是用的编码芯片。不同的编码芯片编码协议不同。NEC是最广泛的。日本人定的。

    空调遥控器的红外通讯,红外编码通常是用遥控器内单片机特定的编码,编码协议是自己定制的,不同厂家编码协议不一样。不过编码调制后基本都在38kHz频率上发射的。

    所以我们也可以通过一体化接收头,把它解调出来,要想知道如何解码,就要用逻辑分析仪或示波器抓出来,分析编码规律。

    NEC的编码完成后,所要发送的基带二进制编码通常有30多位。空调编码完后有100多位。

    NEC

    开始会有一段引导码,是有规定的,高电平9000微秒左右,低电平4500微秒。

    只有两个8位的用户码。也是为了区分不同器件,例如两台电视机,不同品牌,都使用的NEC协议,为了不串用,厂家用户码做的就不一样。

    在之后就是8位数据码和数据反码,数据码就是键值码,反码是为了校验前面8位是否正确的。

    数据是一位一位发送的。

    为了更形象化,我们把遥控器所发送的键值,通过开发板一体化接收头解调出来后,把基带二进制码通过示波器抓出来。开发板和逻辑分析仪接好。

    发送和接收那端,起始码高电平在8~10ms就可以。

    所有的起始码,用户码,数据码和数据反码都能分析出来。

    程序根据波形建立起一个思路,红外接收头的输出端,解调后输出给P32,有第二功能外部中断0,可以配置在跳边沿触发,来一个低电平触发一次,触发时我们就启动定时器,在它下次再次触发时,定时器在这期间走的数,我们取出来,就能知道脉冲有多宽。

    比如从这到这,看到有多长就能知道这是起始码。之后是判断0还是1,0约是1.125ms宽,1约是2.25ms宽。通过这种方法让单片机充当解码芯片,把红外遥控器键值解码出来。

    这里起始码后只有32位数据,空调遥控器就长了,有100多位。

      

    如果有告诉是某品牌的编码规律是怎么样的,还简单一点,否则只能一点一点分析找出规律。

    解码后也可以用单片机把键值码学习下来,按照这个规律重新编码,编码完成后用定时器调制到38k这频率通过红外发射头发射,就可以遥控空调。


     编程,接收到红外信号后,把数据通过NEC协议规定解码,之后让串口以9600波特率发出,用计算机串口助手显示。

     写之前在梳理下思路:

    一体化红外接收头输出端接到了P32,第二功能是外部中断0,可以设置外部中断为跳边沿模式,来一个低电平触发一次,触发外部中断时让定时器开始计数,当下次再触发时,就可以读取计时器所计的数值,就可以计算出上一次脉宽的持续时间,根据时间确认是引导码(13.5ms左右)、数据0(1.125ms左右)或者数据1(2.25ms左右)。

    为了更形象,我们通过逻辑分析仪先把红外数据的波形抓出来,通过波形一边写程序一边讲解。

    先是起始码,从1这里触发外部中断,开启定时器,2这里再次触发,就把定时器走的数读取出来,计算出持续时间,并且把定时器走数的值清0,再开始加,定时器一直不关,到下一次触发外部中断,再一次计算持续时间。

      1 #include <reg52.h>
      2 
      3 #define uchar unsigned char
      4 #define uint  unsigned int
      5 sbit P10=P1^0;
      6 uchar IRtime;    //储存检测红外高低电平持续时间
      7 uchar IRcord[4]; //储存解码后的4个字节数据
      8 uchar IRdata[33];//包含起始码在内的33位数据
      9 bit IRpro_ok;    //解码后4个字节数据接收完成标志位
     10 bit IRok;        //33位数据接收完成标志位
     11 
     12 void init()
     13 {
     14     TMOD|=0x02;//设置定时器0工作模式2,8位自动重装
     15     TL0=TH0=0;//初始化定时器0寄存器,定时器0溢出一次时间为256个机器周期
     16     EA=1;
     17     ET0=1;
     18     TR0=1;
     19     
     20     IT0=1;//设置外部中断0跳边沿触发方式
     21     EX0=1;
     22     
     23     TMOD|=0x20;//设置定时器1工作模式2,8位自动重装
     24     TL1=TH1=0xfd;//比特率9600
     25     SM1=1;SM0=0;//设置串口工作模式1,10位异步收发
     26     TR1=1;
     27 }
     28 
     29 //定时器中断,每中断一次需要256*1.085us=277.76us(256个机器周期,晶振频率位11.0592Mhz,机器周期=12*晶振周期)
     30 void time0() interrupt 1
     31 {
     32     IRtime++;//277.76us
     33 }
     34 
     35 //外部中断0存入33次脉宽
     36 void int0() interrupt 0
     37 {
     38     static uchar i;//静态变量用于存入33次数据计数
     39     static bit startflag;//开始储存脉宽标志位
     40     if(startflag)//标志被置1则开始存储33次脉冲宽度,一位一位存
     41     {
     42         if((IRtime<53)&&(IRtime>=32))i=0;//判断引导码,如果是引导码则从起始码开始存
     43         IRdata[i]=IRtime;//以T0溢出的次数来计算脉宽把这个时间存放在数组
     44         IRtime=0;//计数清零
     45         i++;//计数脉宽存入次数自加
     46         if(i==33)//i=33就表示已经存入了33次脉宽
     47         {
     48             IRok=1;//脉宽检查完成
     49             i=0;//把脉宽计数清零准备下次存入
     50         }
     51     }
     52     else
     53     {
     54         IRtime=0;//定时器0计数清零,因为初始化时就启动了,即使没有收到红外数据也再加
     55         startflag=1;//开始处理标志位置1
     56     }
     57 }
     58 
     59 //把提取的33次脉宽解码 NEC协议
     60 void IRcordpro()
     61 {
     62     uchar i;//计数处理4个字节
     63     uchar j;//用于处理1个字节的8位数据
     64     uchar k;//用于计数处理33次脉宽
     65     k=1;//从第一位脉宽开始处理,丢掉起始码
     66     for(i=0;i<4;i++)
     67     {
     68         for(j=0;j<8;j++)
     69         {
     70             if(IRdata[k]>5)    IRcord[i]|=0x80;//如果脉宽大于数据0标准的1125us那么就判断为数据1
     71             
     72             if(j<7)    IRcord[i]>>=1;//只能移动7次,防止最后一位移出
     73             k++;//处理下一次脉宽
     74         }
     75     }
     76     IRpro_ok=1;//解码完成
     77 }
     78 
     79 void main()
     80 {
     81     uchar i;//计数串口发送字节数
     82     init();
     83     while(1)
     84     {
     85         if(IRok)//判断33次脉宽是否提取完成
     86         {
     87             IRcordpro();//根据脉宽解码出4个字节数据
     88             IRok=0;//清零脉宽检查完成标志位等待下一次脉宽检查
     89             if(IRpro_ok)//判断是否解码完成
     90             {
     91                 if(IRcord[2]==0x45)P10=!P10;//若是CH-按键则亮第一个灯
     92                 for(i=0;i<4;i++)//串口发送4个字节数据
     93                 {
     94                     SBUF=IRcord[i];//发送数据
     95                     while(!TI);//等待发送完成标志
     96                     TI=0;//清零发送完成标志位
     97                 }
     98                 IRpro_ok=0;//清零解码完成标志位
     99             }
    100         }
    101     }
    102     
    103 }
  • 相关阅读:
    Java设计模式之单例模式
    docker常用命令2
    Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate';
    Apache RocketMQ在linux上的常用命令
    RocketMQ的broker启动失败解决
    xshell与xftp使用注意
    Springboot项目打包成jar运行2种方式
    docker常用命令记录
    MySql常用语句总结更新
    springboot启动报错start bean 'eurekaAutoServiceRegistration' NullPointerException
  • 原文地址:https://www.cnblogs.com/IceHowe/p/10834585.html
Copyright © 2020-2023  润新知