在使用家电过程中,必不可少的就是遥控器了。
常用的红外遥控系统一般分发射和接收两个部分。应用编/解码专用集成电路芯片来进行控制操作,如下图所示。发射部分包括键盘矩阵、编码调制、LED红外发送器;接收部分包括光、电转换放大器、解调、解码电路。
发射部分的主要元件为红外发光二极管。它实际上是一只特殊的发光二极管;由于其内部材料不同于普通发光二极管,因而在其两端施加一定电压时,它便发出的是红外线而不是可见光。目前大量的使用的红外发光二极管发出的红外线波长为940nm左右。
由于我们目的不是制作遥控器,而是利用遥控器控制单片机的功能,我们将会重点在于红外接收到信号部分。红外接收头通常使 HS0038(38KHZ)。
注:红外的接收头的选用,是由遥控器发出的信号频率决定的,最常见是38KHZ的遥控器。
红外的协议类型有很多种,使用最为广泛的是NEC红外协议。以下是按下暂停键后,抓到的红外接收头的解码后的波形。
从抓取的数据上看,在前面表示0 与1的高电平信号脉宽不一样,0比较短,而1是高电平是0的两倍左右。
使用51单片接收信号,对信号解码,在lcd1602上显示。效果如下
main.c
#include "lcd1602.h"
#include "infr.h"
void main()
{
LCD1602_Init();
Infr_Qrq0Init();
while(1);
}
void irq0(void) interrupt 0
{
Infr_GetCode();
Infr_LcdShow();
}
sys.h
#include "stdio.h" //标准库头文件
#define ON 1
#define OFF 0
//---重定义关键词---//
//#ifndef uchar
#define uchar unsigned char
//#endif
//#ifndef uint
#define uint unsigned int
//#endif
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
void delayms(uint y);
void delayus(uint i);
#endif
sys.c
#include "sys.h"
void delayms(uint y)
{
uint x;
for( ; y>0; y--)
{
for(x=110; x>0; x--);
}
}
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delayus(uint i)
{
while(i--);
}
lcd1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include "sys.h"
sbit LCD_WR = P2^5;
sbit LCD_RS = P2^6;
sbit LCD_EN = P2^7;
void LCD1602_WriteCmd(uchar cmd);
void LCD1602_WriteData(uchar ldata);
void LCD1602_Init();
void LCD1602_WriteNumXY(uchar x,uchar y,uchar num);
#endif
lcd1602.c
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include "sys.h"
sbit LCD_WR = P2^5;
sbit LCD_RS = P2^6;
sbit LCD_EN = P2^7;
void LCD1602_WriteCmd(uchar cmd);
void LCD1602_WriteData(uchar ldata);
void LCD1602_Init();
void LCD1602_WriteStrXY(uchar x,uchar y,uchar *str);
void LCD1602_WriteNumXY(uchar x,uchar y,uchar num);
//写入地址,字符串,字符串长度,移动字符数
void LCD1602_StrMove(uchar addr, uchar *str,uchar length,uchar step);
#endif
infr.h
#ifndef __INFR_H__
#define __INFR_H__
#include "sys.h"
sbit IRIN = P3^2;
void Infr_Qrq0Init();
void Infr_GetCode();
void Infr_LcdShow();
#endif
infr.c
#include "infr.h"
#include "lcd1602.h"
IrValue[4] = {0};
/*******************************************************************************
* 函 数 名 : Interrupt
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void Infr_Qrq0Init()
{
IT0 = 1;
EA = 1;
EX0 = 1;
}
void Infr_GetCode()
{
u8 j,k;
u16 err;
u8 Time=0;
delayus(700); //7ms
if(IRIN==0) //确认是否真的接收到正确的信号
{
err=1000; //1000*10us=10ms,超过说明接收到错误的信号
/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
侯,程序死在这里*/
while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去
{
delayus(1);
err--;
}
if(IRIN==1) //如果正确等到9ms低电平
{
err=500;
while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去
{
delayus(1);
err--;
}
for(k=0;k<4;k++) //共有4组数据
{
for(j=0;j<8;j++) //接收一组数据
{
err=60;
while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
{
delayus(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0)) //计算高电平的时间长度。
{
delayus(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;
}
}
}
void Infr_LcdShow()
{
LCD1602_WriteStrXY(2,0,"User:");
LCD1602_WriteNumXY(9,0,IrValue[0]&0x0F);
LCD1602_WriteNumXY(8,0,IrValue[0]>>4);
LCD1602_WriteNumXY(11,0,IrValue[1]&0x0F);
LCD1602_WriteNumXY(10,0,IrValue[1]>>4);
LCD1602_WriteStrXY(2,1,"Code:");
LCD1602_WriteNumXY(9,1,IrValue[2]&0x0F);
LCD1602_WriteNumXY(8,1,IrValue[2]>>4);
LCD1602_WriteNumXY(11,1,IrValue[3]&0x0F);
LCD1602_WriteNumXY(10,1,IrValue[3]>>4);
}