⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 利用avr M8输入捕获 对红外遥控器 进行解码
💻 C
字号:
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <stdio.h>


/*----------------------遥控操作值--------------------*/

//        key        code (hex)
#define Key_1       0x01
#define Key_2       0x02
#define Key_3       0x03
#define Key_4       0x04
#define Key_5       0x05
#define Key_6       0x06
#define Key_7       0x07
#define Key_8       0x08
#define Key_9       0x09
#define Key_0       0x00
#define Menu   	  0x5c       // 菜单
#define Menu_up	  0x56       // 菜单上
#define Menu_down	  0x57       // 菜单下
#define Menu_left   0x5f       // 菜单左
#define Menu_right  0x5b       // 菜单右
#define Menu_ok     0x16       // 菜单确认
#define Channel_up  0x1b       // 频道+
#define Channel_down  0x1f       // 频道-
#define Sound_up      0x1e       // 音量+
#define Sound_down   0x1a       // 音量-
#define Open_Close  0x12       // 开/关
#define Mute        0x10       // 静音
#define Pic_in_pic  0x51          //画中画
#define Standard    0x58       // 制式
#define Return      0x52       // 返回
#define Times       0x0b       // 倍数
#define Screen      0x16       // 屏幕
#define Audio       0x1d       // 伴音
#define NICAM       0x13       // 丽音
#define TV_Vedio    0x0f		   // 电视/视频
#define Sleep       0x0e			//睡眠

/*----------------------常用参数定义-------------------*/

#define P0 0
#define P1 1
#define P2 2
#define P3 3
#define P4 4
#define P5 5
#define P6 6
#define P7 7

#define FREQ 8 //定义单片机工作频率为 8M
#define uint unsigned int
#define uchar unsigned char

/*-----------------IR信号指示灯操作函数---------*/

#define EN_IR_LED DDRB|=_BV(P1)
#define CLR_IR_LED PORTB&=~_BV(P1)
#define SET_IR_LED PORTB|=_BV(P1)

/*----------------------某些端口操作-------------------*/

volatile unsigned char i,j,k;

volatile  unsigned long IRcode;                //定义一个长度为4字节的无符号long类型变量来存储代码

volatile unsigned char *IRcodePointer	;  			//定义一个无符号的单字节指针变量,
													//用此地址变量来分别读取IRCode的
													//4个字节 其中操作码为 IRcodePointer[2] 
													//用户码为 IRcodePointer[0]

volatile unsigned char IRReceiveEffective=0;     //IR信号接收有效 当程序响应接收以后请马上清零 这样才会继续接收下一IR码

volatile unsigned char IRReceiveCurrentBit=0;  //IR信号当前接收位 0时表示第0位即同步码(4.5ms高电平)

volatile unsigned int Pulse_length=0;          //捕获的脉冲宽度

volatile unsigned char ICP_Parity=0;           //捕获中断奇偶次计数 1时为偶次 并在此时判断脉宽

volatile unsigned char Received_Key_Temp;      //红外接收操作键缓存

const unsigned char String[]={"You Have Press Key : "};


/*----------------------串口定义-------------------*/

unsigned char SetPrintfConvertMode=0; //使用printf作其他转换,并非输出到UART

void Uart_Init(void);

int System_putchar(char c, FILE *stream);
int System_getchar(FILE *stream);

FILE mystd = FDEV_SETUP_STREAM(System_putchar, System_getchar,_FDEV_SETUP_RW);

/*----------------------常用函数定义------------------*/

void delay_nms(unsigned int ms)                //N ms延时函数
{
	for(i=0;i<ms;i++)
		_delay_loop_2(FREQ*250);
}


/*----------------------系统初始化函数定义------------------*/

void IO_INIT(void)
{
	PORTB|=_BV(P0);  //设置ICP引脚内部上拉 经过试验验证,上拉会提高红外接收灵敏度
}



ISR(TIMER1_OVF_vect)    
{
  IRReceiveCurrentBit=0;//重置IR接收位为第0位,为下次接收做准备
  TIMSK&=~_BV(TOIE1);  //关闭溢出中断
  TCCR1B|=_BV(ICES1);  //设置输入捕获 上升沿有效
  ICP_Parity=0;        
  CLR_IR_LED;
}





