C51红外接收与发射控制及原理编码与解码

红外发射

通过通过红外二极管发射红外光,三极管的状态来控制。
红外模块一般都是三个引脚,vcc,gnd,dat,通过控制dat口的来控制发射红外光。

简易电路图

在这里插入图片描述
将数据口连接到单片机的引脚为上,控制io口的电平状态,来控制三极管的导通状态,从而发射红外光。

NEC协议

NEC协议特点:8位地址和8位命令为提高可靠性,地址和命令都传输2次,脉冲间隔调制38kHz载波频率。
在这里插入图片描述
包含引导码,地址码,地址码反码,命令码,命令码反码,结束码。

产生红外光

1.38khz频率,就是1s/38khz = 26.3us/(周期) pwm波的占空比是1/3,即8.77us发射红外光,17.53us不发射红外光。

2.一个时钟周期时产生高电平的时间为8.77us(导通,发射红外光),低电平的时间为17.53us(不导通,不发射红外光)。
在这里插入图片描述

数据编码 0 1

对数据的编码就是通过多个周期发送指定格式的高低电平,控制红外二极管亮灭。
在这里插入图片描述
发送一个二进制 0
一.0.56ms内发送载波信号,一个周期26.3us 就需要 560us/26.3us = 21.29 个周期。 也就是需要发送8.77us高电平,17.53低电平,需要21个周期 。

二.0.56ms不发送载波信号,也是21个周期 就是26.53us的低电平需要21个周期。

在这里插入图片描述

结合程序

从最下面往上面看,下面是底层函数

#include <reg51.h>
#include <intrins.h>

void Delay9us();
void Delay18us();
void Delay26us();
void Send_IR(unsigned int i);
void NoSend_IR(unsigned int i);
void Send_NEC_0();
void Send_NEC_1(); 
void Send_ENC_Message(unsigned int user_code,unsigned char Cmd);
void GetByte_And_SendByte(unsigned int user_code,unsigned char Cmd);
//红外控制引脚
sbit IR_EN =  P2^0;
void main()
{
	Send_ENC_Message(100,20);  //地址码和命令码
		
}

/*
 *发送一帧数据
*/
void Send_ENC_Message(unsigned int user_code,unsigned char Cmd)
{
	//先发送引导码
	Send_IR(342);   //9ms发送载波信号 周期 = 9000us/26.3us = 342
	NoSend_IR(171); //4.5ms不发送载波信号,周期 = 4500us/26.3us = 171
	GetByte_And_SendByte(user_code,Cmd);   //取出每一位并发送
}

//取出数据中的每一位并发送
void GetByte_And_SendByte(unsigned int user_code,unsigned char Cmd)
{
	unsigned int temp,i; //定义中间变量
	//发送数据码(地址码和地址码的反码)
	temp = user_code&0x0001; //通过与运算取出数据最低位
	for(i = 0;i<16;i++){  //循环16位数据中的每一位
		if(temp){  //如果是1执行
			Send_NEC_1();
		}else{     //是0执行
			Send_NEC_0();
		}
		temp = temp>>1;   //左移一位,取出下一位数据
	}
	//数据赋值给中间变量,取出最低位
	//发送命令码
	temp = Cmd & 0x01;
	for(i = 0;i<8;i++){  //循环8位命令中的每一位
		if(temp){  //如果是1执行
			Send_NEC_1();
		}else{     //是0执行
			Send_NEC_0();
		}
		temp = temp>>1;   //左移一位,取出下一位命令
	}
	//发送命令码的反码
	temp = (~Cmd) & 0x01;
	for(i = 0;i<8;i++){  //循环8位命令中的每一位
		if(temp){  //如果是1执行
			Send_NEC_1();
		}else{     //是0执行
			Send_NEC_0();
		}
		temp = temp>>1;   //左移一位,取出下一位命令
	}
	//发送结束码
	Send_NEC_0();
}


/*
发送二进制数据 0
*/
void Send_NEC_0()
{
	Send_IR(21);  //发送载波信号0.56ms, 也就是发送红外光21个周期
	NoSend_IR(21);   //不发送载波信号0.56ms,也是个周期
}

/*
发送二进制数据 1
*/
void Send_NEC_1()
{
	Send_IR(21);    //发送载波信号也是21个周期
	NoSend_IR(64);     //不发送载波信号为1.68ms 发送周期 = 1680us/26.3us = 63.87
}

//发送红外光, 26.3us这个周期内8.77us发送红外光,17.53us不发送红外光
void Send_IR(unsigned int i)
{
	while(i--)      //产生i个周期的信号 ,一个周期是26.3us
	{
		IR_EN = 1;
		Delay9us();
		IR_EN = 0;
		Delay18us();
	}

}

//不发送红外 26.3us这个周期内都不不发送红外光
void NoSend_IR(unsigned int i)
{
	while(i--)
	{
		IR_EN = 0;
		Delay26us(); 
	}
}



//延时9us函数,用于控制输出高电平的时间 标准为8.77us,允许有误差
void Delay9us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 1;
	while (--i);
}
//延时18us函数,控制输出低电平时间,标准为17.53us
void Delay18us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 5;
	while (--i);
}

//26.3us,用于控制周期内不发射红外光
void Delay26us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	i = 9;
	while (--i);
}

红外接收

与发送相反,当有载波信号是,io口为低电平。
在这里插入图片描述

接收电路

在这里插入图片描述

解码过程

