NEC红外遥控解码

单片机AVR  atmel16,将事件和键值通过串口发送出去注意熔丝位配置时钟。

NEC红外遥控解码_第1张图片

#include <iom16v.h>
#include <macros.h>

#define KEY_CUSTOM_CODE    0x22f5 /* 遥控器用户识别码 */
#define KEY_PRESS_EVENT    0x1    /* PRESS按键事件 */
#define KEY_REPEAT_EVENT   0x2    /* REPEAT按键事件 */
#define KEY_RELEASE_EVENT  0x3    /* RELEASE按键事件 */

/* 主频8MHz,采用64分频 */
#define LEADER_CODE_REPEAT_MIN  (10000 / 8)  /* 9+2.5 = 11.5ms */
#define LEADER_CODE_REPEAT_MAX  (12500 / 8)  /* 9+2.5 = 11.5ms */
#define LEADER_CODE_MIN         (12500 / 8)  /* 9+4.5 = 13.5ms */
#define LEADER_CODE_MAX    		(14500 / 8)  /* 9+4.5 = 13.5ms */
#define DATA_CODE_0_MIN    		(900 / 8)    /* 1.12ms */
#define DATA_CODE_0_MAX    		(1300 / 8)   /* 1.12ms */
#define DATA_CODE_1_MIN    		(2000 / 8)   /* 2.24ms */
#define DATA_CODE_1_MAX    		(2300 / 8)   /* 2.24ms */
#define KEY_REPEAT_MIN		 	(96000 / 8)  /* 108-(9+2.5) = 96.5ms */
#define KEY_REPEAT_MAX		 	(97000 / 8)  /* 108-(9+2.5) = 96.5ms */
#define KEY_COMPLETED_TIME   	(108500 / 8) /* 108ms */

#define LEVEL_HIGH              1
#define LEVEL_LOW               0
#define LEADER_CODE_REPEAT      1
#define LEADER_CODE_PRESS       2
#define ERROR                   (-1)

volatile unsigned int KeyEvent = 0;     /* 保存按键事件 */
volatile unsigned int KeyValue = 0;     /* 保存按键键值 */
volatile unsigned int KeyFlag = 0;      /* 判断是否Rress后没有Repeat,直接Release */
volatile unsigned int KeyEventFlag = 0; /* 判断是否有事件发生 */
volatile unsigned int Time = 0;         /* 保存脉冲间隔时间 */
volatile unsigned int TotalTime = 0;    /* 一帧红外数据的时间 */

/* 函数声明 */
void port_init(void);
void timer1_init(void);
void init_devices(void);
void uart_tx_message(void);
void wait_irda_pulse_signal(void);
void uart_init(unsigned int Baud);
void uart_sendbyte(unsigned char Data);
int is_leader_code(unsigned int Time);
int is_irda_data(unsigned int Time);

void port_init(void)
{
   	/*  设置PA0~PA1引脚为红外信号输入端口  */
	/*  设置PA2~PA7引脚为点灯输出端口  */
	DDRA = 0xFC;
	PORTA = 0xFF;
}

void uart_init(unsigned int Baud)
{
	/* 控制寄存器清零 */
 	UCSRB = 0x00;
    UCSRA = 0x00;

	/* 选择UCSRC,异步模式,禁止校验,1位停止位,8位数据位 */
    UCSRC = (1 << URSEL)|(3 << UCSZ0)|(0 << USBS);

    /* 设置波特率 */
    UBRRH = (unsigned char)(Baud >> 8);
    UBRRL = (unsigned char)Baud;

    /* 打开串口发送使能 */
    UCSRB = (1 << TXEN);

	/* 全局中断开放 */
    SREG = BIT(7);

	/* 配置TX为输出 */
    DDRD |= 0X02;
}

void timer1_init(void)
{
    /* CS12:0 = 0,T/C1停止 */
    TCCR1B = 0x00;

    /* T/C1 采用普通工作模式 WGM13:0 = 0 */
    TCCR1A = 0x00;
    TCNT1  = 0x00;

    /* 启动定时器 64分频,单步间隔为8us */
    TCCR1B = 0X03;
}

void init_devices(void)
{
    CLI();          /* 禁止所有中断 */
    GICR = 0x00;    /* 关闭外部中断 */

    port_init();    /* 端口初始化 */
    uart_init(0x3); /* 串口初始化,波特率115200 */
    timer1_init();  /* 定时器1初始化 */

    SEI();          /* 开全局中断 */
}

void uart_sendbyte(unsigned char Data)
{
    /* 等待串口发送缓冲区为空,准备好接收新数据 */
    while(UCSRA & BIT(UDRE) == 0)
    {
        continue;
    }

    /* 向串口发送缓冲区写入数据 */
    UDR = Data;

    /* 等待发送移位寄存器中的数据送出 */
    while(UCSRA & BIT(TXC) == 0)
    {
        continue;
    }

    /* 产生发送结束中断 */
    UCSRA |= BIT(TXC);
}

