51单片机之红外通信原理图_单片机红外通信原理

2022-11-02 09:15:31 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

1.红外遥控简介

红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点。 由于红外线为不可见光,因此对环境影响很小,再由红外光波动波长远小于无线电波的波长,所以红外线遥控不会影响其他家用电器,也不会影 响临近的无线电设备。

红外线是波长在760nm~1mm之间的非可见光。红外通信装置由红外发射管和红外接受管组成,红外发射管是能发射出红外线的发光二极管,发射强度随着电流的增大而增大;红外接受管是一个具有红外光敏感特征的PN节的光敏二极管,只对红外线有反应,产生光电流。

2.信号调制原理

基带信号:从信号源发出没有经过调制的原始信号,特点是频率较低,信号频率从0开始,频谱较宽。 调制:就是用待传送信号去控制某个高频信号的幅度、相位、频率等参量变化的过程,即用一个信号去装载另一个信号。

红外遥控器使用38KB的载波对原始信号进行解调,原理如下:

调制后产生一定频段的高低电平,但红外接收头接受到的信号和调制后的信号电平相反。

3.NEC协议

  • 8 位地址和 8 位指令长度;
  • 地址和命令 2 次传输(确保可靠性)
  • PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
  • 载波频率为 38Khz;
  • 位时间为 1.125ms 或 2.25ms;

(1)NEC 码的位定义:一个脉冲对应 560us 的连续载波;逻辑“1”:560us脉冲 1.68ms低电平; 逻辑“0”:560us脉冲 560us低电平。而遥控接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到 的信号为:逻辑 1 应该是 560us 低 1680us 高,逻辑 0 应该是 560us 低 560us 高。

(2)NEC 遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。 接收端的同步码由一个 9ms 的低电平和一个 4.5ms 的高电平组成 ,地址码、地址反码、控制码、控制反码均是 8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可 用于校验)。

比如接收到0100 1000的数据,因为低位在前,高位在后,所以要转化成0001 0010

我们遥控器的按键“▽”按下时,从红外接收头端收到的波形如图:

从上图可以看到,其地址码为 0 ,地址反码为255,控制码为 168,控制反码为87 。

可以看到在 100ms 之后,我们还收到了几个脉冲,这是 NEC 码规定的连发码 ( 由 9ms 低电平 2.5m 高电平 0.56ms 低电平 97.94ms 高电平组成 )。如果在一帧数据发送完毕之后,按键仍然没有放开,则发射重复码,即发送的是以110ms为周期的重复码 ,可以通过统计连发码的次数来标记按键按下的长短/次数。

(3)发射端的重复码由9ms高电平和2.25ms的低电平以及560us的高电平组成。

二.实验例程 1.实验原理

产生下降沿,进入外部中断0的中断函数,延时一下之后检IO口是否还是低电平,是就等待9ms的低电平过去。等待完9ms低电平过去,再去等待4.5ms的高电平过去。接着开始接收传送的4组数据先等待560us的低电平过去检测高电平的持续时间,如果超过1.12ms那么是高电平(高电平的的持续时间为1680us,低电平的持续时间为565us。)检测接收到的数据和数据的反码进行比较,是否等到的数据是一样的。

红外遥控键值表:

2.实验程序

方法1:使用外部中断(普中科技代码)

