IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 红外通信的应用——PPM调制与解码(C51) -> 正文阅读

[嵌入式]红外通信的应用——PPM调制与解码(C51)

目录

一、引言

??红外线是波长在750nm至1mm之间的电磁波,其频率高于微波而低于可见光,是一种人的眼眼看不到的光线。无线电波和微波已被广泛应用在长距离的无线通信中,但由于红外线的波长较短,对障碍物的衍射能力差,所以更适合应用在需要短距离无线通信场合点对点的直接线数据传输。为了使各种设备能够通过一个红外接口进行通信,红外数据协议(InfraredDataAssociation,简称IRDA)发布了一个关于红外的统一的软硬件规范,也就是红外数据通讯标准。

??红外通信是利用950nm近红外波段的红外线作为传递信息的媒体,即通信信道。发送端采用脉位调制(PPM)方式,将二进制数字信号调制成某一频率的脉冲序列,并驱动红外发射管以光脉冲的形式发送出去;接收端将接收到的光脉转换成电信号,再经过放大、滤波等处理后送给解调电路进行解调,还原为二进制数字信号后输出。

??PPM是以帧为单位,帧内每个脉冲间隔表示一个通道的控制量,两帧之间有一个长一点的低电平,这个信号曾经用于同步,作为帧和帧之间的划分。

??简而言之,红外通信的实质就是对二进制数字信号进行调制与解调,以便利用红外信道进行传输;红外通信接口就是针对红外信道的调制解调器。

二、数据格式

??数据格式包括了引导码、用户码、数据码和数据码反码,编码总占32位。数据反码是数据码反相后的编码,编码时可用于对数据的纠错。注意:第二段的用户码也可以在遥控应用电路中被设置
成第一段用户码的反码

在这里插入图片描述
本文使用的STC51单片机使用的红外遥控采用NEC协议

1、8 位地址和 8 位指令长度;
2、地址和命令 2 次传输(确保可靠性)
3、PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
4、载波频率为 38Khz;
5、位时间为 1.125ms 或 2.25ms
6、一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要 2.25ms(560us脉冲+1680us 低电平),一个逻辑 0 的传输需要 1.125ms(560us 脉冲+560us 低电平)。

在NEC码中,起始码用于同步,接着是用户码、用户码反码、数据、数据反码。传输时低位在前、高位在后。

三、解码

使用外部中断1(P33引脚)接收信号,收到信号后串口输出,显示对应的十六进制数值。

外部中断步骤:

1.声明一变量来存放高电平时间;
2.如果P3^3口为低电平,超时判断(等待前9ms过去) 如果传输正确(为高电平)接着运行,否则9ms后结束;
3.如果P3^3口为高电平,超时判断(等待4.5ms过去) 开始接受数据(4组8位数据);
4.采用for循环嵌套(大循环4次对应4字节,小循环8次对应每个字节的8位)循环内:
??等待前面560us低电平 计算高电平时间(区分位0和位1)判断如果时间超过3ms退出(位1的总时间为2.25ms);
??对高电平时间判断分辨出位0或者位1,存放在数组中 时间变量清零;
5.判断数据码和数据反码(取反后)如果相等则退出中断。

