资讯详情

51单片机入门——红外通信

文章目录

  • 红外光的基本原理
  • 红外遥控通信原理
  • NEC协议

红外光的基本原理

红外线是微波和可见光之间波长的电磁波 760 纳米到 1 在毫米之间,波形长于红光。只要自然界中的物体温度高于绝对零度(-273),就会有分子和原子的不规则运动,其表面就会不断辐射红外线。当然,虽然它们都辐射红外线,但不同物体的辐射强度不同,我们利用这一点将红外技术应用于我们的实际开发。

红外发射管非常常用,在我们的遥控器上可以看到,它类似于发光二极管,但它发红外线,肉眼看不见。我们了解到,发光二极管的亮度会随着电流的增加而增加。同样,红外发射管的强度也会随着电流的增加而增加,如图所示:在这里插入图片描述 红外接收管内部具有红外光敏感 PN 节,属于光敏二极管,但只对红外光有反应。当没有红外光时,光敏管不导致,当有红外光时,光敏管导致形成光电流,并在一定范围内随着红外光强度的增加而增加。典型的红外接收管如图所示: 如图所示: 在上图中,发射控制和接收检测接收单片机 IO 口上的。

发射部分:当发射控制输出高电时,三极管 Q1 红外发射管不导通 L1 红外信号不会发射;当发射控制输出低电平时,通过三极管 Q1 导通让 L1 发出红外光。接收部分:R4 我们通过调整电位器电位器 LM393 的 2 脚提供阈值电压,可根据实际情况调试确定。红外光敏二极管 L2 当收到红外光时,会产生电流,随着红外光从弱到强,电流会从小变大。当没有红外光或红外光很弱时,3 脚的电压会接近 VCC,如果 3 脚比 2 如果脚的电压高,通过 LM393 比较器后,接收检测引脚输出高电平。当随着光强变大,电流变大,3 脚的电压值等于 VCC-I*R3.电压会越来越小程度时,电压会越来越小 2 脚的电压还小的时候,接收检测引脚就会变成低电平。

当该电路用于避障时,发射管首先发送红外信号。随着传输距离的增加,红外信号会逐渐衰减。如果遇到障碍物,会形成红外反射。当反射信号较弱时,光敏二极管 L2接收的红外光较弱,比较器 LM393 的 3 脚电压高于 2 脚电压,接收检测引脚输出高电平,表明障碍物较远;当反射信号较强时,接收检测引脚输出低电平,表明障碍物较近。

汽车跟踪时,必须有黑白轨道。当红外信号发送到黑色轨道时,黑色因为吸光能力比较强,红外信号发送出去后就会被吸收掉,反射部分很微弱。白色轨道会反射大部分红外信号。通常情况下的循迹小车,需要应用多个红外模块同时检测,从多个角度判断轨道,根据判断的结果来调整小车使其按照正常循迹前行。

红外遥控通信原理

在实际的通信领域,发出来的信号一般有较宽的频谱,而且都是在比较低的频率段分布大量的能量,所以称之为基带信号,这种信号是不适合直接在信道中传输的。为了便于传输,提高抗干扰能力,有效利用带宽,信号通常需要调制到适合信道和噪声特性的频率,称为信号调制。在通信系统的接收端,解调接收到的信号,恢复原始基带信号。了解这部分通信原理。我们通常使用红外遥控器中的红外通信 38K 左右载波调制,下面我给大家介绍一下原理,先看发送的原理。调制:用待传输信号控制高频信号的范围、相位、频率等参数变化的过程,即用一个信号装载另一个信号。例如,当我们的红外遥控信号需要发送时,首先通过 38K 如图所示: 原始信号是我们要发送的数据0位或数据1位 38K 载波是频率 38K 调制后的方波信号是我们最终发出的波形。我们使用原始信号来控制它 38K 载波,当信号为数据0时,38K 当信号为数据1时,,当信号为数据1时,不发送任何载波信号。

原则上,我们如何从电路的角度实现这一功能? 如下图所示: 38K 我们可以使用载波 455K 晶振,经过 12 分频得到 37.91K,也可以由时基电路 NE产生555,或使用单片机 PWM 来产生。当信号输出引脚输出高电时,Q2 截止,不管38K 如何控制载波信号? Q1.右侧的垂直支路不会导通,红外管 L1 不会发送任何信息。当信号输出为低电平时, 38K 载波会通过 Q1 释放,在 L1 上产生 38K 载波信号。这里需要注意的是,大多数家用电器遥控器 38K 的占空比是 1/3,也有 1/2 是的,但相对较少。

