21_红外遥控

发布时间 2023-11-30 15:10:46作者: 爱吃冰激凌的黄某某

红外遥控

介绍

image-20231129190715228

硬件电路

image-20231129191035748

基本发送和接收

image-20231129201010474

NEC编码

image-20231129201127650

image-20231129201528564

遥控器键码

image-20231129201944042

51单片机的外部中断

image-20231129202009226

外部中断寄存器

image-20231129202114484

红外遥控 VOL-/VOL+

Timer0.c

#include <REGX52.H>

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

void Timer0_SetCounter(unsigned int Value)
{
	TH0=Value/256;
	TL0=Value%256;
}

unsigned int Timer0_GetCounter()
{
	return (TH0<<8)|TL0;
}

void Timer0_Run(unsigned char Flag)
{
	TR0=Flag;
}

Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);

void Timer0_SetCounter(unsigned int Value);

unsigned int Timer0_GetCounter();

void Timer0_Run(unsigned char Flag);

#endif

IR.c

#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)
	{
		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)				//状态0,空闲状态
	{
		Timer0_SetCounter(0);	//定时计数器清0
		Timer0_Run(1);			//定时器启动
		IR_State=1;				//置状态为1
	}
	else if(IR_State==1)		//状态1,等待Start信号或Repeat信号
	{
		IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间
		Timer0_SetCounter(0);	//定时计数器清0
		//如果计时为13.5ms,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)
		if(IR_Time>12442-500 && IR_Time<12442+500)
		{
			IR_State=2;			//置状态为2
		}
		//如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)
		else if(IR_Time>10368-500 && IR_Time<10368+500)
		{
			IR_RepeatFlag=1;	//置收到连发帧标志位为1
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
		else					//接收出错
		{
			IR_State=1;			//置状态为1
		}
	}
	else if(IR_State==2)		//状态2,接收数据
	{
		IR_Time=Timer0_GetCounter();	//获取上一次中断到此次中断的时间
		Timer0_SetCounter(0);	//定时计数器清0
		//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)
		if(IR_Time>1032-500 && IR_Time<1032+500)
		{
			IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));	//数据对应位清0
			IR_pData++;			//数据位置指针自增
		}
		//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)
		else if(IR_Time>2074-500 && IR_Time<2074+500)
		{
			IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));	//数据对应位置1
			IR_pData++;			//数据位置指针自增
		}
		else					//接收出错
		{
			IR_pData=0;			//数据位置指针清0
			IR_State=1;			//置状态为1
		}
		if(IR_pData>=32)		//如果接收到了32位数据
		{
			IR_pData=0;			//数据位置指针清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;	//置收到连发帧标志位为1
			}
			Timer0_Run(0);		//定时器停止
			IR_State=0;			//置状态为0
		}
	}
}

IR.h

#ifndef __IR_H__
#define __IR_H__

#define IR_POWER		0x45
#define IR_MODE			0x46
#define IR_MUTE			0x47
#define IR_START_STOP	0x44
#define IR_PREVIOUS		0x40
#define IR_NEXT			0x43
#define IR_EQ			0x07
#define IR_VOL_MINUS	0x15
#define IR_VOL_ADD		0x09
#define IR_0			0x16
#define IR_RPT			0x19
#define IR_USD			0x0D
#define IR_1			0x0C
#define IR_2			0x18
#define IR_3			0x5E
#define IR_4			0x08
#define IR_5			0x1C
#define IR_6			0x5A
#define IR_7			0x42
#define IR_8			0x52
#define IR_9			0x4A

void IR_Init();

unsigned char IR_GetDataFlag();

unsigned char IR_GetRepeatFlag();

unsigned char IR_GetAddress();

unsigned char IR_GetCommand();

#endif

main.c

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

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

void main()
{
	LCD_Init();
	IR_Init();
	LCD_ShowString(1,1,"ADDR  CMD  NUM");
	LCD_ShowString(2,1,"00    00   00");
	P2=0xFF;
	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);
		}
	}
}

运行效果

VID_20231130_142656

红外遥控电机调速

Motor.c

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

sbit Motor=P1^0;

unsigned char Counter,Compare;

void Motor_Init()
{
	Timer1_Init();
}

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;
	}
}

Motor.h

#ifndef __MOTOR_H__
#define __MOTOR_H__

void Motor_Init();
void Motor_SetSpeed(unsigned char Speed);

#endif

Timer1.c

#include <REGX52.H>

/**
* @brief 定时器1初始化,100微秒@12.000MHz
  * @param 无
  * @retval 无
  */
void Timer1_Init(void)
{
	TMOD &= 0x0F;			//设置定时器模式
	TMOD |= 0x10;			//设置定时器模式
	TL1 = 0x9C;				//设置定时初始值
	TH1 = 0xFF;				//设置定时初始值
	TF1 = 0;				//清除TF0标志
	TR1 = 1;				//定时器0开始计时
	ET1=1;
	EA=1;
	PT1=0;
}

/* 定时器中断函数模板
void Timer1_Routine() interrupt 3
{
	static unsigned int T1Count;
	TL1 = 0x9C;				//设置定时初始值
	TH1 = 0xFF;				//设置定时初始值
	T1Count++;
	if(T1Count>=1000)
	{
		T1Count=0;
		
	}
}
*/

Timer1.h

#ifndef __TIMER1_H__
#define __TIMER1_H__

void Timer1_Init(void);

#endif

main.c

#include <REGX52.H>
#include "Delay.h"
#include "Nixie.h"
#include "Motor.h"
#include "IR.h"

unsigned char Command,Speed;

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