ISR(TIMER1_CAPT_vect)
{
	SET_IR_LED;
	if(!IRReceiveEffective)
	{
		if(ICP_Parity==0) 
			{
				ICP_Parity++;
				TIMSK|=_BV(TOIE1);
				TCCR1B&=~_BV(ICES1); //设置输入捕获 下降沿有效
				TCNT1=0;
		
			}
		else
			{
				
				ICP_Parity=0;
				TCCR1B|=_BV(ICES1);//设置输入捕获 上升沿有效
				Pulse_length=ICR1;
				//TCNT1=0;
				//TIMSK&=~_BV(TOIE1);  //关闭溢出中断
				printf("\n%d",Pulse_length);
				if(IRReceiveCurrentBit==0)
					{
						
						if(Pulse_length>=3500&&Pulse_length<5000)// 如果是引导码 (4.5ms) 进入下一个bit的读取
							{
								IRReceiveCurrentBit++;
								
							}
					}
				else if(IRReceiveCurrentBit<33) //接收32位数据
					{
						IRcode>>=1;	
						if(Pulse_length<1800&&Pulse_length>1200)  //判断是否为 1 ( 1.685 ms)
							IRcode|=0x80000000;
						IRReceiveCurrentBit++;
						if(IRReceiveCurrentBit==33)
							{
								
								IRReceiveCurrentBit=0; //重置IR接收位为第0位,为下次接收做准备
								if(IRcodePointer[0]==(unsigned char)(~IRcodePointer[1])&&IRcodePointer[2]==(unsigned char)(~IRcodePointer[3]))
									{
										SET_IR_LED;    //开启IR信号指示灯
										IRReceiveEffective=1; //数据有效
									}
								delay_nms(5); //因为32位数据后面还有一个信号上跳变,所以要适当延时,延时0.65ms以上即可
							}
					}
			}
	}
}

/////////////////////////////////////////////////////////////////


int main(void)  
{
	
	wdt_disable();

	IO_INIT();

	Uart_Init();
	printf("\nSystem!");
	
	TCCR1B=_BV(CS11);//_BV(WGM12)|_BV(CS11);//采用8分频 这样的话 TCNT1的计数时基为 1us
	//OCR1A=65000;  //TCNT1 计数上限 设置IR接收超时 这里设置 8ms
	
	TIMSK|=_BV(TICIE1);//开启输入捕获中断
	
	TCCR1B|=_BV(ICES1);//输入捕获 上升沿有效
	
	EN_IR_LED;  //IR信号指示灯允许
	CLR_IR_LED; //关闭IR信号指示灯
	
	IRcodePointer=&IRcode;	
	
	sei();	
	
	while(1)
	{
		if(IRReceiveEffective)
			{
				Received_Key_Temp=IRcodePointer[2];//把接收到的操作键放入缓存
				IRReceiveEffective=0; //允许下一次接收
				switch(Received_Key_Temp)
					{
						case Key_1      : printf("\n%sKey_1",String);break;
						case Key_2      : printf("\n%sKey_2",String);break;
						case Key_3      : printf("\n%sKey_3",String);break;
						case Key_4      : printf("\n%sKey_4",String);break;
						case Key_5      : printf("\n%sKey_5",String);break;
						case Key_6      : printf("\n%sKey_6",String);break;
						case Key_7      : printf("\n%sKey_7",String);break;
						case Key_8      : printf("\n%sKey_8",String);break;
						case Key_9      : printf("\n%sKey_9",String);break;
						case Key_0      : printf("\n%sKey_0",String);break;
						case Menu       : printf("\n%sMenu",String);break;
						case Menu_up    : printf("\n%sMenu_up",String);break;
						case Menu_down  : printf("\n%sMenu_down",String);break;
						case Menu_left  : printf("\n%sMenu_left",String);break;
						case Menu_right : printf("\n%sMenu_right",String);break;
						case Menu_ok    : printf("\n%sMenu_ok",String);break;
						case Channel_up	 : printf("\n%sChannel+",String);break;
						case Channel_down   : printf("\n%sChannel-",String);break;
						case Sound_up     : printf("\n%sSound+",String);break;
						case Sound_down   : printf("\n%sSound-",String);break;
						case Open_Close : printf("\n%sOpen_Close",String);break;
						case Mute       : printf("\n%sMute",String);break;
						case Standard   : printf("\n%sStandard",String);break;
						case Return     : printf("\n%sReturn",String);break;
						case Times      : printf("\n%sTimes",String);break;
						//case Screen     : printf("\n%sScreen",String);break;//Screen 与 menu_ok 值相同
						case Audio      : printf("\n%sAudio",String);break;
						case NICAM      : printf("\n%sNICAM" ,String);break;
						case TV_Vedio   : printf("\n%sTV_Vedio",String);break;
						case Sleep      : printf("\n%sSleep",String);break;
						case Pic_in_pic : printf("\n%sPic_in_pic",String);break;
						default:printf("\n%sOther Key 0x%x",String,Received_Key_Temp);break;
					}
			CLR_IR_LED;     //处理完数据以后关闭IR信号指示灯
			}
		
	}
}


/*----------------------串口函数实体------------------*/

void Uart_Init(void)
{
  UCSRB=_BV(RXEN)|_BV(TXEN); 
  UBRRL=25;   //8M 19200 
  stdout=&mystd;
  stdin=&mystd;
}

int System_putchar(char c, FILE *stream)
{
	if(SetPrintfConvertMode==1)
	{
				
	}
	else
	{
		if (c == '\n')
		System_putchar('\r', stream);
		loop_until_bit_is_set(UCSRA, UDRE);
		UDR = c;
	}
	return 0;
}


int System_getchar( FILE *stream)
{
	loop_until_bit_is_set(UCSRA,RXC);
	return UDR;
}




 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -