|
紅外遙控在生產(chǎn)和生活中應(yīng)用越來(lái)越廣泛,不同的紅外遙控芯片有不同的發(fā)碼協(xié)議,但一般都是由引導(dǎo)碼,系統(tǒng)碼,鍵碼三部分組成. 引導(dǎo)碼是告訴接收機(jī)準(zhǔn)備接收紅外遙控碼.系統(tǒng)碼是識(shí)別碼,不同的遙控芯片有不同的誤別碼,以免搞錯(cuò). 遙控器上不同的按鍵有不同的鍵碼,系統(tǒng)碼和鍵碼都是16位碼,8位正碼,8位反碼.如SC6122的系統(tǒng)碼是FF00,FF和00互為反碼,鍵碼1為 EF10也是互為反碼.關(guān)于SC6122的資料在我們的網(wǎng)頁(yè)資料下載上有. SC6122的引導(dǎo)碼為低電平為9000微秒,高電平為4500微秒.當(dāng)然高電平不可能精確為9000微秒,在8000微秒到10000微秒都看作是正常范圍, 低電平在4000-5000之間都看作是正常范圍. 引導(dǎo)碼后的32位編碼(16位系統(tǒng)碼和16位鍵碼)不管高低電平,載波時(shí)間都是560微秒,但低電平持續(xù)時(shí)間是1125微秒,高電平持續(xù)時(shí)間是2250 微秒,所以低電平除去載波時(shí)間大約是560微秒,高電平除去載波時(shí)間大約是1680微秒.低電平也有一個(gè)波動(dòng)范圍,在400-700之間都看作是正常 的,具體多少可以通過示波器測(cè)量出來(lái).高電平也有一個(gè)波動(dòng)范圍,在400-2000之間都看作是正常的,具體多少也是根據(jù)經(jīng)驗(yàn).當(dāng)然范圍越寬,捕 捉紅外線的范圍也越寬,越精確.在捕捉到有高低電平之間,在560-1680之間取一個(gè)中間值1120微秒,認(rèn)為小于1120微秒是低電平,大于1120微 秒是高電平. 下面有兩個(gè)經(jīng)過實(shí)踐能在實(shí)驗(yàn)板上顯示鍵碼的程序,一個(gè)是匯編寫的,一個(gè)是用C寫的,與大家一起探討遙控器. 以下程序能在LCD上顯示系統(tǒng)碼和鍵碼,按不同的按鍵,系統(tǒng)碼不變,變的是鍵碼.有不懂的地方可以在留言本上留言. RS EQU P2.5 ;這幾個(gè)是LCD引腳. RW EQU P2.6 E EQU P2.7 IRR EQU P3.3 ;紅外接收的輸出接P3.3. BUF EQU 30H ;30H-33H保存解碼結(jié)果 ;============================================= ORG 0000H AJMP MAIN
;============================================= ORG 0030H MAIN: MOV SP,#70H ;堆棧指針設(shè)到70H的地方 ACALL INIT_LCD ;初始化LCD MOV R7,#10 ACALL DELAY_MS MOV DPTR,#MSG1 CALL DISPLAY_LINE1 ;在第一行顯示 Test8: IR Reader MOV DPTR,#MSG2 CALL DISPLAY_LINE2 ;在第二行顯示www.mcuedu.com MAIN_LOOP: JB IRR,$ ;等待接收頭信號(hào)為低 ACALL GET_LOW ;測(cè)量引導(dǎo)脈沖低電平 CLR C MOV A,R7 SUBB A,#(8000/50) ;SC6122的引導(dǎo)脈沖低電平為9000US,我們只要測(cè)到低電平的值在8000-10000US范圍內(nèi)就認(rèn)為合格的. JC MAIN_LOOP ;如果小于8000US,不對(duì),重新等待接收
CLR C MOV A,R7 SUBB A,#(10000/50) JNC MAIN_LOOP ACALL GET_HIGH ;測(cè)量引導(dǎo)脈沖高電平 CLR C MOV A,R7 SUBB A,#(4000/50) JC MAIN_LOOP ;如果小于4000US,不對(duì),重新等待接收 CLR C MOV A,R7 SUBB A,#(5000/50) JNC MAIN_LOOP ;如果大于5000US,不對(duì),重新等待接收 MOV R0,#BUF ;
MOV R5,#8 ;SC6122發(fā)的碼有32位,我們用4個(gè)字節(jié)來(lái)存放,每個(gè)字節(jié)有8位 IR_NEXT: CALL GET_LOW CLR C MOV A,R7 SUBB A,#(300/50) ;300US JC MAIN_LOOP ;低電平小于300微秒認(rèn)為不對(duì),重新接收 CLR C MOV A,R7 SUBB A,#(800/50) ;800US JNC MAIN_LOOP ;低電平大于800微秒認(rèn)為不對(duì),重新接收 ACALL GET_HIGH CLR C MOV A,R7 SUBB A,#(300/50) ;300US JC MAIN_LOOP ;高電平小于300微秒認(rèn)為不對(duì),重新接收
CLR C MOV A,R7 SUBB A,#(2000/50) ;2000US JNC MAIN_LOOP ;高電平大于2000微秒認(rèn)為不對(duì),重新接收 CLR C MOV A,R7 SUBB A,#(1120/50) ; ;跟中間值1120進(jìn)行比較
RRC A MOV @R0,A ;通過CY移到間接地址R0中去 DJNZ R5,IR_NEXT ;8位移完了嗎 MOV R5,#8 INC R0 MOV A,R0 XRL A,#(BUF+4) JNZ IR_NEXT ;如果不到4個(gè)字節(jié),接收下一個(gè)
MOV DPTR,#MSG_6122 ACALL DISPLAY_LINE1 ;顯示格式名稱
ACALL DISPLAY_IR_CODE ;顯示碼 AJMP MAIN_LOOP ;============================================ MSG1: DB " Test8: IR Reader " MSG2: DB " MSG_6122: DB " Format: SC6122 " ;============================================
;轉(zhuǎn)為ASCII碼在LCD在顯示 TO_ASCII: CJNE A,#0AH,TO_ASCII_1 TO_ASCII_1: JC TO_ASCII_2 ;小于10 ADD A,#('A'-10) RET TO_ASCII_2: ADD A,#'0' RET ;============================================ DISPLAY_IR_CODE: MOV A,#0C0H ;顯示在第二行 ACALL SEND_COMMAND_BYTE ;設(shè)置DDRAM地址 MOV R0,#BUF DISPLAY_IR_CODE_NEXT: MOV A,@R0 SWAP A ANL A,#0FH ;分離出高字節(jié) ACALL TO_ASCII ;轉(zhuǎn)為ASCII碼 ACALL SEND_DATA_BYTE ;顯示 MOV A,@R0 ANL A,#0FH ;分離出低字節(jié) ACALL TO_ASCII ;轉(zhuǎn)為ASCII碼 ACALL SEND_DATA_BYTE ;顯示 MOV A,#' ' ACALL SEND_DATA_BYTE ;顯示空格 INC R0 MOV A,R0 XRL A,#(BUF+4) JNZ DISPLAY_IR_CODE_NEXT MOV R0,#8 ;第2行共有20個(gè)字符,前面顯示用了12個(gè),再用8個(gè)空格填滿 DISPLAY_IR_CODE_B: MOV A,#' ' ACALL SEND_DATA_BYTE DJNZ R0,DISPLAY_IR_CODE_B RET ;============================================ ;測(cè)量低電平時(shí)間,50US采樣一次,R7加1一次,比如低電平時(shí)間為9000US,測(cè)得R7的結(jié)果為180(0B4H) ;OUTPUT: R7 GET_LOW: MOV R7,#00H
GET_LOW_NEXT: MOV R6,#20 ;在晶振為11.0592M時(shí),延50US需要46個(gè)機(jī)器周期, DJNZ R6,$ ;這條指令執(zhí)行需要2個(gè)機(jī)器周期 JB IRR,GET_LOW_RTN ;接收頭為高電平,結(jié)束測(cè)量 INC R7 MOV A,R7 JNZ GET_LOW_NEXT ;看R7是否有溢出 GET_LOW_RTN: RET ;============================================ ;測(cè)量高電平時(shí)間,50US采樣一次,R7加1一次,比如高電平時(shí)間為4500US,測(cè)得R7的結(jié)果為90 ;OUTPUT: R7 GET_HIGH: MOV R7,#00H GET_HIGH_NEXT: MOV R6,#20 ;在晶振為11.0592M時(shí),延50US需要46個(gè)機(jī)器周期, DJNZ R6,$ ;這條指令執(zhí)行需要2個(gè)機(jī)器周期 JNB IRR,GET_HIGH_RTN ;接收頭為低電平,結(jié)束測(cè)量 INC R7 MOV A,R7 JNZ GET_HIGH_NEXT ;看R7是否有溢出 GET_HIGH_RTN: RET ;============================================ ;============================================ DELAY_MS: MOV R6,#250 DELAY_MS_NEXT: NOP NOP DJNZ R6,DELAY_MS_NEXT DJNZ R7,DELAY_MS RET ;============================================ ;INPUT: R7 DELAY: DJNZ R7,$ RET ;============================================ ;向LCD寫一個(gè)命令字節(jié) ;INPUT: ACC SEND_COMMAND_BYTE: CLR RS CLR RW MOV P0,A SETB E NOP NOP NOP NOP NOP NOP CLR E MOV R7,#100 ACALL DELAY RET ;=============================================== ;向LCD寫一個(gè)數(shù)據(jù)字節(jié) ;INPUT: ACC SEND_DATA_BYTE: SETB RS CLR RW MOV P0,A SETB E NOP NOP NOP NOP NOP NOP CLR E MOV R7,#100 ACALL DELAY RET ;====================================================== ;初始化LCD INIT_LCD: MOV A,#30H ACALL SEND_COMMAND_BYTE ACALL SEND_COMMAND_BYTE ACALL SEND_COMMAND_BYTE MOV A,#38H ;設(shè)置工作方式 ACALL SEND_COMMAND_BYTE MOV A,#0CH ;顯示狀態(tài)設(shè)置 ACALL SEND_COMMAND_BYTE MOV A,#01H ;清屏 ACALL SEND_COMMAND_BYTE MOV A,#06H ;輸入方式設(shè)置 ACALL SEND_COMMAND_BYTE RET ;======================================================= ;在第一行顯示 ;INPUT: DPTR指向要顯示的內(nèi)容 DISPLAY_LINE1: MOV A,#080H DISPLAY_LINE1_A: ACALL SEND_COMMAND_BYTE ;設(shè)置DDRAM地址 MOV R6,#20 DISPLAY_LINE1_NEXT: CLR A MOVC A,@A+DPTR ACALL SEND_DATA_BYTE INC DPTR DJNZ R6,DISPLAY_LINE1_NEXT MOV R7,#100 ACALL DELAY RET ;======================================================= ;在第二行顯示 ;INPUT: DPTR指向要顯示的內(nèi)容 DISPLAY_LINE2: MOV A,#0C0H AJMP DISPLAY_LINE1_A ;======================================================= END 下面是一個(gè)用C寫的遙控器程序.能在數(shù)碼管上顯示鍵碼. #include <reg52.h> #define c(x) (x*110592/120000) sbit Ir_Pin=P3^3; unsigned char code Led_Tab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82, 0xf8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E}; //共陽(yáng)極數(shù)碼顯示碼0-F. unsigned char code Led_Sel[]={0xe,0xd,0xb,0x7}; unsigned char Led_Buf[4]; //顯示緩沖區(qū) char Led_Index; //位選 unsigned char Ir_Buf[4]; //用于保存解碼結(jié)果 //============================================================== //數(shù)碼管掃描 timer0() interrupt 1 using 1 { TL0=65536-1000; TH0=(65536-1000)/256; //定時(shí)器0設(shè)定約1000us中斷一次,用于數(shù)碼管掃描 P0=0xff; P2=Led_Sel[Led_Index]; //位選 P0=Led_Tab[Led_Buf[Led_Index]]; //段選 if(++Led_Index>3) Led_Index=0; //四個(gè)掃描完了,到第一個(gè)數(shù)碼管 } //============================================================== unsigned int Ir_Get_Low() { TL1=0; TH1=0; TR1=1; while(!Ir_Pin && (TH1&0x80)==0); TR1=0; return TH1*256+TL1; } //============================================================= unsigned int Ir_Get_High() { TL1=0; TH1=0; TR1=1; while(Ir_Pin && (TH1&0x80)==0); TR1=0; return TH1*256+TL1; } //============================================================== main() { unsigned int temp; char i,j; Led_Index=1; TMOD=0x11; TL0=65536-1000; TH0=(65536-1000)/256; //定時(shí)器0設(shè)定約1000us中斷一次,用于數(shù)碼管掃描 EA=1; ET0=1; TR0=1; Led_Buf[0]=0; Led_Buf[1]=0; Led_Buf[2]=0; Led_Buf[3]=0; //顯示區(qū)設(shè)成0 do{ restart: while(Ir_Pin); temp=Ir_Get_Low(); if(temp<c(8500) || temp>c(9500)) continue;//引導(dǎo)脈沖低電平9000 temp=Ir_Get_High(); if(temp<c(4000) || temp>c(5000)) continue;//引導(dǎo)脈沖高電平4500 for(i=0;i<4;i++) //4個(gè)字節(jié) for(j=0;j<8;j++) //每個(gè)字節(jié)8位 { temp=Ir_Get_Low(); if(temp<c(200) || temp>c(800)) goto restart; temp=Ir_Get_High(); if(temp<c(200) || temp>c(2000)) goto restart; Ir_Buf[i]>>=1; if(temp>c(1120)) Ir_Buf[i]|=0x80; } Led_Buf[0]=Ir_Buf[2]&0xf; Led_Buf[1]=(Ir_Buf[2]/16)&0xf; Led_Buf[2]=Ir_Buf[3]&0xf; Led_Buf[3]=(Ir_Buf[3]/16)&0xf; //顯示結(jié)果 }while(1); }
|