void uart_tx_message(void)
{
    /* 先发送按键事件 */
    uart_sendbyte(KeyEvent);

    /* 再发送按键键值 */
	uart_sendbyte(KeyValue);
}

int is_leader_code(unsigned int Time)
{
	if(Time > LEADER_CODE_MIN && Time < LEADER_CODE_MAX)
	{
		return LEADER_CODE_PRESS;
	}
	else if(Time > LEADER_CODE_REPEAT_MIN && Time < LEADER_CODE_REPEAT_MAX)
	{
		return LEADER_CODE_REPEAT;
	}
	else
	{
		return ERROR;
	}
}

int is_irda_data(unsigned int Time)
{
	if(Time > DATA_CODE_0_MIN && Time < DATA_CODE_0_MAX)
	{
		return LEVEL_LOW;
	}
	else if(Time > DATA_CODE_1_MIN && Time < DATA_CODE_1_MAX)
	{
		return LEVEL_HIGH;
	}
	else
	{
		return ERROR;
	}
}

void wait_irda_pulse_signal(void)
{
	while((PINA & 0x1) != 0)
	{
		if((TCNT1 > KEY_COMPLETED_TIME - TotalTime) && KeyEventFlag == 1)
		{
		    KeyFlag = 1;
			goto GET_TIME;
		}
		else
		{
		    continue;
		}
	}

	TCNT1 = 0;

	while((PINA & 0x1) != 1)
	{
		continue;
	}

	while((PINA & 0x1) != 0)
	{
	    if(TCNT1 > KEY_REPEAT_MAX)
		{
			goto GET_TIME;
		}
		else
		{
		    continue;
		}
	}

GET_TIME:
	Time = TCNT1;
	TCNT1 = 0;
}

int main()
{
    int Ret = -1;
    unsigned int IrdaData = 0;/* 保存Custom code和Data code,bit31~bit16:Custom code,bit15~bit8:KeyValue,bit7~bit0:校验码 */
    unsigned int Count = 0;

    init_devices();

    while(1)
    {
	START_IRDA_DECODE:
		KeyEvent = 0;

		wait_irda_pulse_signal();
		if(KeyFlag == 1)
		{
		    KeyFlag = 0;
		    KeyEventFlag = 0;
		    KeyEvent = KEY_RELEASE_EVENT;
		    uart_tx_message();
			PORTA = 0xFC; /* 关呼吸灯 */

			goto START_IRDA_DECODE;
		}

		Ret = is_leader_code(Time);
		if(Ret == LEADER_CODE_PRESS) /* 接收到PRESS引导码,准备接收红外数据,发送键值和事件 */
		{
			IrdaData = 0;
			Count = 0;
			TotalTime = Time;

			while(1)
			{
				wait_irda_pulse_signal();
				Ret = is_irda_data(Time);
				if(Ret == LEVEL_LOW) /* 红外数据0 */
				{
					IrdaData <<= 1;
					Count ++;
				}
				else if(Ret == LEVEL_HIGH) /* 红外数据1 */
				{
					IrdaData <<= 1;
					IrdaData |= 0x1;
					Count ++;
				}
				else /* 错误数据 */
				{
					goto START_IRDA_DECODE;
				}

				TotalTime += Time;
#if 0
				if((Count == 16 && IrdaData) != KEY_CUSTOM_CODE) /* 判断用户识别码 */
				{
					goto START_IRDA_DECODE;
				}
#endif
				if(Count == 32)
				{
					KeyValue = (IrdaData >> 8) & 0xFF;
					if((KeyValue + (IrdaData & 0xFF)) == 0xFF) /* 按键码和按键反码校验,正确时通过串口发送 */
					{
					    KeyEventFlag = 1;
					    KeyEvent = KEY_PRESS_EVENT;
						uart_tx_message();
                        PORTA = 0xF0; /* 点呼吸灯 */

						goto START_IRDA_DECODE;
					}
					else /* 键值错误,丢弃 */
					{
						goto START_IRDA_DECODE;
					}
				}
			}
		}
		else if(Ret == LEADER_CODE_REPEAT) /* 接收到REPEAT引导码,发送REPEAT事件 */
		{
			while(1)
			{
                wait_irda_pulse_signal();

				if(Time > KEY_REPEAT_MIN && Time < KEY_REPEAT_MAX)
				{
				    KeyEvent = KEY_REPEAT_EVENT;
					uart_tx_message();

					goto START_IRDA_DECODE;
				}
				else if(Time > KEY_REPEAT_MAX)
				{
				    KeyEventFlag = 0;
					KeyEvent = KEY_RELEASE_EVENT;
					uart_tx_message();
					PORTA = 0xFC; /* 关呼吸灯 */

				    goto START_IRDA_DECODE;
				}
			}
		}
		else if(Ret == ERROR) /* 不是引导码,错误,进入接收引导码前的状态 */
		{
			goto START_IRDA_DECODE;
		}
    }

	return 0;
}




你可能感兴趣的:(NEC红外遥控解码)