打印
[经验分享]

89C51单片机之红外通信

[复制链接]
51|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2025-1-22 10:24 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一、概述
常见的红外线遥控器:空调遥控器,电视机遥控器。

1.1、什么是红外线
人眼可见光按波长从长到短排列,依次为:红、橙、黄、绿、青、蓝、紫。
红光的波长范围为0.62~0.76um(微米)。
紫光的波长范围位0.38~0.46um(微米) 。       1米(m)=1000000微米(um)
比紫光波长还短的叫紫外线。
比红光波还长的叫红外线。
红外线遥控就是利用波长位0.76~1.5um(微米)之间的近红外线来传送控制信号的。
1.2、红外系统的组成
红外系统的组成:红外发射装置和红外接收设备两大部分组成。
红外发射装置的组成:由键盘电路、红外编码芯片、电源和红外发射电路组成。
红外接收设备的组成:红外接收电路、红外解码芯片、电源和应用电路组成。
通常为了使信号更好的被发射端发送出去,经常会将二进制数据信号调成位脉冲信号,通过红外发射管发射。
脉冲信号调制的两种方式:
通过脉冲宽度来实现信号调制的脉宽调制(PWM)。
通过脉冲串之间的时间间隔来实现信号调制的脉时调制(PPM)。
二、红外发射管
红外遥控发射装置(红外遥控器):由红外编码电路,键盘电路,电源电路和红外发射电路组成。
红外发射电路的主要元件:红外发光二极管。实质是一只特殊的发光二极管。
红外发光二极管内部材料不同于普通的发光二极管,在其两端施加一定电压时,便发出红外线,而不是可见光。
目前红外发光二极管发出的红外线波长为940左右,其外形与普通φ5发光二极管相同。



三、红外遥控器发射
红外遥控器为了提高抗干扰性能和降低电源消耗;红外遥控器常用的载波方式传送二进制编码,常用的载波频率为38KHz,由发射端所使用的455kHz晶振来决定的。
发射端要对晶振进行整数分频,分频系数一般采取12,所以455kHz/12  约为  37.9kHz  取整四舍五入38kHz.
也有一些遥控系统采用36kHz、40kHz、56kHz等,一般由发射短晶振的振荡频率来决定。
通常的红外遥控器是将遥控信号(二进制脉冲码),调制在38KHz的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去。
二进制脉冲的形式有多种,其中最为常用的是PWM码(脉冲宽度调制码)和PPM码(脉冲位置调制码,脉冲串之间的时间间隔来实现信号调制)
如果要开红外接收设备,一定要直到红外遥控器的编码方式和载波频率,选取一体红外接收头和制定解码方案。




四、红外线接收
红外接收设备的组成:由红外接收电路,红外解码,电源和应用电路组成。

红外遥控器接收器的主要作用是将遥控器发射出来的红外信号转换位电信号,再放大、限幅、检波,整形、形成遥控指令脉冲,输出至遥控微处理器。

成品红外接收头的封装有两种:一种由铁皮屏蔽;一种是塑料封装;有三只脚,即电源正(VDD)、电源负(GEN)和数据输出(VOUT)。

注意:成品红外接收头的载波频率,另外在遥控编码芯片输出的波形与接收头端接收到的波形。



五、数据格式



数据格式:由引导码(起始码)、用户码、数据码和数据码反码组成,编码总占领32位。
数据反码:是数据码反相后的编码,编码用于对数据的纠错。
注意:第二阶段的用户码也可以在遥控应用中被设置成第一段用户码的反码。
数据码:    1111 0000
数据码反码:   0000 1111


六、位定义
用户码或数据码中的每一个位可以是‘1’,也可以是位‘0’。区分‘0’和‘1’是利用脉冲的时间间隔来区分,这种编码方式称为脉冲位置调制方式,英文简写PPM。(红外遥控器的编码方式)



由上图可区分,位0和位1;位0和位1的低电平时间相同,高电平时间不同,位0高电平持续时间为0.56ms,位1高电平时间为1.69ms,但也不是绝对的,如位0高电平持续时间在0.56ms上下浮动,故而取0.56~1.69ms中间值,1ms.

高电持平续时间 >1ms时  为位1
高电平持续时间<1ms时    为位0
七、硬件设计
该电路是集成的,红外接收头的输出管脚接至单片机 P32 管脚上,为了保证红外接收头输出管脚默认为高电平,需外接一个上拉电阻,同 样的与单片机 IO 口连接就相当于外接了 10K 上拉电阻。 由于该模块电路是集成的,所以红外接收头的输出管脚与单片机 P32 管脚连接使用即可。