/*******************************************************************************
* 函数名         : ReadIr()
* 函数功能		: 读取红外数值的中断函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/

void ReadIr() interrupt 2
{
	u8 j,k;
	u16 err;
	Time=0;					 
	delay_10us(700);	//7ms
	if(IRIN==0)		   //确认是否真的接收到正确的信号
	{	 
		err=1000;     //1000*10us=10ms,超过说明接收到错误的信号
		             //当两个条件都为真是循环,如果有一个条件为假的时候跳出循环
		while((IRIN==0)&&(err>0))	//等待前面9ms的低电平过去  		
		{			
			delay_10us(1);
			err--;
		} 
		if(IRIN==1)			//如果正确等到9ms低电平
		{
			err=500;
			while((IRIN==1)&&(err>0))		 //等待4.5ms的起始高电平过去
			{
				delay_10us(1);
				err--;
			}
			for(k=0;k<4;k++)		//共有4字节数据
			{				
				for(j=0;j<8;j++)	//接收一组数据
				{
					err=60;		
					while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
					{
						delay_10us(1);
						err--;
					}
					err=500;
					while((IRIN==1)&&(err>0))	 //计算高电平的时间长度。
					{
						delay_10us(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;
		}
	}		
}

读取的红外数据存放在IrValue中,根据NEC的帧格式,第三位是数据码,即IrValue[2]。在主程序中使用串口发送到电脑上。

使用两个变量存放数据值,当新的红外数据发生变化的时候再使用串口发出去。

while(1)
	{	
		new_value=IrValue[2];
		if(new_value!=old_value)
		{
			old_value=new_value;
			SBUF =new_value;
			while (!TI);			         
			TI = 0;	
				
			SBUF ='\r';  //发完一次数据之后换行0x0D
			while (!TI);			         
			TI = 0;
			SBUF ='\n';  //0x0A
			while (!TI);			         
			TI = 0;
		}
		delay_10us(100);
	}		

在电脑的串口助手中,选择十六进制方式查看,不要使用字符(char),因为有些编码对应的字符是不能显示的,可能会显示“?”之类的。示例:

1C 0D 0A
18 0D 0A

其中,1C、18是NEC帧中的数据,0D和0A 是回车换行

四、应用

可以正确解码,那么下来就要应用了。最常用的有2种,拿空调举例

  1. 空调遥控板按下“开”,就一直运行着。
  2. 空调遥控板按一下“温度+”,温度只增加一度,不应该一直增加。

对于第一种情况,可以用这种格式:

if(IrValue[2]==0x18)
{
	task();  //按一次该按键,就一直运行task
}

对于第二种情况,可以用:

if(IrValue[2]==0x18)
{
	IrValue[2]==0x00;
	task();  //按一次该按键,运行一次task
}

无、完整代码

/**************************************************************************************
* 实验名称:红外通信实验											
* 实现现象:下载程序后,串口输出红外遥控键值数据
* 作者:CQUPTLEI
* 时间:2022/05/26																		  
***************************************************************************************/
#include "reg52.h"		
#include <string.h>
#include <stdio.h>

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

sbit IRIN=P3^3;  //外部中断1,接红外接收头

u8 IrValue[6];   //红外数据存放
u8 Time;


/*******************************************************************************
* 函 数 名          : delay_10us
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay_10us(u16 i)
{
	while(i--);	
}

/*******************************************************************************
* 函数名          : IrInit()
* 函数功能		 : 初始化红外线接收
* 输入           : 无
* 输出         	: 无
*******************************************************************************/
void IrInit()
{
	IT1=1;//下降沿触发
	EX1=1;//打开中断1允许
	EA=1;	//打开总中断
	IRIN=1;//初始化端口
}

/*******************************************************************************
* 函数名          :  UsartInit()
* 函数功能		 : 初始化串口,波特率4800
* 输入           : 无
* 输出         	: 无
*******************************************************************************/
void UsartInit()
{
	SCON=0X50;			
	TMOD=0X20;			
	PCON=0X80;			
	TH1=0XF3;
	TL1=0XF3;
	ES=1;	
	//EA=1;			
	TR1=1;
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		: 主函数
* 输    入       : 无
* 输    出    	: 无
*******************************************************************************/
void main()
{	
	char old_value,new_value; //上一次红外值和本次红外值
	IrInit();
	UsartInit();
	old_value=1;
	while(1)
	{	
		new_value=IrValue[2];
		if(new_value!=old_value)
		{
			old_value=new_value;
			SBUF =new_value;
			while (!TI);			         
			TI = 0;	
					
			SBUF ='\r';  //发完一次数据之后换行0x0D
			while (!TI);			         
			TI = 0;
			SBUF ='\n';  //0x0A
			while (!TI);			         
			TI = 0;
		}
		delay_10us(100);
	}		
}


/*******************************************************************************
* 函数名         : ReadIr()
* 函数功能		   : 读取红外数值的中断函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/

void ReadIr() interrupt 2
{
	u8 j,k;
	u16 err;
	Time=0;					 
	delay_10us(700);	//7ms
	if(IRIN==0)		//确认是否真的接收到正确的信号
	{	 
		err=1000;				//1000*10us=10ms,超过说明接收到错误的信号
		/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
		侯,程序死在这里*/	
		while((IRIN==0)&&(err>0))	//等待前面9ms的低电平过去  		
		{			
			delay_10us(1);
			err--;
		} 
		if(IRIN==1)			//如果正确等到9ms低电平
		{
			err=500;
			while((IRIN==1)&&(err>0))		 //等待4.5ms的起始高电平过去
			{
				delay_10us(1);
				err--;
			}
			for(k=0;k<4;k++)		//共有4组数据
			{				
				for(j=0;j<8;j++)	//接收一组数据
				{

					err=60;		
					while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
					{
						delay_10us(1);
						err--;
					}
					err=500;
					while((IRIN==1)&&(err>0))	 //计算高电平的时间长度。
					{
						delay_10us(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; //数据和它的反码的反码不相同,退出
		}
	}		
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-06-01 15:23:19  更:2022-06-01 15:24:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 15:02:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码