51单片机学习笔记红外遥控

红外遥控

介绍

红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出,其通信方式为单工,异步。它的红外LED波长为940nm,通信协议标准:NEC标准

硬件电路

 对于左边的图

这里连接了两个三极管开关;R1所在电路输入端为38KHZ的方波;IN口输入为波形;对应的三极管开关(PHP型)为低电平导通(高电平不导通);利用两个三极管开关,组合成IN口传出的波形,波形每段对应38KHZ的波形,从而与控制红外LED的闪烁相对应。但是,加入38KHZ的波形闪烁,使得该红外波形成为特有的类型,从而不会受到外界干扰,比如太阳光,

对于中间的图

该图的原理与左边的图类似,只不过需要用程序自己模拟一遍38KHZ的方波。

对于右边的图

这是接收电路,将数据传入红外接收器,经过滤波以及各种解码操作,他就会通过OUT口输出,我们对输出的信号进行分析就行

 

在此基础上,它还有好几个状态,处于空闲状态时红外LED不亮,接收头输出高电平,处于发送低电平时,红外LED以38KHz频率闪烁发光,接收头输出低电平,处于发送高电平时红外LED不亮,接收头输出高电平。

NEC编码

对于Data格式部分,地址码反码对地址取反,用于对地址码进行验证;命令反码同理。一共是32位,前8位是地址码,后8位是地址码的反码,再后八位是命令码,跟在后面的8位也是命令码的反码,用来校验数据。

对于蓝色部分,即数据红外接收部分,560us的下降沿与560us的上升沿组成数据0;560us的下降沿与1600us的上升沿组成数据1。一帧数据时间长度为110ms,采集完后接下来进行分析解调。绿色的Repeat部分为按住按键不放时,连续发送数据的意思。

 以上图的第一个为例,首先是启动码,然后是00000000是地址码,11111111是反码,10100010是命令码,01011101是反码。

其实51单片机的遥控器的键码就是命令码

外部中断

 外部中断寄存器

从上图中,我们可以知道 INT0用来选择中断方式,EX0表示使能中断,EA表示使能所有中断,PX则是选择优先级。

红外遥控代码

主函数代码

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Int0.h"
#include "Timer0.h"
#include "IR.h"


unsigned char Num;
unsigned char Address;
unsigned char Command;


void main()
{
	LCD_Init();
	LCD_ShowString(1,1,"ADDR  CMD  NUM");
	LCD_ShowString(2,1,"00    00   000");
	IR_Init();
	while(1)
	{
		if(IR_GetDataFlag()||IR_GetRepeatFlag())//可达到连发的效果
		{
			//获取地址与键码值
			Address=IR_GetAddress();
			Command=IR_GetCommand();
			//显示地址与键码值
			LCD_ShowHexNum(2,1,Address,2);
			LCD_ShowHexNum(2,7,Command,2);
			
			if(Command==IR_VOL_MINUS)
			{
				Num--;
			}
			if(Command==IR_VOL_ADD)
			{
				Num++;
			}
			
			LCD_ShowNum(2,12,Num,3);
			
		}
	}
}

部分模块代码

 

#include <REGX52.H>

/**
  *@brief  定时器0初始化,100us@12.000MHz
  *@param  无
  *@retval 无
  */

void Timer0_Init(void)		
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0;		//设置定时初值
	TH0 = 0;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 0;		//定时器0开始计时
}


/**
  * @brief  定时器0设置计数器值
  * @param  Value,要设置的计数器值,范围:0~65535
  * @retval 无
  */
void Timer0_SetCounter(unsigned int Value)//计数器部分
{
	TH0=Value/256;
	TL0=Value%256;
	
}


/**
  * @brief  定时器0获取计数器值
  * @param  无
  * @retval 计数器值,范围:0~65535
  */
unsigned int Timer0_GetCounter(void)//返回计算值
{
	return (TH0<<8)|TL0;
}



/**
  * @brief  定时器0启动停止控制
  * @param  Flag 启动停止标志,1为启动,0为停止
  * @retval 无
  */
void Timer0_Run(unsigned char Flag)		//控制计数器是否启动
{
	TR0=Flag;		//给1开始计时,给零停止计时
}
#include <REGX52.H>


/**
  * @brief  外部中断0初始化
  * @param  无
  * @retval 无
  */
void Int0_Init(void)
{
	IT0=1;		//配置为下降沿触发
	IE0=0;		//设置为中断标志位清零
	EX0=1;		//打开后续通路
	EA=1;
	PX0=1;		//设置为优先级为1,即高优先级,从而能够打断其它中断进行中断嵌套
}
#include <REGX52.H>
#include "Timer0.h"
#include "Int0.h"


unsigned int IR_Time;
unsigned char IR_State;

unsigned char IR_Data[4];	//利用数组分别表示四个字节
unsigned char IR_pData;		//用于指向当前位置

unsigned char IR_DataFlag;		//用于判断是否得到数据
unsigned char IR_RepeatFlag;	//用于重发的标志位
unsigned char IR_Address;		//存储最终地址
unsigned char IR_Command;		//存储命令码



/**
  * @brief  红外遥控初始化
  * @param  无
  * @retval 无
  */

void IR_Init(void)//初始化
{
	Timer0_Init();
	Int0_Init();
	
}


