(14)红外遥控

红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出

通信方式:单工,异步

红外LED波长:940nm

通信协议标准:NEC标准

请添加图片描述

空闲状态:红外LED不亮,接收头输出高电平

发送低电平:红外LED以38KHz频率闪烁发光,接收头输出低电平

发送高电平:红外LED不亮,接收头输出高电平

NEC编码:

请添加图片描述

请添加图片描述

STC89C52有4个外部中断

STC89C52的外部中断有两种触发方式:

  • 下降沿触发
  • 低电平触发

低电平触发是中断允许后,只要中断引脚的信号是低电平,就触发中断,使用时注意,如果低电平一直保持,会导致多次触发中断。(一直按着按钮动作)

下降沿触发是中断允许后,只要中断引脚的信号出现下降沿,就触发中断,使用时注意,如果信号出现抖动,会导致多次触发中断。(每按一下动作一下)

中断号:

请添加图片描述

外部中断寄存器

请添加图片描述

请添加图片描述

// 配置外部中断
void Int0_Init(){
    
    
	IT0 = 1; // 配置外部中断的触发模式:1下降沿触发,0低电平触发
	IE0 = 0; // 中断位清零
	EX0 = 1; // 外部中断打开
	EA = 1; // 总中断开启
	PX0 = 1; // 优先级(高)保证能及时响应
}
#include <REGX52.H>
#include "Timer0.h"
#include "Int0.h"

unsigned int IR_Time; // 计时
unsigned char IR_State; // 红外解码状态

// 出错可能是0x01默认是int型,写成0x01LL就不会错了
unsigned char IR_Data[4]; // 数据区(4个字节)
unsigned char IR_pData; // 数据区下标

unsigned char IR_DataFlag; // 标识是否接受完数据
unsigned char IR_RepeatFlag; // 接收Repeat时的标识
unsigned char IR_Address; // 数据接收完后保存地址数据
unsigned char IR_Command; // 保存命令码数据


void IR_Init(){
    
    
	Timer0_Init_Counter();
	Int0_Init();
}

unsigned char IR_GetDataFlag(){
    
    
	if(IR_DataFlag){
    
    
		IR_DataFlag = 0;
		return 1;
	}
	return 0;
}

unsigned char IR_GetRepeatFlag(){
    
    
	if(IR_RepeatFlag){
    
    
		IR_RepeatFlag = 0;
		return 1;
	}
	return 0;
}

unsigned char IR_GetAddress(){
    
    
	return IR_Address;
}

unsigned char IR_GetCommand(){
    
    
	return IR_Command;
}

void Int0_Routine() interrupt 0{
    
     // 外部中断函数
	
	switch(IR_State){
    
    
		case 0:{
    
     // 空闲状态
			// P2_0 = 0;
			Timer0_SetCounter(0);
			Timer0_CounterRun(1); // 开始程序计时
			IR_State = 1;
			break;
		}
		case 1:{
    
     // 接收Start/Repeat状态
			IR_Time = Timer0_GetCounter(); // 获取计时结果
			Timer0_SetCounter(0); // 重置计时器
			if(IR_Time>12442-500 && IR_Time<12442+500){
    
     // 红外发送Start,范围误差
				//P2_1 = 0;
				IR_State = 2;
			}else if(IR_Time>10368-500 && IR_Time<10368+500){
    
     // 红外发送Repeat,范围误差
				IR_RepeatFlag = 1; // 标识接收到Repeat
				Timer0_CounterRun(0); // 停止计时
				IR_State = 0; // 回到空闲状态
			}
			break;
		}
		case 2:{
    
     // 接收0/1状态
			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));
                /*
                这一句有点复杂
                IR_Data一共能存四个字节,分别是地址码、地址反码、命令码、命令反码
                每个字节8位,要存入0就用:&=1101 1111,但是按位移会把位置0,所以使用:&=~(0010 0000)
                IR_pData是从0增加到32的,(IR_pData % 8)使得按位移时不超过字节
                IR_pData/8使得IR_pData每增加8次就换到下一个字节,4(个字节)*8(位)=32
                */
				IR_pData++;
			}else if(IR_Time>2074-500 && IR_Time<2074+500){
    
     // 红外发送数据1
				IR_Data[IR_pData/8] |= (0x01 << (IR_pData % 8));
				IR_pData++;
			}else{
    
    
				IR_pData = 0;
				IR_State = 1;
			}
			
			if(IR_pData >= 32){
    
     // 接收了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_CounterRun(0);
				IR_State = 0;
			}
			break;
		}
		default:
			break;
	}
}

猜你喜欢

转载自blog.csdn.net/Falling_Asteroid/article/details/130737398