可定義任意I/O作接收腳,支持長/短按,自適應主頻6MHz~40
//*********************【 NEC解碼頭文件 】******************* // // 簡介:本程序適用于NCE解碼:(9ms+4.5ms)引導碼+32位編碼。 // 兼容STC所有型號(包括 1T 和 12T 系列),可以定義任意I/O作紅外接收腳, // 自適應解碼主頻:6MHz ~ 40MHz。 // // 使用條件:占用系統定時器0,開啟定時器0中斷(如使用其它定時器請自改IR_Init();初始化函數) // // 使用說明:填相關宏定義:USER_H、USER_L、Check_EN、CPU_Fosc、IR, // 上電初始化函數IR_Init(), // 在定時器0中斷中調用IR_NEC()解碼函數, // 解碼有效時,IR_BT=2即短按,IR_BT=3即長按,由用戶清0, // 解碼存放:用戶碼高8位NEC[0],用戶碼低8位NEC[1],操作碼NEC[2],操作碼反碼NEC[3]。 // //【供用戶調用的函數】 // IR_Init(); //接收初始化,開啟定時器0中斷400us // IR_NEC(); //紅外線解碼(解NEC編碼) // //***************************************************************/ #ifndef __IR_NEC_H__ #define __IR_NEC_H__ //【用戶必填項:USER_H、USER_L、Check_EN、CPU_Fosc、IR】 #define USER_H 0x80 //用戶碼高8位 #define USER_L 0x7F //用戶碼低8位 #define Check_EN 0 //是否要校驗16位用戶碼:不校驗填0,校驗則填1 #define CPU_Fosc 12000000L //輸入主頻,自適應解碼(單位:Hz,范圍:6MHz ~ 40MHz) #define CA_S 8 //長按時間設置,單位:108mS(即 108mS整數倍,10倍以上為宜) sbit IR = P3^6; //紅外線接口(任意引腳) #define Step 400 //紅外采樣步長:400us #define TH_H ((65536-Step*(CPU_Fosc/300)/40000)/256) //定時器高8位基準賦值 #define TH_L ((65536-Step*(CPU_Fosc/300)/40000)%256) //定時器低8位基準賦值 uint8 IR_BT; //解碼效果返回:0無效,1有效,2短按,3長按 uint8 NEC[4]; //解碼存放:16位用戶碼、操作碼正反碼 uint8 cntCA; //長按計數 uint16 cntStep; //步數計 bit IRa,IRb; //接收腳電位狀態保存 bit IRsync; //同步標志 uint8 BitN; //位碼裝載數 /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:紅外線解碼初始化 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void IR_Init() { TMOD &= 0xF0; //清定時器0 TMOD |= 0x01; //定時器0:16位定時器 TL0 = TH_L; //每步時間 TH0 = TH_H; ET0 = 1; EA = 1; TR0 = 1; } /*┈┈┈┈┈┈┈┈┈┈ 基準 ┈┈┈┈┈┈┈┈┈┈┈*/ #define Boot_Limit ((9000+4500 +1000)/Step) //引導碼周期上限 #define Boot_Lower ((9000+4500 -1000)/Step) //引導碼周期下限 #define Bit1_Limit ((2250 +800)/Step) //“1”周期上限 #define Bit0_Limit ((1125 +400)/Step) //“0”周期上限 /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:紅外線NEC周期采樣解碼法(定時中斷,下降沿查詢周期時間) 全局變量:IR_BT = 0無效 1有效,待繼續判斷長、短按(如不需要判斷長、短按,則直接使用) 2短按 3長按 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void IR_NEC() { TL0 = TH_L; //重賦值 TH0 = TH_H; cntStep++; //步數累加 if(IR_BT==1)if(cntStep>300)IR_BT=2; //解碼有效后,如果無長按,120ms(400us×300)后默認短按 IRb = IRa; //保存上次電位狀態 IRa = IR; //保存當前電位狀態 if(IRb && !IRa) //是否下降沿(上次高,當前低) { if(cntStep > Boot_Limit) //超過同步時間? { if(IR_BT==1)if(++cntCA>CA_S)IR_BT=3; //解碼有效后,繼續按住遙控>CA_S即長按 IRsync=0; //同步位清0 } else if(cntStep > Boot_Lower){ IRsync=1; BitN=32; } //同步位置1,裝載位碼數32 else if(IRsync) //如果已同步 { if(cntStep > Bit1_Limit)IRsync=0; else { NEC[3] >>= 1; if(cntStep > Bit0_Limit)NEC[3] |= 0x80; //“0”與“1” if(--BitN == 0) { IRsync = 0; //同步位清0 #if (Check_EN == 1) if((NEC[0]==USER_H)&&(NEC[1]==USER_L)&&(NEC[2]==~NEC[3])) //校驗16位用戶碼、操作碼正反碼 { IR_BT=1; cntCA=0; } //解碼有效,接下來判斷:短按?長按? #else if(NEC[2]==~NEC[3]){ IR_BT=1; cntCA=0; } //只校驗操作碼正反碼 #endif } else if((BitN & 0x07)== 0) //NEC[3]每裝滿8位,移動保存一次(即 BitN%8 == 0) { NEC[0]=NEC[1]; NEC[1]=NEC[2]; NEC[2]=NEC[3]; } } } cntStep = 0; //步數計清0 } } //取消相關宏定義 #undef CPU_Fosc #endif 主程序 #include "INC\STC89C52RC.H" #include "INC\MY_SET.H" #include "INC\IR_NEC.H" //調用NEC解碼頭文件 sfr SE = 0x80; //數碼管段選 P0:0x80 P1:0x90 sbit WX1 = P2^0; //數碼管位顯 sbit WX2 = P2^1; sbit WX3 = P2^2; sbit WX4 = P2^3; sbit WX5 = P2^4; sbit WX6 = P2^5; sbit WX7 = P2^6; sbit WX8 = P2^7; uint8c tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0X88,0X83,0XC6,0XA1,0X86,0X8E,0xFF}; uint8 Xn,X1,X2,X3,X4,X5,X6; void KZ0(); //短按處理 void KZ1(); //長按處理 /***************** 主函數 ********************/ void main(void) { IR_Init(); //紅外線解碼初始化 while(1) { //遙控檢測 if((IR_BT==2)||(IR_BT==3)) { if(IR_BT==2)KZ0(); //短按處理 else KZ1(); //長按處理 IR_BT =0; //清有效標志 X1 = NEC[0]/16; //更新顯示 X2 = NEC[0]%16; X3 = NEC[1]/16; X4 = NEC[1]%16; X5 = NEC[2]/16; X6 = NEC[2]%16; } } } /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:遙控短按處理 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void KZ0() { switch(NEC[2]) { case 0x12: P10 = !P10; break; case 0x05: break; case 0x1E: break; case 0x55: break; case 0x01: break; case 0x1B: break; case 0x03: break; case 0x6B: break; case 0x07: break; case 0x08: break; case 0x09: break; case 0x68: break; case 0x22: break; case 0xE6: break; case 0x33: break; case 0xE2: break; default:break; } } /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:遙控長按處理 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void KZ1() { switch(NEC[2]) { case 0x12: P14 = !P14; break; case 0x05: break; case 0x1E: break; case 0x55: break; case 0x01: break; case 0x1B: break; case 0x03: break; case 0x6B: break; case 0x07: break; case 0x08: break; case 0x09: break; case 0x68: break; case 0x22: break; case 0xE6: break; case 0x33: break; case 0xE2: break; default:break; } } /*********************數碼管掃描*************************/ void XS(void) { if(++Xn > 7)Xn=0; switch(Xn) { case 0: WX8=1; NOP; //屏蔽上個位顯 SE=tab[X1]; //送段碼 WX1=0; //開位顯 break; case 1: WX1=1; NOP; SE=tab[X2]; WX2=0; break; case 2: WX2=1; NOP; SE=tab[X3]; WX3=0; break; case 3: WX3=1; NOP; SE=tab[X4]; WX4=0; break; case 4: WX4=1; NOP; SE=tab[16]; WX5=0; break; case 5: WX5=1; NOP; SE=tab[16]; WX6=0; break; case 6: WX6=1; NOP; SE=tab[X5]; WX7=0; break; case 7: WX7=1; NOP; SE=tab[X6]; WX8=0; break; default:break; } } /********************** 定時器0中斷函數************************/ void time0(void) interrupt 1 { IR_NEC(); XS(); }
接收源程序+仿真
點擊此處下載 http://www.zg4o1577.cn/f/hong1.rar
遙控器源程序
點擊此處下載 http://www.zg4o1577.cn/f/hong2.rar
/*************************************************************** 作品:紅外線遙控發射(NEC編碼) 單片機:STC89C52RC 晶振:12M ***************************************************************/ // // 發射引腳(接PNP三極管b極) // PNP三極管e極接2Ω電阻,c極接紅外發射管 #include <REG51.h> #include "INC\MY_SET.h" #include "INC\LCD1602_6IO.h" sbit IR = P3^6; //發射引腳(接PNP三極管基極) #define USER_H P2 //用戶碼高8位 #define USER_L P0 //用戶碼低8位 uint8c tab[16] = { //操作碼 0x12,0x05,0x1e,0x55, 0x01,0x1b,0x03,0x6b, 0x07,0x08,0x09,0x68, 0x22,0xE6,0x33,0xe2}; #define m9 (65536-9000) //9mS #define m4_5 (65536-4500) //4.5mS #define m1_6 (65536-1650) //1.65mS #define m_56 (65536-560) //0.56mS #define m40 (65536-40000) //40mS #define m56 (65536-56000) //56mS #define m2_25 (65536-2250) //2.25mS void SanZhuan(); uint8 KEY(void); void ZZ(uint8 x); //NEC編碼發送程序 void Z0(uint8 temp); //單幀(8位數據)發送程序 void TT0(bit BT,uint16 x); //38KHz載波發射 + 延時程序 /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:主程序 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void main(void) { TMOD = 0x01; //T0 16位工作方式 IR=1; //發射端口常態為高電平 L1602_Init(); L1602_clr(); L1602_xy(0,0); L1602_ZIFUC("UserCode :0x"); L1602_xy(0,1); L1602_ZIFUC("Opcode :0x"); while(1) { L1602_xy(12,0); L1602_JZ(USER_H,16,1); L1602_JZ(USER_L,16,1); SanZhuan(); } } /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:4×4矩陣鍵盤 【 線翻轉法鍵值表 】 P1.0 P1.1 P1.2 P1.3 P1.4 P1.5 P1.6 P1.7 │ │ │ │ │ │ │ │ │ │ │ └──7e be de ee │ │ └─────7d bd dd ed │ └────────7b bb db eb └─────────── 77 b7 d7 e7 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ uint8 KEY(void) { uint8 Key = 0; P1 = 0xf0; //鍵盤初始:行值=0,列值=1 NOP; //緩沖,待IO端口電位穩定 Key = P1&0xf0; //得到行標志 P1 = 0x0f; //翻轉鍵盤接口輸出 NOP; Key |= (P1&0x0f); //列標志 + 行標志 return Key; //返回鍵值 } /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:散轉程序 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void SanZhuan() { uint8 v; v = KEY(); //鍵盤檢測 switch(v) { case 0x7e:ZZ(tab[0]);break; case 0xbe:ZZ(tab[1]);break; case 0xde:ZZ(tab[2]);break; case 0xee:ZZ(tab[3]);break; case 0x7d:ZZ(tab[4]);break; case 0xbd:ZZ(tab[5]);break; case 0xdd:ZZ(tab[6]);break; case 0xed:ZZ(tab[7]);break; case 0x7b:ZZ(tab[8]);break; case 0xbb:ZZ(tab[9]);break; case 0xdb:ZZ(tab[10]);break; case 0xeb:ZZ(tab[11]);break; case 0x77:ZZ(tab[12]);break; case 0xb7:ZZ(tab[13]);break; case 0xd7:ZZ(tab[14]);break; case 0xe7:ZZ(tab[15]);break; default:break; } v=0; } /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:NEC編碼發送程序 ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void ZZ(uint8 Value) { L1602_xy(12,1); L1602_JZ(Value,16,1); //更新顯示 TT0(1,m9); //高電平9mS TT0(0,m4_5); //低電平4.5mS /*┈ 發送4幀數據┈*/ Z0(USER_H); //用戶碼高8位 Z0(USER_L); //用戶碼低8位 Z0(Value); //操作碼 Z0(~Value); //操作碼反碼 /*┈┈ 結束碼 ┈┈*/ TT0(1,m_56); TT0(0,m40); /*┈┈ 重復碼 ┈┈*/ while(KEY() != 0xFF) { TT0(1,m9); TT0(0,m2_25); TT0(1,m_56); TT0(0,m40); TT0(0,m56); } } /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:單幀(8位數據)發送程序 入口:temp ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void Z0(uint8 temp) { uint8 v; for(v=0;v<8;v++) { TT0(1,m_56); //高電平0.65mS if(temp&0x01) TT0(0,m1_6); //發送最低位 else TT0(0,m_56); temp >>= 1; //右移一位 } } /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 函數:38KHz載波發射 + 延時程序 入口:(是否發射載波,延時約 x (uS)) ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/ void TT0(bit BT,uint16 x) { TH0 = x>>8; //輸入定時值 TL0 = x; TF0=0; //溢出標志位清0 TR0=1; //啟動定時器0 if(BT == 0) while(!TF0); //BT=0時,不發射38KHz載波只延時; else while(1) //BT=1時,發射38KHz脈沖+延時;38KHz載波(低電平)占空比5:26 { IR = 0; if(TF0)break;if(TF0)break; IR = 1; if(TF0)break;if(TF0)break; if(TF0)break;if(TF0)break; if(TF0)break;if(TF0)break; if(TF0)break;if(TF0)break; if(TF0)break;if(TF0)break; } TR0=0; //關閉定時器0 IR =1; //載波停止后,發射端口常態為高 }