Bootstrap

51单片机红外遥控

红外遥控其实很简单,分为发射和接收两部分,也都是关于时序的时间设置来发送或者接收数据的。

1、红外发送:主要利用38Khz的载波+红外发光二极管 来发送红外光,且数据遵循NEC码,遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反码

NEC码的位定义:一个脉冲对应560us 的连续载波,一个逻辑1 传输需要2.25ms(560us 脉冲+1680us 低电平),

一个逻辑0 的传输需要1.125ms(560us脉冲+560us 低电平)

 2、红外接收:接收红外发送传来的4个格式数据(引导码、地址码、地址反码、控制码、控制反码)。

但由于接收时没有脉冲时是高电平收到脉冲时为低电平,所以当有脉冲信号传进来时,利用外部中断中的下降沿触发 下降沿中断,然后判断低电平的时间,进而判断数据的0或1

   ENC码定义:接收头接收数据时,逻辑1 应该是560us 低+1680us 高,逻辑0 应该是560us 低+560us 高。

接收时引导码是由一个9ms低电平 + 一个4.5ms高电平组成。

地址反码、控制码、控制反码均是8位数据格式。接收时数据(低位在前,高位在后顺序)按照逻辑1:560us 低+1680us 高,逻辑0:560us 低+560us 高的方式进行数据判断。

**!!!主要在于接收部分是有脉冲时低电平,无脉冲时高电平。所以依照这种特性可以采用外部中断的下降沿触发外部中断进行轮询下降沿的时间来判断数据1或是0**

程序待发:

** 红外c文件:**

#include "ir.h"

unsigned char Read_Ir_value[4];//存储4个字节接收码(地址码+地址反码+控制码+控制反码)

//定义延时函数
//void delay10us(void)   //误差 -0.234375us
//{
//    unsigned char a;
//    for(a=2;a>0;a--);
//}


void delay10us(unsigned int ten_us)
{
	while(ten_us--);	
}

void ired_init(void)
{
	IT0 = 1;	//下降沿触发
	EX0 = 1;	//打开中断0允许
	EA = 1;	//打开总中断
	IRIN = 1;	//初始化端口
}

void ired() interrupt 0	//外部中断0服务函数
{
	unsigned int Ir_time = 0;
	unsigned char i = 0, j = 0;
	unsigned char cnt = 0;
	
	if(IRIN == 0)
	{
		Ir_time = 1000;      		// 10 000 = 10ms 
		while((!IRIN) && (Ir_time))		//引导信号0 9ms ,超过10ms强制退出
		{
			delay10us(1);   			// 延时函数 10us
			Ir_time--;
			if(Ir_time == 0) return;
		}
		if(IRIN == 1)
		{
			Ir_time = 500;
			while(IRIN && Ir_time)	 //引导信号1 4.5ms ,超过5ms强制退出
			{
				delay10us(1);
				Ir_time--;
				if(Ir_time == 0) return;
			}
			for(i=0; i<4; i++)		//引导码结束后就是剩下的4个8bit数据
			{
				for(j=0; j<8; j++)
				{
					Ir_time = 600;
					while( (IRIN == 0) && Ir_time)  //等待数据1或0前面的0.56ms结束,若超过6ms强制退出
					{
						delay10us(1);
						Ir_time--;
						if(Ir_time == 0) return;
					}
					Ir_time = 20;
					while(IRIN && (Ir_time))   				//等待数据1或0后面的高电平结束,若超过2ms强制退出
					{
						delay10us(10);   /* 问题在这里 10us*10 循环20次 */
						Ir_time--;
						cnt++;
						if(Ir_time == 0) return;
						if(cnt > 20) return;
					}
					Read_Ir_value[i] >>= 1;
					if(cnt >= 8)    //如果cnt>0.8ms,数组i就等于1
					{
						Read_Ir_value[i] |= 0x80;
					}
					cnt = 0;
				}
			}
		}
		if(Read_Ir_value[2] != ~Read_Ir_value[3])
		{
			for(i=0; i<4; i++)
			{
				Read_Ir_value[i] = 0;
			}
			return;
		}
	}
}

** 红外H文件:**

#ifndef _ir_H
#define _ir_H

#include <reg51.h>
//管脚定义
sbit IRIN = P3^2;

//声明变量
extern unsigned char Read_Ir_value[4]; 

//函数声明
//void Delay10us(void);
void delay10us(unsigned int ten_us);
void ired_init(void);

#endif

** 数码管C文件:**

#include "smg.h"

//共阴极数码管显示0~F的段码数据
unsigned char dx[10] = {0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0XFe, 0XF6};

void delay_10us(unsigned int ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能		 : 动态数码管显示
* 输    入       : dat:要显示的数据
				   pos:从左开始第几个位置开始显示,范围1-8
* 输    出    	 : 无
*******************************************************************************/
void smg_display(unsigned char dat[], unsigned char pos)
{
	unsigned char i = 0;
	unsigned char pos_temp = pos - 1;

	for(i=pos_temp; i<8; i++)
	{
	   	switch(7 - i)//位选
		{
			case 0: LSC=1;LSB=1;LSA=1;break;
			case 1: LSC=1;LSB=1;LSA=0;break;
			case 2: LSC=1;LSB=0;LSA=1;break;
			case 3: LSC=1;LSB=0;LSA=0;break;
			case 4: LSC=0;LSB=1;LSA=1;break;
			case 5: LSC=0;LSB=1;LSA=0;break;
			case 6: LSC=0;LSB=0;LSA=1;break;
			case 7: LSC=0;LSB=0;LSA=0;break;
		}
		P0 = dat[i - pos_temp];//传送段选数据
		delay_10us(100);//延时一段时间,等待显示稳定
		P0 = 0x00;//消音
	}
}

** 数码管H文件:**

#ifndef _smg_H_
#define _smg_H_

#include <reg51.h>
//#define SMG_A_DP_PORT	P0	//使用宏定义数码管段码口    //现用P0代替

//定义数码管位选信号控制脚
sbit LSA = P2^0;
sbit LSB = P2^1;
sbit LSC = P2^2;

//声明变量
extern unsigned char dx[10];

//声明函数
void delay_10us(unsigned int ten_us);
//函数声明
void smg_display(unsigned char dat[], unsigned char pos);

#endif

** 主函数/主程序文件:**

#include "smg.h"
#include "ir.h"


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main(void)
{	
	unsigned char ired_buf[3];

	ired_init();//红外初始化

	while(1)
	{				
		ired_buf[0] = dx[Read_Ir_value[2] / 16];		//将控制码高4位转换为数码管段码,
                                                        //可以位移位和位或 得到高四位和低四位
		ired_buf[1] = dx[Read_Ir_value[2] % 16];		//将控制码低4位转换为数码管段码
		ired_buf[2] = 0X6E;			//显示H的段码
		smg_display(ired_buf, 6);
	}		
}

;