在正常通信方面,接收端应首先通过监控、放大、滤波、解调等一系列电路处理信号,然后输出基带信号。但红外通信的集成接收器 HS0038B,所有这些电路都集成在一起了。我们只需要连接这个电路,就可以直接输出我们想要的基带信号,如图所示: 由于红外接收头内部放大器增益大,容易造成干扰,因此必须在接收头供电引脚上添加滤波电容器,官方手册给出的值是 4.7uF,我们直接在这里使用 10uF,手册还要求电源引脚和电源串联 100 欧洲电阻,进一步减少干扰。

当上图所示的电路用于接收波形时 HS0038B 监测到有 38K在红外信号中, OUT 当没有引脚输出低电平时, 38K 的时候,OUT 引脚会输出高电平。然后我们把它拿走 OUT 引脚与单片机相连 IO 红外通信发送的数据可以通过口头编程获得。

大家想想,OUT 引脚输出的数据是否恢复为基带信号数据?当我们单片机接收基带信号数据时,如何判断接收到什么数据,应遵循什么协议?就像我们前面学到的 UART、I2C、SPI 等待通信协议是基带通信的通信协议,红外 38K 只调制基带信号,使信号更适合在信道中传输。

因为我们的红外调制信号是半双工的,同时空间只能允许一个信号源,所以红外基带信号不适合 I2C 或者 SPI 我们前面提到过的通信协议 UART 虽然是 2 但是通信的时候,其实一条线就够了,所以红外线可以在 UART 中间通信。当然,这种通信也不是没有限制的,比如HS0038B 在数据手册中注明,如果你想,你想 HS0038B 识别到 38K红外信号,所以这个 38K 载波必须大于 10 这限制了红外通信基带信号的比例不得高于 3800,如果直接使用串口输出的信号 38K 调制的话,波特率不能高于 3800。当然,还有许多其他基带协议可以通过红外调制。让我们介绍一种常用于遥控器的红外通信协议——NEC 协议。

NEC协议

家电遥控器的通信距离往往不高,红外线的成本远低于其他无线设备,因此红外线在家电遥控器的应用中一直占有一席之地。遥控器的基带通信协议很多,大概有几十种,常用 ITT 协议、NEC 协议、Sharp 协议、Philips RC-5 协议、Sony SIRC 协议等。最常用的是 NEC 协议了。

NEC 协议的数据格式包括引导码、用户码、用户码(或用户码反码)、按键码和键码反码,最后一个停止位。停车位主要起隔离作用,一般不判断,编程时也不理会。总共有数据编码 4 个字节 32 如图所示。第一个字节是用户代码,第二个字节也可能是用户代码,或用户代码的反向代码,具体由制造商决定,第三个字节是当前按钮的关键数据代码,第四个字节是关键数据代码的反向代码,可用于纠正数据错误。

这个 NEC 协议表味着数据的方式不像我们以前学到的那样 UART 如此直观,但每个数据本身也需要编码,然后编码载波调制。

  • :9ms 的载波 4.5ms 的空闲。
  • :560us 的载波 560us 的空闲。
  • :560us 的载波 1.68ms 的空闲。

结合上图,我们可以看到前面的黑色段落是指导码 9ms 载波,然后是引导码 4.5ms 后面的数据码是许多载波和空闲交叉,它们的长度取决于它们想要传递的具体数据。HS0038B 红外到载波信号时,红外集成接收器将输出低电平,并在业余时间输出高电平。我们用逻辑分析仪抓住红外按钮HS0038B 解码后的图形。 从图中可以看出,首先是 9ms 载波加 4.5ms 空闲的起始码,数据码是低位在前,高位在后,数据码第一个字节是 8 组 560us 的载波加 560us 空闲,也就是 0x第二个字节是00 8 组 560us的载波加 1.68ms 的空闲,可以看出来是 0xFF,这两个字节是用户码和用户码的反码。键码二进制是按键 0x0C,反码就是 0xF最后跟着一个 560us 载波停止。键码二进制是按键 0x0C,反码就是 0xF最后跟着一个 560us 载波停止位。对于我们的遥控器来说,不同的按钮是键码和键码反码的区别,用户码是一样的。这样,我们就可以通过单片机程序分析当前按键的键码。