最前面接收的9ms的引导码:
就是9ms的低电平, 也就是IR端口会输出9ms的低电平,然后是4.5ms的高电平。
数据位;

解码代码

#include "ir.h"
//数据接收缓冲区
unsigned char ircode[4];

//标志位,用于判断是否成功接收数据
char ir_flag =0;

//等待10us
void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

void Delay600us()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 15;
	do
	{
		while (--j);
	} while (--i);
}



//接收初始化
void IR_Init()
{
	IR_INPUT = 1;  //初始化引脚转态
	IT0 = 1;       //外部中断0 设置为下降沿触发
	EA = 1;        //开中断
	EX0 = 1;        //中断总允许
}

//中断服务函数
//处理接收的红外信息,进行解码
void EX0_ISR() interrupt 0
{
	ir_flag = ir_read(ircode);   //对接收标志位进行判断,将接受到的数据保存到数组中
	if(!ir_flag)
	{
		return;  //返回值为零直接退出
	}
}

//接收红外数据解码
char ir_read(unsigned char * readBuff)
{
	unsigned char count ,i,j,temp = 0;
	//判断是不是低电平,即接收引导码为低电平
	if(!IR_INPUT){
		//检测低电平的有效性,是否为引导码 低电平的时间只有9ms
		count = 0;
		//等待低电平(引导码)结束,接收为低电平时一直等待
		while(!IR_INPUT){
			count++;   //为低电平是加加技术
			//实时检测是否为低电平
			Delay10us(); 
			if(count>1000){   //9ms/10us = 900次 如果超过9ms还是低电平,低电平不合法(允许误差,稍微大一点,1000)
				return 0;    //不是有效引导码,退出
			}
		}
		//IR_INPUT = 1,引导码低电平结束,进入4.5ms的高电平
		count = 0; //清零
		//检测高电平的有效性
		while(IR_INPUT){
			count++;
			Delay10us();    //高电平超过4.5ms,超时判断
			if(count>500){  //4500us/10us = 450 ,允许误差,设置为 500
				return 0;  
			}
		}
		//高电平结束,引导码结束,接收数据
		//接收四个字节的数据 用号码,用户码反码 ,命令码,命令码反码
		for(i = 0;i<4;i++){
			//接收每个字节的比特位Byte
			for(j=0;j<8;j++){
				count = 0;
				while(!IR_INPUT){ //等待第一个位的低电平结束0.56ms,也就是载波有红外时。
					count++;
					Delay10us();
					if(count>60){  //0.54ms/10us = 56 ,允许误差
						return 0; //超时退出,正常自动在while循环判断就退出了
					}
				}
				//判断是0还是1,高电平时间为560us,是0,如果高电平时间为1.685ms,是1
				//延时600us,超过0的时间,判断IR_INPUT是0还是1,如果是1,则表示前面状态还未结束,说明是1
				Delay600us();
				if(IR_INPUT){  //高电平,表示数据为比特位 1
					temp |= 1<<j; //当前位置1
					count = 0;
					while(IR_INPUT){  //等待高电平结束
						count++;
						Delay10us();
						if(count>100){
							return 0;
						}
					}
				} //不是 1,为0时开始已经赋值为0了
			}
			readBuff[i] = temp;  //保存数据
			temp = 0;
		}
		Delay600us();
		//通过反码判断数据是否正确 >>互为反码相加等于255
		if((readBuff[0]+readBuff[1]) == 255 ){
			if((readBuff[2]+readBuff[3]) == 255 ){
				return 1;  //数据正确,返回1
			}
		}
	}
	return 0;
}	



调用

//采用判断标志位标志位,为1表示接收到数据
	if(ir_flag){
		switch(ircode[2]){  //取出命令码
			case 0xff :method1();break; //相应的命令执行函数
			case 0x0f :method2();break;
			case 0x7f :method3();break;
		}
	}
  • 21
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
单片机原理与应用是一门应用性较强的课程,主要介绍了单片机的基本原理和应用。单片机是一种高度集成的电子器件,内部集成了中央处理器、存储器和各种外设接口,可以完成控制和处理信息的任务。 在单片机原理和应用课程中,学生将学习系统地了解单片机的基本构造、工作原理和数字电子技术。课程内容包括单片机的硬件设计和软件设计两个方面。硬件设计包括单片机接口电路的设计与实现,软件设计则涉及到使用C语言编程,完成各种功能的程序设计。 C51是一种常用的单片机系列型号,具有广泛的应用和较强的稳定性。C51程序设计是针对C51系列单片机进行的程序设计,学习者可以通过该课程掌握C语言在单片机编程中的应用。 针对这门课程,有许多电子教案和课件可以供学生下载。通过电子教案和课件,学生可以系统地学习单片机原理与应用以及C51程序设计的相关知识。这些资源可以帮助学生更好地理解课程内容,掌握单片机原理和应用,提高C51程序设计的能力。 学生可以通过搜索引擎或相关教学网站,搜索并下载单片机原理与应用及C51程序设计的电子教案和课件。此外,一些大学或培训机构的官方网站也会提供相关资源的下载链接。对于初学者来说,一些简单的实例和案例教学资源可能更易于理解和上手。 总之,单片机原理与应用及C51程序设计是一门重要的课程,通过学习该课程,学生可以掌握单片机的基本原理与应用,并能够使用C语言进行单片机的程序设计。通过下载相关的电子教案和课件,学生可以更好地学习和掌握这门课程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值