红外数据传输.docx
《红外数据传输.docx》由会员分享,可在线阅读,更多相关《红外数据传输.docx(20页珍藏版)》请在冰豆网上搜索。
![红外数据传输.docx](https://file1.bdocx.com/fileroot1/2023-6/17/d5a850d4-2218-4a88-a5ea-5be6ba3eec6d/d5a850d4-2218-4a88-a5ea-5be6ba3eec6d1.gif)
红外数据传输
红外数据传输
一、 红外通信原理
红外遥控有发送和接收两个组成部分。
发送端采用单片机将待发送的二进制信号编码调制为一系列的脉冲串信号,通过红外发射管发射红外信号。
红外接收完成对红外信号的接收、放大、检波、整形,并解调出遥控编码脉冲。
为了减少干扰,采用的是价格便宜性能可靠的一体化红外接收头(HS0038,它接收红外信号频率为38kHz,周期约26μs)接收红外信号,它同时对信号进行放大、检波、整形得到TTL电平的编码信号,再送给单片机,经单片机解码并执行去控制相关对象。
如图1所示:
红外发送部分由51单片机、键盘、红外发光二极管和7段数码管组成。
键盘用于输入指令,51单片机检测键盘上按键的状态,并对红外信号进行调制,发光二极管产生红外线,数码管用来显示发送的键值。
图2红外发射电路
红外接收部分由51单片机、一体化红外接收头HS0038和7段数码管组成。
51单片机检测HS0038,并对HS0038接收到的数据解码,通过数码管显示接收到的键值。
图3红外接收电路
二、 编码、解码
(1)二进制信号的调制
二进制信号的调制由单片机来完成,它把编码后的二进制信号调制成频率为38kHz的间断脉冲串,相当于用二进制信号的编码乘以频率为38kHz的脉冲信号得到的间断脉冲串,即是调制后用于红外发射二极管发送的信号如图4二进制码的调制所示
(2)红外接收需先进行解调,解调的过程是通过红外接收管进行接收的。
其基本工作过程为:
当接收到调制信号时,输出高电平,否则输出为低电平,是调制的逆过程(图5解调)。
HS0038是一体化集成的红外接收器件,直接就可以输出解调后的高低电平信号;红外接收器HS0038的应用电路(图6)。
(3)红外遥控发射芯片采用PPM编码方式,当发射器按键按下后,将发射一组108ms的编码脉冲。
遥控编码脉冲由前导码、16位地址码(8位地址码、8位地址码的反码)和16位操作码(8位操作码、8位操作码的反码)组成。
通过对用户码的检验,每个遥控器只能控制一个设备动作,这样可以有效地防止多个设备之间的干扰。
编码后面还要有编码的反码,用来检验编码接收的正确性,防止误操作,增强系统的可靠性。
前导码是一个遥控码的起始部分,由一个9ms的高电平(起始码)和一个4.5ms的低电平(结果码)组成,作为接受数据的准备脉冲。
以脉宽为0.56ms、周期为1.12ms的组合表示二进制的“0”;以脉宽为1.68ms、周期为2.24ms的组合表示二进制的“1”。
(4)单片机采用外部中断INT0管脚和红外接收头的信号线相连,中断方式为边沿触发方式。
计算中断的间隔时间,来区分前导码、二进制的“1”、“0”码。
并将8位操作码提取出来在数码管上显示。
红外接收头输出的原始遥控数据信号,正好和发射端倒向.也就是以前发射端原始信号是高电平,那接收头输出的就是低电平,反之.
软件原理:
开始时发射一个特定的同步码头,对于接收端而言就是一个9ms的低电平,和一个4.5ms的高电平,这个同步码头可以使程序知道从这个同步码头以后可以开始接收数据。
采用脉宽调制的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉
宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”。
解码的关键是如何识别“0”和“1”,从位的定义我们可以发现“0”、“1”均以0.56ms的高电平开始,不同的是
低电平的宽度不同,“0”为0.56ms,“1”为1.685ms,所以必须根据高电平的宽度区别“0”和“1”。
如果从0.56ms
低电平过后,开始延时,0.56ms以后,若读到的电平为低,说明该位为“0”,反之则为“1”,为了可靠起见,
延时必须比0.56ms长些,但又不能超过1.12ms,否则如果该位为“0”,读到的已是下一位的高电平,因此取
(1.12ms+0.56ms)/2=0.84ms最为可靠,一般取0.84ms左右即可。
根据红外编码的格式,程序应该等待9ms
的起始码和4.5ms的结果码完成后才能读码。
HS0038红外接收器,接收红外遥控器发射的信号,输出DATA口和单片机的外部中断0P3.2口相连。
当有红外信号时,触发中断查询中断时间,并和红外起始码,“0”、“1”、终止码的时间进行比较。
从而检测红外的操作码。
整体流程图
(1)发射部分:
通过中断产生38K的载波,TX端口产生发送的数据,然后经过与门放大经发射管发射数据:
38k载波第一列
有效发送数据第二列
对管发射数据第三列
2)接受部分:
HS0038A2接受到38k载波时,会输出低电平,否则
输出高电平。
将HS0038A2产生的信号经过非门后得的原来的信号。
HS0038A2产生信号第一列
经过非门后得到原来数据第二列
经过与门
(3)设计思想简介:
1:
对输入的数据进行编码。
2:
对编码进行脉冲调制。
3:
信号放大后,通过发射管发送38khz信号。
4:
接收信号,进行解码。
5:
让51对信号进行处理(显示,统计,分析)。
51可参考的程序
(1)发送程序
#include
staticbitOP;//红外发射管的亮灭
staticunsignedintcount;//延时计数器
staticunsignedintendcount;//终止延时计数
staticunsignedinttemp;//按键
staticunsignedcharflag;//红外发送标志
staticunsignedcharnum;
sbitir_in=P3^4;
chariraddr1;//十六位地址的第一个字节
chariraddr2;//十六位地址的第二个字节
unsignedcharcodetable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//共阳数码管0~~f
voidSendIRdata(charp_irdata);
voiddelay(unsignedint);
voidkeyscan();
/******************主函数**************************/
voidmain(void)
{
num=0;
P2=0x3f;
count=0;
flag=0;
OP=0;
ir_in=0;
EA=1;//允许CPU中断
TMOD=0x11;//设定时器0和1为16位模式1
ET0=1;//定时器0中断允许
TH0=0xFF;
TL0=0xE6;//设定时值0为38K也就是每隔26us中断一次
TR0=1;//开始计数
iraddr1=3;//00000011
iraddr2=252;//11111100
do{keyscan();
}while
(1);
}
/***********************定时器0中断处理**********************/
voidtimeint(void)interrupt1
{
TH0=0xFF;
TL0=0xE6;//设定时值为38K也就是每隔26us中断一次
count++;
if(flag==1)
{
OP=~OP;
}
else
{
OP=0;
}
ir_in=OP;
}
voidSendIRdata(charp_irdata)
{
inti;
charirdata=p_irdata;
//发送9ms的起始码
endcount=223;
flag=1;
count=0;
do{}while(count/**********************发送4.5ms的结果码***********************/
endcount=117;
flag=0;
count=0;
do{}while(count/********************发送十六位地址的前八位*******************/
irdata=iraddr1;
for(i=0;i<8;i++)
{
/*****先发送0.56ms的38KHZ红外波(即编码中0.56ms的低电平)*****/
endcount=10;
flag=1;
count=0;
do{}while(count/***********停止发送红外信号(即编码中的高电平)*************/
if(irdata-(irdata/2)*2)//判断二进制数个位为1还是0
{
endcount=41;//1为宽的高电平
}
else
{
endcount=15;//0为窄的高电平
}
flag=0;
count=0;
do{}while(countirdata=irdata>>1;
}
/**********************发送十六位地址的后八位******************/
irdata=iraddr2;
for(i=0;i<8;i++)
{
endcount=10;
flag=1;
count=0;
do{}while(countif(irdata-(irdata/2)*2)
{
endcount=41;
}
else
{endcount=15;
}
flag=0;
count=0;
do{}while(countirdata=irdata>>1;
}
/******************发送八位数据********************************/
irdata=p_irdata;
for(i=0;i<8;i++)
{
endcount=10;
flag=1;
count=0;
do{}while(countif(irdata-(irdata/2)*2)
{
endcount=41;
}
else
{
endcount=15;
}
flag=0;
count=0;
do{}while(countirdata=irdata>>1;
}
/***********************发送八位数据的反码**********************/
irdata=~p_irdata;
for(i=0;i<8;i++)
{
endcount=10;
flag=1;
count=0;
do{}while(countif(irdata-(irdata/2)*2)
{
endcount=41;
}
else
{
endcount=15;
}
flag=0;
count=0;
do{}while(countirdata=irdata>>1;
}
endcount=10;
flag=1;
count=0;
do{}while(countflag=0;
}
voiddelay(unsignedintz)
{
unsignedcharx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
/*********************4×4键盘扫描按下按键发射数据************************/
voidkeyscan()
{
P1=0xfe;
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xee:
num=1;
break;
case0xde:
num=2;
break;
case0xbe:
num=3;
break;
case0x7e:
num=4;
break;
}
while(temp!
=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
P2=table[num-1];
SendIRdata(table[num-1]);
}
P1=0xfd;
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xed:
num=5;
break;
case0xdd:
num=6;
break;
case0xbd:
num=7;
break;
case0x7d:
num=8;
break;
}
while(temp!
=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
P2=table[num-1];
SendIRdata(table[num-1]);
}
P1=0xfb;
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xeb:
num=9;
break;
case0xdb:
num=10;
break;
case0xbb:
num=11;
break;
case0x7b:
num=12;
break;
}
while(temp!
=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
P2=table[num-1];
SendIRdata(table[num-1]);
}
P1=0xf7;
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xe7:
num=13;
break;
case0xd7:
num=14;
break;
case0xb7:
num=15;
break;
case0x77:
num=16;
break;
}
while(temp!
=0xf0)
{
temp=P1;
temp=temp&0xf0;
}
P2=table[num-1];
SendIRdata(table[num-1]);
}
}
(2)接收程序
#include"reg52.h"
#defineucharunsignedchar
#defineuintunsignedint
uchardis_num,num,num1,num2,num3;
sbitled=P1^0;
unsignedcharcodetable[]={
0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e};//共阳数码管0~~f
sbitprem=P3^2;//定义遥控头的接收脚
ucharram[4]={0,0,0,0};//存放接受到的4个数据地址码16位+按键码8位+按键码取反的8位
voiddelaytime(uinttime)//延迟90uS
{
uchara,b;
for(a=time;a>0;a--)
{
for(b=40;b>0;b--);
}
}
voidrem()interrupt0//中断函数
{
ucharramc=0;//定义接收了4个字节的变量
ucharcount=0;//定义现在接收第几位变量
uinti=0;//此处变量用来在下面配合连续监测9MS内是否有高电平
prem=1;
for(i=0;i<1100;i++)//以下FOR语句执行时间为8MS左右
{
if(prem)//进入遥控接收程序首先进入引导码的前半部判断,即:
是否有9MS左右的低电平
return;//引导码错误则退出
}
while(prem!
=1);//等待引导码的后半部4.5MS高电平开始的到来。
delaytime(50);//延时大于4.5MS时间,跨过引导码的后半部分,来到真正遥控数据32位中
//第一位数据的0.56MS开始脉冲
for(ramc=0;ramc<4;ramc++)//循环4次接收4个字节
{for(count=0;count<8;count++)//循环8次接收8位(一个字节)
{
while(prem!
=1);//开始判断现在接收到的数据是0或者1,首先在这行本句话时,
//保已经进入数据的0.56MS低电平阶段
//等待本次接受数据的高电平的到来。
delaytime(9);//高电平到来后,数据0高电平最多延续0.56MS,而数据1,高电平可
//延续1.66MS大于0.8MS后我们可以再判断遥控接收脚的电平,
if(prem)//如果这时高电平仍然在继续那么接收到的数据是1的编码
{
ram[ramc]=(ram[ramc]<<1)+1;//将目前接收到的数据位1放到对应的字节中
delaytime(11);//如果本次接受到的数据是1,那么要继续延迟1MS,这样才能跨入//下个位编码的低电平中(即是开始的0.56MS中)
}
else//否则目前接收到的是数据0的编码
ram[ramc]=ram[ramc]<<1;//将目前接收到的数据位0放到对应的字节中
}//本次接收结束,进行下次位接收,此接收动作进行32次,正好完成4个字节的接收
}
if(ram[2]!
=(~(ram[3]&0x7f)))//本次接收码的判断
{
for(i=0;i<4;i++)//没有此对应关系则表明接收失败,清除接受到的数据
ram[i]=0;
return;
}
dis_num=ram[2];//将接收到的按键数据赋给显示变量
}
main()
{
IT0=1;//设定INT0为边沿触发
EX0=1;//打开外部中断0
EA=1;//全局中断开关打开
while
(1)
{
switch(dis_num)
{
case0x81:
num=0;break;
case0xcf:
num=1;break;
case0x92:
num=2;break;
case0x86:
num=3;break;
case0xcc:
num=4;break;
case0xa4:
num=5;break;
case0xa0:
num=6;break;
case0x8f:
num=7;break;
case0x80:
num=8;break;
case0x84:
num=9;break;
case0x88:
num=10;break;
case0xe0:
num=11;break;
case0xb1:
num=12;break;
case0xc2:
num=13;break;
case0xb0:
num=14;break;
case0xb8:
num=15;break;
}
P2=table[num];
P1=0x01;
delaytime(5);
}
}