N76E003红外编码程序及NEC协议分析

N76E003红外编码程序及电路(38kHZ,NEC协议)

N76E003是一款带有flash的增强型8位8051内核单片机,指令集与标准的80C51完全兼容,并且内置16M晶振,故在51上使用的红外发射程序,修改一下定时器数据(晶振不同),就可在N76E003上运行,本文重点说一下NEC红外协议,电路等。完整工程文件可以看此处

由于 NEC协议需要工作在38kHZ载波上,在N76E003中我们使用定时器0来产生,由下图可得知相关寄存器设置方法
定时器1
这里写图片描述
这里写图片描述

定时器0配置代码如下

	//总中断开
	EA=1;
	//设置定时器0位16位模式
	TMOD=0x01;
	//定时器0中断允许
	ET0=1;
	//设定定时大小 38K 等于 26us中断一次             
	TH0=0xff;
	TL0=0xf1;
	//开始计数
	TR0=1;

在产生了38kHZ载波后,我们再来看看NEC协议是如何定义“0”、“1”的,参考下图:
图1:红外编码
“0”——0.56ms的载波+0.56ms的空闲=1.12ms
“1”——0.56ms的载波+1.68ms的空闲=2.24ms

下图为NEC协议格式:会先发送一个9ms载波的引导码,之后是4.5ms的空闲,后发送16位地址码(18ms36ms)、8位数据码(9ms18ms)以及8为数据反码。(第二个108ms)如果接下来发射重复的数据,可以先发送9ms载波,空闲2.5ms,再发射0.56ms载波即可,注意每次发射的间隔时间。
图2:红外编码协议
在调试过程中,建议通过逻辑分析仪确定相应时间,我在使用内置16M晶振,且定时器0设定如上时,计算出的相关数值如下

	endcount=45;//0.56ms
	endcount=132;//1.68ms
	endcount=665;//9ms
	endcount=351;//4.5ms
	count=0;//计数器清空(中断服务程序中累加count)
	do{}while(count<endcount);

电路图如下所示
红外发射电路

相关发射函数及中断服务程序如下所示

sbit LED=P0^4;
sbit IR=P0^5;//定时器0引脚

//红外发射管的亮灭控制
static bit OP;
//延时计数器
static uint count;
//终止延时计数器
static uint endcount;
//红外发送标志
static uchar flag;
//16位地址 第一字节
char iraddr1;
//16位地址 第二字节
char iraddr2;

unsigned char CNT=0;


//红外发射函数
void SendIRdata(char p_irdata);

void delay1(int ms)
{
 unsigned char y;
  while(ms--)
 {
  for(y = 0; y<250; y++)
  {
   _nop_();
   _nop_();
   _nop_();
   _nop_();
  }
 }
}

void main (void) 
{
//	unsigned char temp;
	Set_All_GPIO_Quasi_Mode;					// Define in Function_define.h


	count=0;
	flag=0;
	OP=0;
	IR=0;
	//总中断开
	EA=1;
	//设置定时器0和1为16位模式
	TMOD=0x11;
	//定时器0中断允许
	ET0=1;
	//设定定时大小 38K 等加于 26us中断一次             
	TH0=0xff;
	TL0=0xf1;
	//开始计数
	TR0=1;
	
	//写16位地址
	iraddr1=3;
	iraddr2=252;
		while(1)
		{
			//填写你的代码,发射速度不要过快,建议加延时
			SendIRdata(0x66);
			//由于红外发射需要通过定时器0产生38K载波,建议用	delay1(int ms)函数或其他定时器进行延时	
			delay1(1000);
			LED=~LED;
		}
}
	
//定时器0中断处理函数
void timeint(void) interrupt 1
{
	//设定定时器初值
	TH0=0xff;
	TL0=0xf1;
	
	//中断计数累加
	count++;
	if(flag==1)
	{
		OP=~OP;
	}
	else
	{
		OP=0;
	}
	IR=OP;//IR为定时器0引脚,P05
}

//发送数据函数
//发送的延时时间参数即(endcount)都是在16MHZ的值
void SendIRdata(char p_irdata)
{
	int i;
	char irdata=p_irdata;
	
	//发送9ms的起始码
	endcount=665;
	flag=1;
	count=0;
	while(count<endcount);

	//发送4.5ms的结果码
	endcount=351;
	flag=0;
	count=0;
	do{}while(count<endcount);

	//发送16位地址的前八位
	irdata=iraddr1;
	for(i=0;i<8;i++)
	{
		//先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)45
		endcount=45;
		flag=1;
		count=0;
		do{}while(count<endcount);

		//停止发送红外信号(即编码中的高电平)
		if(irdata-(irdata/2)*2)//判断二进制的个位是1还是0
		{
			endcount=132;//1
		}
		else
		{
			endcount=45;//0
		}
		flag=0;
		count=0;
		do{}while(count<endcount);
		irdata=irdata>>1;
	}

	//发送16位地址的后八位
	irdata=iraddr2;
	for(i=0;i<8;i++)
	{
		//先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)
		endcount=45;
		flag=1;
		count=0;
		do{}while(count<endcount);

		//停止发送红外信号(即编码中的高电平)
		if(irdata-(irdata/2)*2)//判断二进制的个位是1还是0
		{
			endcount=132;//1
		}
		else
		{
			endcount=45;//0
		}
		flag=0;
		count=0;
		do{}while(count<endcount);
		irdata=irdata>>1;
	}


	//发送8位数据
	irdata=p_irdata;
	for(i=0;i<8;i++)
	{
		//先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)
		endcount=45;
		flag=1;
		count=0;
		do{}while(count<endcount);

		//停止发送红外信号(即编码中的高电平)
		if(irdata-(irdata/2)*2)//判断二进制的个位是1还是0
		{
			endcount=132;//1
		}
		else
		{
			endcount=45;//0
		}
		flag=0;
		count=0;
		do{}while(count<endcount);
		irdata=irdata>>1;
	}


	//发送8位数据反码
	irdata=~p_irdata;
	for(i=0;i<8;i++)
	{
		//先发送0.56ms的38K红外波(即编码中的0.56ms的低电平)
		endcount=45;
		flag=1;
		count=0;
		do{}while(count<endcount);

		//停止发送红外信号(即编码中的高电平)
		if(irdata-(irdata/2)*2)//判断二进制的个位是1还是0
		{
			endcount=132;//1
		}
		else
		{
			endcount=45;//0
		}
		flag=0;
		count=0;
		do{}while(count<endcount);
		irdata=irdata>>1;
	}
	//结束信息
	endcount=45;
	flag=1;
	count=0;
	do{}while(count<endcount);
	flag=0;
}

猜你喜欢

转载自blog.csdn.net/u014798590/article/details/82561284