当我们的学习中断时,我们学会了 51 单片机外部中断 0 和外部中断 1 这两个外部中断。我们的红外接收引脚收到了 P3.3 在引脚上,引脚的第二个功能是外部中断 1。在寄存器TCON 中的 bit3 和 bit2 这两个人与外部中断 1 相关两个。其中 IE1 这是外部中断标志位,当外部中断发生时,该标志位会自动移动 1.与定时器中断标志位置 TF 类似地,中断后会自动清零,软件也可以清零。bit2 如果设置外部中断类型,则设置外部中断类型 bit2 为 0,那么只要 P3.3 为低电平就可以触发中断,如果 it2 为 1,那么 P3.3 从高电平到低电平的下降沿发生才可以触发中断。此外,外部中断 1 使能位是 EX1。那下面我们就把程序写出来,使用数码管把遥控器的用户码和键码显示出来。

Infrared.c 文件主要是用来检测红外通信的,当发生外部中断后,进入外部中断,通过定时器 1 定时,首先对引导码判断,而后对数据码的每个位逐位获取高低电平的时间,从而得知每一位是 0 还是 1,最终把数据码解出来。虽然最终实现的功能很简单,但因为编码本身的复杂性,使得红外接收的中断程序在逻辑上显得就比较复杂,那么我们首先提供出中断函数的程序流程图,大家可以对照流程图来理解程序代码。

  • infrared.c
/* 本例程使用晶振为24MHz */
#include "infrared.h"
#include <reg52.h>

bit irflag = 0; //红外接收标志,收到一帧正确数据后置 1
unsigned char ircode[4]; //红外代码接收缓冲区

/* 初始化红外接收功能 */
void InitInfrared()
{ 
        
	IR_INPUT = 1; //确保红外接收引脚被释放
	TMOD &= 0xf0; //清零 T0 的控制位
	TMOD |= 0x01; //配置 T0 为模式 1
	TR0 = 0; //停止 T0 计数
	ET0 = 0; //禁止 T0 中断
	IT0 = 1; //设置 INT0 为负边沿触发
	EX0 = 1; //使能 INT0 中断
}

/* 获取当前高电平的持续时间 */
unsigned int GetHighTime()
{ 
        
	TH0 = 0; //清零 T0 计数初值
	TL0 = 0;
	TR0 = 1; //启动 T0 计数
	while (IR_INPUT) //红外输入引脚为 1 时循环检测等待,变为 0 时则结束本循环
	{ 
        
		if (TH0 >= 0x8c) //当 T0 计数值大于 0x8c00,即高电平持续时间超过约 18ms 时
		{ 
         
			break; //强制退出循环,是为了避免信号异常时,程序假死在这里。
		}
	}
	TR0 = 0; //停止 T0 计数
	return (TH0 * 256 + TL0); //T0 计数值合成为 16bit 整型数,并返回该数
}

/* 获取当前低电平的持续时间 */
unsigned int GetLowTime()
{ 
        
	TH0 = 0; //清零 T0 计数初值
	TL0 = 0;
	TR0 = 1; //启动 T0 计数
	while (!IR_INPUT) //红外输入引脚为 0 时循环检测等待,变为 1 时则结束本循环
	{ 
        
		if (TH0 >= 0x8c) //当 T0 计数值大于 0x8c00,即低电平持续时间超过约 18ms 时
		{ 
         
			break; //强制退出循环,是为了避免信号异常时,程序假死在这里。
		}
	}
	TR0 = 0; //停止 T1 计数
	return (TH0 * 256 + TL0); //T0 计数值合成为 16bit 整型数,并返回该数
}

