51单片机之CHQ1838红外接收(NEC协议)

我们的开发板上会有一个红外接收头和一个遥控器。通过这两个小东西就可以完成红外实验。其中这个遥控器采用了NEC协议。除了这个协议还有RC5、RC6类型的。我们接下来就说说红外接受和红外发射。

  1. 红外发送与接收
    发射段就是一个红外发光二极管,产生红外光信号;接收端接收光信号通过光敏电阻把光信号转换成电信号,进一步装换成数字信号。但是发射端的功率较弱,那么光信号就比较弱,为了解决这个问题我们就引入了载波的概念。

  2. 载波
    载波就是一个车,我可以做上这个车到达下一个地方。这个车就是载波。那么上车和下车就是调制解调

  3. 调制
    调制就是按下遥控器的数字,然后通过把这个按键的信号转换成一个载波信号。信号遥控器发送的数据码由以下部分组成:引导码,8位的客户码,8位客户码的补码,8位的按键值,8位按键值的补码;

  4. 解调
    解调就是把这个载波信号通过接收端转换位时序信号,通过接收端的输出引脚把时序信号传送给MCU的外部中断,让主机来判断信号。

    那么我们就想,数字信号是由0和1组成的。发射段最终把他的光信号包含的信息也是最终转换成了接收端的0和1。他是怎么做到的呐。
    在这里插入图片描述
    上边阴影部分代表载波。载波-空闲-载波-空闲。第一部分空闲2.25ms-560微秒,第二部分空闲时间是1.12ms-560微秒。通过两个载波之间的空闲时间来判断是1或者0。通过0和1来传递信息

  5. NEC协议
    我们的单片机有一个红外遥控器,按下其中的一个按钮的时候就会发出如下的载波信号
    在这里插入图片描述
    每个按键被按下会发送不停的信号。但是最开始都是9ms载波加上4.5ms的空闲。之后是32位数据,一共四个字节:地址码,地址码反码,数据码,数据码反码。红外接收端把载波信号转换成时序信号共主机来判断。
    另外我们需要注意的一点是发射端和接收端的0和1是相反的。 当红外接收端接收到载波信号的时候,out引脚输出低电平。如下图所示。这就是解调的过程。调制是把信息转换成载波信号,解调就是重新载波信号解调出来。
    在这里插入图片描述


下边我们俩看看红外发送与接收需要那些东西

  1. 首先是需要定时器,因为通过定时器来计算两个载波之间空闲时间
  2. 外部中断1,我用的板子是MCS51 。红外接收端的OUT引脚连接的是
    P3.2(外部中断1),因为接收端接收到载波信号输出低电平,所以我们需要外部中断1为低电平触发。
  3. 需要说明一点的是,在项目中,外部中断1中断级别0,是最高级别,比我们用的定时器中断级别要高,所以面对两个中断是,主机先处理外部中断。当载波接收完毕,就开始接收空闲信号,这个时候外部中断不被触发,开始执行定时器中端,开始计数,通过计数数值结合定时器单次溢出时间来判断时序信号的0和1.

上代码


#include<reg52.h>    	//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义

sbit IR=P3^2;  			//红外接口标志
sbit dula=P2^6;		//定义锁存使能端口 段锁存
sbit wela=P2^7;		//                 位锁存

unsigned char code Table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9
unsigned char  irtime;	//红外用全局变量

bit irpro_ok,irok;
unsigned char IRcord[4];
unsigned char irdata[33];

void Ir_work(void);
void Ircordpro(void);

void tim0_isr (void) interrupt 1 using 1
{
  irtime++;  //用于计数2个下降沿之间的时间
}

void EX0_ISR (void) interrupt 0 //外部中断0服务函数
{
	static unsigned char  i;             //接收红外信号处理
	static bit startflag=0;                //是否开始处理标志位

	if(startflag)                         
	{
		if(irtime<63&&irtime>=33)//引导码 TC9012的头码,9ms+4.5ms
            i=0;
    		irdata[i]=irtime;//存储每个电平的持续时间,用于以后判断是0还是1
    		irtime=0;
    		i++;
   			if(i==33)
      		{
	  			irok=1;
				i=0;
	  		}
	}
	else
	{
		irtime=0;
		startflag=1;
	}
}


void Ir_work(void)//红外键值散转程序
{
       switch(IRcord[2])//判断第三个数码值
	         {
			 case 0x0c:P0=Table[1];break;//1 显示相应的按键值
			 case 0x18:P0=Table[2];break;//2
			 case 0x5e:P0=Table[3];break;//3
			 case 0x08:P0=Table[4];break;//4
			 case 0x1c:P0=Table[5];break;//5
			 case 0x5a:P0=Table[6];break;//6
			 case 0x42:P0=Table[7];break;//7
			 case 0x52:P0=Table[8];break;//8
			 case 0x4a:P0=Table[9];break;//9
             default:break;
			 }

		  irpro_ok=0;//处理完成标志

}
void Ircordpro(void)//红外码值处理函数
{ 
	unsigned char i, j, k,cord,value;
	k=1;
	for(i=0;i<4;i++)      //处理4个字节
	{
		for(j=1;j<=8;j++) //处理1个字节8位
		{
			cord=irdata[k];
			if(cord>7)//大于某值为1,这个和晶振有绝对关系,这里使用12M计算,此值可以有一定误差
			value=value|0x80;
			if(j<8)
			{
				value>>=1;
			}
			k++;
		}
		IRcord[i]=value;
		value=0;     
	} 
	irpro_ok=1;//处理完毕标志位置1
}


void TIM0init(void)//定时器0初始化
{
	TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
	TH0=0x00; //重载值
	TL0=0x00; //初始化值
	ET0=1;    //开中断
	TR0=1;    
}
void EX0init(void)
{
 IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
 EX0 = 1;   //使能外部中断
 EA = 1;    //开总中断
}

void main(void)
{
	EX0init(); //初始化外部中断
	TIM0init();//初始化定时器
	dula=0;      //位锁存
	P0=0xfe; //取位码 第一位数码管选通,即二进制1111 1110
	wela=1;      //位锁存
	wela=0;
	P0=0x3f; //取位码 第一位数码管选通,即二进制1111 1110
	dula=1;      //位锁存

	while(1)//主循环
	{
		if(irok)                        //如果接收好了进行红外处理
		{   
			Ircordpro();
			irok=0;
		}
		if(irpro_ok)                   //如果处理好后进行工作处理,如按对应的按键后显示对应的数字等
		{
			Ir_work();
		}
	}
}
  
  • 注释
    代码中的Ir_work()函数中用到了按键时序信号和按键值的对应关系,比如:
    0x0c对应按键1。这里每个遥控器有所不同,可以通过看说明书获得,也可以通过示波器测波形,也可以通过串口通信把数字打印在上位机上
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星光技术人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值