八、软件设计


/*
       1,单片机-->红外接收模块
                                   P32-->J11
                   2,单片机-->动态数码管模块
                                   J22-->J6
                                P22-->J9(A)
                                P23-->J9(B)
                                P24-->J9(C)       
*/

#include "reg52.h"                         //此文件中定义了单片机的一些特殊功能寄存器
       

typedef unsigned int u16;          //对数据类型进行声明定义
typedef unsigned char u8;

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

sbit IRIN=P3^2;

u8 IrValue[6];
u8 Time;

u8 DisplayData[8];
u8 code smgduan[17]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0X76};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F、H的显示码

/*******************************************************************************
* 函 数 名         : delay
* 函数功能                   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
        while(i--);       
}


/*******************************************************************************
* 函数名         :DigDisplay()
* 函数功能                 :数码管显示函数
* 输入           : 无
* 输出                  : 无
*******************************************************************************/
void DigDisplay()
{
        u8 i;
        for(i=0;i<3;i++)
        {
                switch(i)         //位选,选择点亮的数码管,
                {
                        case(0):
                                LSA=1;LSB=1;LSC=1; break;//显示第0位       
                        case(1):
                                LSA=0;LSB=1;LSC=1; break;//显示第1位
                        case(2):
                                LSA=1;LSB=0;LSC=1; break;//显示第2位
                }
                P0=DisplayData;//发送数据
                delay(100); //间隔一段时间扫描       
                P0=0x00;//消隐
        }               
}


/*******************************************************************************
* 函数名         : IrInit()
* 函数功能                   : 初始化红外线接收
* 输入           : 无
* 输出                  : 无
*******************************************************************************/

void IrInit()
{
        IT0=1;//下降沿触发
        EX0=1;//打开中断0允许
        EA=1;        //打开总中断

        IRIN=1;//初始化端口
}


/*******************************************************************************
* 函 数 名       : main
* 函数功能                 : 主函数
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void main()
{       
        IrInit();
        while(1)
        {       
                DisplayData[0] = smgduan[IrValue[2]/16];
                DisplayData[1] = smgduan[IrValue[2]%16];
                DisplayData[2] = smgduan[16];
            DigDisplay();               
        }               
}

/*******************************************************************************
* 函数名         : ReadIr()
* 函数功能                   : 读取红外数值的中断函数
* 输入           : 无
* 输出                  : 无
*******************************************************************************/

void ReadIr() interrupt 0
{
        u8 j,k;
        u16 err;
        Time=0;                                         
        delay(700);        //7ms
        if(IRIN==0)                //确认是否真的接收到正确的信号
        {         
               
                err=1000;                                //1000*10us=10ms,超过说明接收到错误的信号
                /*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
                侯,程序死在这里*/       
                while((IRIN==0)&&(err>0))        //等待前面9ms的低电平过去                 
                {                       
                        delay(1);
                        err--;
                }
                if(IRIN==1)                        //如果正确等到9ms低电平
                {
                        err=500;
                        while((IRIN==1)&&(err>0))                 //等待4.5ms的起始高电平过去
                        {
                                delay(1);
                                err--;
                        }
                        for(k=0;k<4;k++)                //共有4组数据
                        {                               
                                for(j=0;j<8;j++)        //接收一组数据
                                {

                                        err=60;               
                                        while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
                                        {
                                                delay(1);
                                                err--;
                                        }
                                        err=500;
                                        while((IRIN==1)&&(err>0))         //计算高电平的时间长度。
                                        {
                                                delay(10);         //0.1ms
                                                Time++;
                                                err--;
                                                if(Time>30)
                                                {
                                                        return;
                                                }
                                        }
                                        IrValue[k]>>=1;         //k表示第几组数据
                                        if(Time>=8)                        //如果高电平出现大于565us,那么是1
                                        {
                                                IrValue[k]|=0x80;
                                        }
                                        Time=0;                //用完时间要重新赋值                                                       
                                }
                        }
                }
                if(IrValue[2]!=~IrValue[3])
                {
                        return;
                }
        }                       
}


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/RONG_YAO/article/details/106157518

使用特权

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

本版积分规则

2086

主题

16074

帖子

15

粉丝