/**
  * @brief  红外遥控获取收到数据帧标志位
  * @param  无
  * @retval 是否收到数据帧,1为收到,0为未收到
  */
unsigned char IR_GetDataFlag(void)
{
	if(IR_DataFlag)		//判断是否接收到数据
	{
		IR_DataFlag=0;
		return 1;
	}
	return 0;
}


/**
  * @brief  红外遥控获取收到连发帧标志位
  * @param  无
  * @retval 是否收到连发帧,1为收到,0为未收到
  */
unsigned char IR_GetRepeatFlag(void)
{
	if(IR_RepeatFlag)		//判断是否接收到重复(Repeat)信号
	{
		IR_RepeatFlag=0;
		return 1;
	}
	return 0;
}



/**
  * @brief  红外遥控获取收到的地址数据
  * @param  无
  * @retval 收到的地址数据
  */
unsigned char IR_GetAddress(void)//返回地址值
{
	return IR_Address;
}

/**
  * @brief  红外遥控获取收到的命令数据
  * @param  无
  * @retval 收到的命令数据
  */
unsigned char IR_GetCommand(void)//返回命令字
{
	return IR_Command;
}


//外部中断0中断函数,下降沿触发执行
void Int0_Routine(void)	interrupt 0
{
	if(IR_State==0)		//处于空闲状态
	{
		
		Timer0_SetCounter(0);//确保启动时计数器为0
		Timer0_Run(1);		//启动定时器
		IR_State=1;			//将状态置1,开始处理
	}
	else if(IR_State==1)		//触发读取
	{
		IR_Time=Timer0_GetCounter();//获取当前时间
		Timer0_SetCounter(0);		//将计数器清零
		if(IR_Time>12442-500&&IR_Time<12442+500)	//得到启动信号
		{
			IR_State=2;				//下次中断要解码数据
		}
		else if(IR_Time>10368-500&&IR_Time<10368+500)//得到重发(Repeat)信号
		{
			IR_RepeatFlag=1;		//表示收到数据
			Timer0_Run(0);			//停止计数器
			IR_State=0;				//回到空闲状态
		}
		else					//数据出错时
		{
			IR_State=1;		//搜索起始信号
		}
	}
	else if(IR_State==2)	//开始解码
	{
		IR_Time=Timer0_GetCounter();//获取当前时间
		Timer0_SetCounter(0);		//将计数器清零
		if(IR_Time>1032-500&&IR_Time<1032+500) //获得0信号
		{
			IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));		//将数组单元特定位清零(先1在取反)
			IR_pData++;
		}
		else if(IR_Time>2074-500&&IR_Time<2074+500)		//检测为1信号
		{
			IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));	//将数组单元特定位赋值为1
			IR_pData++;
		}
		else			//数据出错时
		{
			IR_pData=0;
			IR_State=1;		//搜索下一个信号
		}
		if(IR_pData>=32)		//搜索完成时
		{
			IR_pData=0;		//将移位变量清零
			if((IR_Data[0]==~IR_Data[1])&&(IR_Data[2]==~IR_Data[3]))//验证接收的数据是否正确
			{
				
				IR_Address=IR_Data[0];	//进行地址转存
				IR_Command=IR_Data[2];	//进行地址转存
				IR_DataFlag=1;			//已获得数据
			}
			Timer0_Run(0);		//停止计数器运行
			IR_State=0;			//切回空闲状态
		}
	}
}

红外遥控直流电机代码

主函数代码

#include <REGX52.H>
#include "Key.h"
#include "Delay.h"
#include "Nixie.h"
#include "Timer1.h"
#include "Timer0.h"
#include "IR.h"
#include "Int0.h"
#include "Motor.h"


unsigned char Command,Speed;

void main()
{
	Motor_Init();
	IR_Init();
	while(1)
	{
		if(IR_GetDataFlag())
		{
			Command=IR_GetCommand();
			
			if(Command==IR_0){Speed=0;}
			if(Command==IR_1){Speed=1;}
			if(Command==IR_2){Speed=2;}
			if(Command==IR_3){Speed=3;}
			
			
			Speed++;
			Speed%=4;
			if(Speed==0){Motor_SetSpeed(0);}
			if(Speed==1){Motor_SetSpeed(50);}
			if(Speed==2){Motor_SetSpeed(75);}
			if(Speed==3){Motor_SetSpeed(100);}
			
		}
		Nixie(1,Speed);
		
	}
}

部分模块代码

#include <REGX52.H>
#include "Timer1.h"

sbit Motor=P1^0;

unsigned char Counter,Compare;//定义计数器与比较值



/**
  * @brief  电机初始化
  * @param  无
  * @retval 无
  */
void Motor_Init(void)
{
	Timer1_Init();
}



/**
  * @brief  电机设置速度
  * @param  Speed 要设置的速度,范围0~100
  * @retval 无
  */
void Motor_SetSpeed(unsigned char Speed)
{
	Compare=Speed;
}


void Timer1_Routine()  interrupt 3
{
	TL1 = 0x9C;		//设置定时初值
	TH1 = 0xFF;		//设置定时初值
	Counter++;
	Counter%=100;
	if(Counter<Compare)
	{
		Motor=1;
	}
	else
	{
		Motor=0;
	}
	
	
}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

夜雨星辰487

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

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

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

打赏作者

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

抵扣说明:

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

余额充值