代码语言:javascript复制
/**************************************************************************************
*		              红外通信实验												  *
实现现象:下载程序后,数码管显示红外遥控键值数据
注意事项:	红外遥控器内的电池绝缘片一定要抽掉																			  
***************************************************************************************/
#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=0;LSB=0;LSC=0; break;//显示第0位
case(1):
LSA=1;LSB=0;LSC=0; break;//显示第1位
case(2):
LSA=0;LSB=1;LSC=0; break;//显示第2位	
}
P0=DisplayData[2-i];//发送数据
delay(100); //间隔一段时间扫描	
P0=0x00;//消隐
}		
}
/*******************************************************************************
* 函数名         : IrInit()
* 函数功能		   : 初始化红外线接收
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void IrInit()
{
EA=1;	//打开总中断
EX0=1;//打开中断0允许
IT0=1;//下降沿触发
IRIN=1;//初始化端口
}
/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
IrInit();
while(1)
{	
DisplayData[0] = smgduan[IrValue[2]/16];
DisplayData[1] = smgduan[IrValue[2]];
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;     //接收的第1个数为高电平;在第二个for循环中,数据会向右移8次
}
Time=0;		//用完时间要重新赋值							
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}			
}

方法2:不使用外部中断,直接用定时中断

代码语言:javascript复制
#include "IR.h"
#include "extern.h"
#define  P_IR  	 (PT2_DIN&0x08)		//红外
//-------10ms----------------------
void SBR_IR_PRO()
{
if(bfirstover_NUM>=C_IR_up_time)
{
bfirstover_NUM=0;
f_ir_keyupping=0;
IR_DEAL_INIT();
}
else
{
IR_DEAL_PRO1();
}
}
//----------10ms-------------
void IR_DEAL_PRO1()
{
if(P_IR)		//高电平
{
if(!f_ir_old)
{
f_ir_old=1;
//-------------上升沿 0-1--------------------
bfirstover_NUM=0;
if(f_ir_head)		  //地址码的第一个低电平后f_ir_head为1
{
bIrCnt=0;		  //定时器125us加1
}
else
{
if(bIrCnt<C_IR_head_min||bIrCnt>C_IR_head_max)	//低电平时间
{
IR_DEAL_INIT();	  //错误信号
}
else
{
bIrCnt=0;
f_ir_head_one=1;
}
}
}
}
else			//低电平
{
if(f_ir_old)			//f_ir_old初始时为1;经过高电平为1
{
f_ir_old=0;
//-------------下降沿 1-0------------------
bfirstover_NUM=0;
if(f_ir_head)		 //初始时为0;地址码的第一个低电平后为1
{
IR_DATA_COM_PRO1();
}
else
{
//---------引导码----0--------------
if(f_ir_head_one)	 //初始时为0;经过开始信号后为1
{
if((bIrCnt>=16)&&(bIrCnt<=20))	//重复码
{
IR_REPEAT_CNT  ;	   //记录重组码次数
}
else
{
f_ir_head=1;
}
}
bIrCnt=0;
}
}
}
}
//-------10ms--------初始状态-----------
void  IR_DEAL_INIT()
{
birread_num=0;
f_ir_head=0;
f_ir_old=1;
F_IRfrist_over=0;
f_ir_head_one=0;
IR_REPEAT_CNT=0;
}
//--------下降沿--用所得的高电平时间决定逻辑“1”和“0”------------------
void  IR_DATA_COM_PRO1()
{
if(!f_ir_keyupping)	//初始值为0
{
if((bIrCnt<=1)||(bIrCnt>=20))	//这时的bIrCnt是高电平时间
{
IR_DEAL_INIT();	  //错误信号
}
else
{
birread_num  ;				//记录7次移位
if(birread_num>=250)
birread_num=250;   //设置一个值 防止按键一直按着  变量溢出
if(birread_num==1)
{
IR_CODE_VALUE1=0;   //控制反码
IR_CODE_VALUE2=0;   //控制码
IR_CODE_VALUE3=0;  //地址反码
IR_CODE_VALUE4=0;  //地址码
}
else
{
IR_DATA_COM_PRO2();
}
}
}
}
void  IR_DATA_COM_PRO2()
{	
if(birread_num<=C_readover)
{    
if(birread_num<=8)
IR_CODE_VALUE4>>=1;		//移位7次	
else if(birread_num<=16)
IR_CODE_VALUE3>>=1;		
else if(birread_num<=24)
IR_CODE_VALUE2>>=1;				
else						
IR_CODE_VALUE1>>=1;	
if(bIrCnt>=C_l_length)	//大于9*125us 就判断为逻辑“1”
{
if(birread_num<=8)
IR_CODE_VALUE4|=0x80;	
else if(birread_num<=16)
IR_CODE_VALUE3|=0x80;			
else if(birread_num<=24)
IR_CODE_VALUE2|=0x80;							
else						
IR_CODE_VALUE1|=0x80;
}
}						
bIrCnt=0;
if(birread_num==C_readover)
{
//*************接收完毕后*********
f_ir_keyupping=1;
if(!F_IRfrist_over)
{
F_IRfrist_over=1;
SBR_IR_DATA_OUT();
//----------------------
f_ir_head=0;
f_ir_head_one=0;		
}
}
}
//--------------数据输出---------------------
void  SBR_IR_DATA_OUT()
{
if((IR_CODE_VALUE4==C_user_value)&&(IR_CODE_VALUE3==C_user_value_1))
{}
else
return;  //退出
//-----------------
if((IR_CODE_VALUE2==C_IRDATA_KEY1)&&(IR_CODE_VALUE1==(~C_IRDATA_KEY1)))
{
//-------ON
PT24DO=1;
}
if((IR_CODE_VALUE2==C_IRDATA_KEY2)&&(IR_CODE_VALUE1==(~C_IRDATA_KEY2)))
{
//-------OFF
PT24DO=0;
}
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/203649.html原文链接:https://javaforall.cn

0 人点赞