本节我们主要是讲解有关于红外通信的内容,我们通过我们的一个红外发射器(就像一个遥控器一样的东西)向连接了红外接收器的51单片机发射一个红外信号,红外接收器接收到了信号之后在我们的数码管上显示出来我们发射的具体的按键值。
关于红外光:
人类能看到的光从长到短排列依次就是彩虹七色:红,橙,黄,绿,青,蓝,紫。其中红光的波长范围为0.62~0.76um;紫光的波长范围为0.38~046um;比紫光波长还短的光叫紫外线,比红光波长长的光叫红外线。红外线遥控就是利用波长为0.76um~1.5um之间的红外线来控制信号的。而且由于红外光不具备穿墙的能力,虽然是它的一个缺点,但同时也可以称作它的优点,这也为大规模的的使用提供了条件,每家每户都可以用同一频率的红外遥控器而基本不会出现窜台。
红外遥控通信一般由两红外发射装置和红外接收装置组成
关于红外发射装置,也就是我们所说的遥控器,常用的载波频率是38kHz,这是由于发射端的455kHz频率决定的,在发射端要对整数进行分频,一般是12分频,所以发射端的频率就是455/12=37.9,约等于38,当然也有一些红外的频率是36kHz,40kHz等,一般这个频率都是由发射端频率决定。两个设备之间的二进制脉冲码的形式有两种,意思就是说有两种形式来表示高脉冲和低脉冲,我现在使用的就是NEC Protocol的PWM码,这种码的特点就是有8位地址和8位指令长度,地址和命令两次传输,PWM脉冲位置调制,以发射红外载波的占空比来代表0和1,这是什么意思呢?每一个逻辑0或者1都是以560us为一个基本单位,如果我们要表示一个逻辑1,那么我们需要先发送一个560us的脉冲和三个560us的低电平,如果我们要表示一个逻辑0,只需要一个560us的脉冲和一个560us的低电平。而红外接收头的接收是与发射的逻辑刚好相反,意思就是说红外发射装置发射一个高电平,那么我们红外接收装置就会接收一个低电平,而你发送一个低电平就会接收一个低电平,至于其中的原理我们没必要搞懂,其实就是一个协议。我们刚说了有关于高低电平的表示,那我们又该如何发送一个数据呢?红外传输过程其实就是几种码的传递,它的数据格式为:引导码,地址码,地址反码,控制码,控制反码。引导码由一个9ms的低电平和一个4.5ms的高电平组成,其余的都是由8位构成。反码的意义就是为了校验你接收的是否正确。增加传输的可靠性。NEC码还规定了连发码,用于统计假如你按下之后一直没有松开,就可以通过统计连发码的次数来统计按键按下的长短或者次数。具体连发码可以查一下。
硬件:
一下就是我的51单片机的红外接收模块的内容,我的单片机通过P32和红外模块进行通信,看是否有红外发射装置给这个红外模块发送内容
软件:
我们的P32刚好是一个中断引脚,我们可以通过判定是否有引导码来判定是否有发送红外信号,这个代码有个不好的地方,也不能说不好把,这也算是单片机的局限性。就是把所有判定内容都写到了中断里面,这样很容易在大型程序中影响其他程序的正常运行,因为中断时间过长,但是如果不写在中断,又可能受到其它中断影响。但是这个程序也就不会有什么问题,毕竟只有这样一个程序在运行。所以写在中断里面也就没什么问题了。我们通过数码管来显示我们接收到的地址码。代码如下:
#include "reg52.h"
#include "main.h"
#include "ir.h"
sbit IRIN = P3^2;
int Time;
unsigned char IrValue[4] = {0,0,0,0};
void delay(int xms){
while(xms--);
}
void ir_init(){
IT0 = 1;
EX0 = 1;
EA = 1;
IRIN = 1;
}
void ir_check(){
unsigned char j,k;
unsigned short err;
Time=0;
delay(700);
if(IRIN==0)
{
err=1000;
while((IRIN==0)&&(err>0))
{
delay(1);
err--;
}
if(IRIN==1)
{
err=500;
while((IRIN==1)&&(err>0))
{
delay(1);
err--;
}
for(k=0;k<4;k++)
{
for(j=0;j<8;j++)
{
err=60;
while((IRIN==0)&&(err>0))
{
delay(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0))
{
delay(10); //0.1ms
Time++;
err--;
if(Time>30)
{
return;
}
}
IrValue[k]>>=1;
if(Time>=8)
{
IrValue[k]|=0x80;
}
Time=0;
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}
}
void main(){
ir_init();
while(1){
display(IrValue[2]);
}
}
void ir_interrupt() interrupt 1{
IT0 = 0;
ir_check();
IRIN = 1;
IT0 = 1;
}
数码管的代码如下
#include "reg52.h"
#include "main.h"
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
unsigned char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
void display(int val){
char temp[3];
int i;
temp[0] = 0x76;
temp[1] = smgduan[val % 16];
temp[2] = smgduan[val / 16];
for(i = 0;i < 3;i++){
switch(i){
case 0:
LSA = 0; LSB = 0; LSC = 0;
break;
case 1:
LSA = 1; LSB = 0; LSC = 0;
break;
case 2:
LSA = 0; LSB = 1; LSC = 0;
break;
}
P0 = temp[i];
delay(100);
P0 = 0x00;
}
}
两个头文件如下:
#ifndef _MAIN_H_
#define _MAIN_H_
void delay(int xms);
#endif
#ifndef _IR_H_
#define _IR_H_
void display(int val);
#endif