/* INT1 中断服务函数,执行红外接收及解码 */
void EXINT1_ISR() interrupt 0
{ 
        
	unsigned char i, j;
	unsigned char byt;
	unsigned int time;
	 
	//接收并判定引导码的 9ms 低电平
	time = GetLowTime();
	if ((time < (8500 * 2)) || (time > (9500 * 2))) //时间判定范围为 8.5~9.5ms,
	{ 
         //超过此范围则说明为误码,直接退出
		IE0 = 0; //退出前清零 INT1 中断标志
		return;
	}
	//接收并判定引导码的 4.5ms 高电平
	time = GetHighTime();
	if ((time < (4000 * 2)) || (time > (5000 * 2))) //时间判定范围为 4.0~5.0ms,
	{ 
         //超过此范围则说明为误码,直接退出
		IE0 = 0;
		return;
	}
	//接收并判定后续的 4 字节数据
	for (i = 0; i < 4; i ++) //循环接收 4 个字节
	{ 
        
		for (j = 0; j < 8; j ++) //循环接收判定每字节的 8 个 bit
		{ 
        
			//接收判定每 bit 的 560us 低电平
			time = GetLowTime();
			if ((time < (340 * 2)) || (time > (780 * 2))) //时间判定范围为 340~780us,
			{ 
         //超过此范围则说明为误码,直接退出
				IE0 = 0;
				return;
			}
			//接收每 bit 高电平时间,判定该 bit 的值
			time = GetHighTime();
			if ((time > (340 * 2)) && (time < (780 * 2))) //时间判定范围为 340~780us,
			{ 
         //在此范围内说明该 bit 值为 0
				byt >>= 1; //因低位在先,所以数据右移,高位为 0
			}
			else if ((time > (1460 * 2)) && (time < (1900 * 2))) //时间判定范围为 1460~1900us,
			{ 
         //在此范围内说明该 bit 值为 1
				byt >>= 1; //因低位在先,所以数据右移,
				byt |= 0x80; //高位置 1
			}
			else //不在上述范围内则说明为误码,直接退出
			{ 
        
				IE0 = 0;
				return;
			}
		}
		ircode[i] = byt; //接收完一个字节后保存到缓冲区
	}
	irflag = 1; //接收完毕后设置标志
	IE0 = 0; //退出前清零 INT1 中断标志
}
  • infrared.h
#ifndef _INFRARED_H
#define _INFRARED_H

#include <reg52.h>
sbit IR_INPUT = P3^2; //红外接收引脚

extern void InitInfrared();
extern bit irflag; //红外接收标志,收到一帧正确数据后置 1
extern unsigned char ircode[4]; //红外代码接收缓冲区

#endif
  • mian.c
#include <reg52.h>
#include "infrared.h"

unsigned char ledChar[18] = { 
         //共阴极数码管显示字符转换表
	0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 
	0x7F, 0x6F, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 
	0x40, 0x00 
};

unsigned char ledBuff[8] = { 
         //数码管显示缓冲区
 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

unsigned char T1RH = 0; //T1 重载值的高字节
unsigned char T1RL = 0; //T1 重载值的低字节

void ConfigTimer1(unsigned int ms);

void main()
{ 
        
	EA = 1; //开总中断

	InitInfrared(); //初始化红外功能
	ConfigTimer1(1); //配置 T1 定时 1ms
	PT1 = 1; //配置 T1 中断为高优先级,启用本行可消除接收时的闪烁
	while (1)
	{ 
        
		if (irflag) //接收到红外数据时刷新显示
		{ 
        
			irflag = 0;
			ledBuff[5] = ledChar[ircode[0] >> 4]; //用户码显示
			ledBuff[4] = ledChar[ircode[0]&0x0F];
			ledBuff[1] = ledChar[ircode[2] >> 4]; //键码显示
			ledBuff[0] = ledChar[ircode[2]&0x0F];
		}
	} 
}

/* 配置并启动 T1,ms-T0 定时时间 */
void ConfigTimer1(unsigned int ms)
{ 
        
	unsigned long tmp; //临时变量
 
	tmp = 24000000 / 12; //定时器计数频率
	tmp = (tmp * ms) / 1000; //计算所需的计数值
	tmp = 65536 - tmp; //计算定时器重载值
	tmp = tmp + 13; //补偿中断响应延时造成的误差

	T1RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
	T1RL = (unsigned char)tmp;
	TMOD &= 0x0f; //清零 T1 的控制位
	TMOD |= 0x10; //配置 T1 为模式 1
	TH1 = T1RH; //加载 T1 重载值
	TL1 = T1RL;
	ET1 = 1; //使能 T1 中断
	TR1 = 1; //启动 T1
}

/* 数码管动态扫描刷新函数,需在定时中断中调用 */
void LedScan()
{ 
        
	static unsigned char i = 0; //动态扫描的索引
 
	P0 = ledChar[11]; //显示消隐
	P2 = ~(0x80 >> i);
	P0 = ledBuff[i];
	i ++;
	i &= 0x07;
}

/* T0 中断服务函数,执行数码管扫描显示 */
void InterruptTimer0() interrupt 3
{ 
        
	TH1 = T1RH; //重新加载重载值
	TL1 = T1RL;
	LedScan(); //数码管扫描显示
}

main.c 文件的主要功能就是把获取到的红外遥控器的用户码和键码信息,传送到数码管上显示出来,并且通过定时器 T0 的 1ms 中断进行数码管的动态刷新。

标签: 电容表面白色的多黑色少rl系列二极管uf208快恢复二极管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台