红外遥控器发送数据时,是将二进制数据调制成一系列的脉冲信号红外发射管发射出去,红外载波为频率38KHz的方波,红外接收端在收到38KHz的载波信号时,会输出低电平,否则输出高电平,从而可以将“时断时续”的红外光信号解调成一定周期的连续方波信号,再经过1838一体化红外接收头解调便可以恢复出原数据信号。
红外遥控器的原理到处是,这里就不多废话了,直接上图:
程序:
#include
#include
#include
#define uint unsigned int
#define uchar unsigned char
sbit ir=P3^2 ;
//红外端口
sbit P2_0=P2^0 ; //LED1端口
sbit P2_1=P2^1 ; //LED2端口
sbit P2_2=P2^2 ; //LED3端口
sbit P2_3=P2^3 ; //LED4端口
sbit P2_4=P2^4 ; //LED5端口
sbit P2_5=P2^5 ; //LED6端口
sbit P2_6=P2^6 ; //LED7端口
sbit P2_7=P2^7 ; //LED8端口
uchar key_code=0 ;
//遥控键值
uchar new_code=0 ;
//有无新按键
uint buf_key_code=0 ;
//键值暂存
uchar key_bit_count=0 ;
//键编码脉冲计数
uint count=0 ;
//定时中断次数计数
uint buf_count=0 ;
//定时中断计数暂存
uchar common_code_count=0 ;
//前导码脉冲计数
uchar ir_status=0 ;
//脉冲接收器所处的状态,0:无信号,1:系统码接收区,2:数据编码接收区
///延时子程序 10us
void delay_10us(unsigned char y)
{
unsigned char x ;
for(x=y;x>0;x--);
}
/////初始化
void init(void)
{
ir=1 ;
//红外端口写 1
EA=1 ;
//开总中断
TMOD=0x02 ;
//定时器0,模式2,8 位自动装载模式
TH0=0Xd1 ;
//定时50us
TL0=0Xd1 ;
IT0=1 ;
//INT1 下降沿触发
ET0=1 ;
//允许定时器中断
EX0=1 ;
//允许外部中断
}
/***********************************************
定时器中断
***********************************************/
///定时器中断
void time0()interrupt 1
{
count++;
//定时器中断次数累加
}
/**********************************************
外部中断,红外解码程序
**********************************************/
///外部中断
void int1()interrupt 0
{
TR0=1 ;
//开定时器中断
//如果信号合法,则放入buf_count,count 清 0,对下一个脉冲信号计时
if(count>12&&count<270)
{
buf_count=count ;
count=0 ;
}
delay_10us(10);
//延时 100us 以消除下降沿跳变抖动
//INT1 引脚稳定为低电平,则表法确实是信号,count 重新计时,因上面延时了50us,故要 补偿 1 次TO 中断
if(ir==0)
{
count=2 ;
}
//若收到的信号合法,则再进行信号分析
if(buf_count>12&&buf_count<270)
{
//如果之前未收到引导码
if(ir_status==0)
{
//判断是否引导码 13.5ms
if(buf_count>210&&buf_count<270)
{
ir_status=1 ;
//系统标记
buf_count=0 ;
//
}
}
///收到引导码
else if(ir_status==1)
{
//若收完26 个脉冲
if(common_code_count>=25)
{
ir_status=2 ;
//数据解码标记
common_code_count=0 ;
//系统码计算清零
buf_count=0 ;
// 中断计数暂存清0
}
else if((buf_count>40&&buf_count<70)||(buf_count>12&&buf_count<32))
{
buf_count=0 ;
common_code_count++;
//每收到一个信号自加 1
}
}
//进入数据编码接收
else if(ir_status==2)
{
//收到数据少于8 位,则将收到的数据写入buf_key_code
if(key_bit_count<8)
{
if(buf_count>40&&buf_count<70)
{
buf_count=0 ;
buf_key_code>>=1 ;
buf_key_code|=0x80 ;
//收到 1
key_bit_count++;
//数据脉冲累加
}
//收到0
else if(buf_count>12&&buf_count<32)
{
buf_count=0 ;
buf_key_code>>=1 ;
//收到0
key_bit_count++;
}
}
//若收完 8 位数据则做以下处理
else
{
ir_status=0 ;
//接收状态返回到空闲
key_code=buf_key_code ;
key_bit_count=0 ;
buf_key_code=0 ;
buf_count=0 ;
TR0=0 ;
new_code=1 ;
}
}
}
}
/*************************************
主程序
*************************************/
void main()
{
init(); //中断初始化。
P2_0=P2_1=P2_2=P2_3=P2_4=P2_5=P2_6=P2_7=1;//初始化,使全部LED灯灭。
while(1)
{
while(!new_code);
//判断是否有新按键,如果有则执行下面程序,没有则一直循环
switch(key_code%16) //判断哪个按键。
{case 1:P2_0=~P2_0;break; //当按下按键1,LED1亮或灭。
case 2:P2_1=~P2_1;break; //当按下按键2,LED2亮或灭。
case 3:P2_2=~P2_2;break; //当按下按键3,LED3亮或灭。
case 4:P2_3=~P2_3;break; //当按下按键4,LED4亮或灭。
case 5:P2_4=~P2_4;break; //当按下按键5,LED5亮或灭。
case 6:P2_5=~P2_5;break; //当按下按键6,LED6亮或灭。
case 7:P2_6=~P2_6;break; //当按下按键7,LED7亮或灭。
case 8:P2_7=~P2_7;break; //当按下按键8,LED8亮或灭。
}
new_code=0; //按键标志位清“0”,进入下一次循环判断。
}
}
红外发射原理图:
晶振用的是22.1184M
三级管驱动红外发射电路:
R16另一边接P1.0
红外发射程序如下:(参考网上程序)
#include
#define uint unsigned int
#define uchar unsigned char
bit irout;//红外管状态
sbit ir=P1^7;//红外发射管控制脚
uint count, set_count;//中断计数,设定中断次数
bit flag,keyflag;//红外发送标志,按键标志位
uchar irsys[4]={0x1a,0xa1,0xdc,0x03};//26位系统码,最后一个字节只用2位
uchar ircode,irdata;
/**********************************************
延时1ms
***********************************************/
void delay(uint z)//延时1ms,晶振22.1184M
{
uint x,y;
for(x=z;x>0;x--)
for(y=225;y>0;y--);
}
/**********************************************
按键扫描
**********************************************/
void keyscan(void)
{
uchar keytemp;
P2=0xff;
keytemp=P2&0xff;
if(keytemp!=0xff)
{
delay(20);
keytemp=P2&0xff;
if(keytemp!=0xff)
keyflag=1;//有按键标志
switch(keytemp)
{
case 0xfe:irdata=1;break;//按键1
case 0xfd:irdata=2;break;//按键2
case 0xfb:irdata=3;break;//按键3
case 0xf7:irdata=4;break;//按键4
case 0xef:irdata=5;break;//按键5
case 0xdf:irdata=6;break;//按键6
case 0xbf:irdata=7;break;//按键7
case 0x7f:irdata=8;break;//按键8
}
}
}
/*******************************************
发送8位红外数据
*******************************************/
void sendcode_8(void)
{
uchar i;
for(i=0;i<8;i++)
{
set_count=28;//发送0.56ms 38k红外波(编码中的0.56ms低电平)
flag=1;
count=0;
TR0=1;
while(count
TR0=0;
if(ircode&0x01)//判断红外编码最低位,1宽的高电平,0窄的高电平
{
set_count=120;
}
else
{
set_count=38;
}
flag=0;
count=0;
TR0=1;
while(count
TR0=0;
ircode=ircode>>1;
}
}
/*******************************************
发送2位红外数据
*******************************************/
void sendcode_2(void)//前26位系统码最后两位
{
uchar i;
for(i=0;i<2;i++)
{
set_count=28;
flag=1;
count=0;
TR0=1;
while(count
TR0=0;
if(ircode&0x01)
{
set_count=120;
}
else
{
set_count=38;
}
flag=0;
count=0;
TR0=1;
while(count
TR0=0;
ircode=ircode>>1;
}
}
/*******************************************
发送红外数据
*******************************************/
void sendcode(void)
{
set_count=575;//发送9ms 38K红外光
flag=1;
count=0;
TR0=1;
while(count
TR0=0;
set_count=320;//间隔4.5ms
flag=0;
count=0;
TR0=1;
while(count
TR0=0;
ircode=irsys[0];//发送26位系统码的前1-8位
sendcode_8();
ircode=irsys[1];//发送26位系统码的前9-16位
sendcode_8();
ircode=irsys[2];//发送26位系统码的前17-24位
sendcode_8();
ircode=irsys[3];//发送26位系统码的前24-26位
sendcode_2();
ircode=irdata;//发送8位数据码
sendcode_8();
ircode=~irdata; //发送8位数据反码
sendcode_8();
set_count=28;//发送0.56ms 38k红外波(编码中的0.56ms低电平)
flag=1;
count=0;
TR0=1;
while(count
TR0=0;
ir=1;
delay(23);//延时23ms(编码中的23ms高电平)
set_count=575;//发送9ms 38k红外波
flag=1;
count=0;
TR0=1;
while(count
TR0=0;
set_count=330;//间隔4.5ms
flag=0;
count=0;
TR0=1;
while(count
TR0=0;
set_count=30;//发送0.56ms 38k红外波(编码中的0.56ms低电平)
flag=1;
count=0;
TR0=1;
while(count
TR0=0;
ir=1;
}
/*******************************************
定时器初始化
*******************************************/
void init_timer()
{
EA=1;
TMOD=0X02;//8位自动重载模式
ET0=1;
TH0=0XE8;//定时13us,38K红外波,晶振22.1184
TL0=0XE8;
}
/*******************************************
主函数
*******************************************/
void main(void)
{
init_timer();
count=0;
flag=0;
irout=1;
while(1)
{
keyscan();
if(keyflag)//若有新按键
{
delay(10);
sendcode();//发送红外编码
delay(500);
keyflag=0;//按键标志清零
}
}
}
/*******************************************
定时器中断
*******************************************/
void timer0(void) interrupt 1
{
count++;
if(flag==1)
{
irout=~irout;
}
else
{
irout=1;
}
ir=irout;
}