以前剛學MCU時做過紅外遙控解碼,參考別人的程序寫了老半天,總共幾十行,用外部中斷方式,而且還很不好使。
后來在做一個遙控控制RGB燈變色時,發現用外部中斷方式解碼在按鍵時RGB燈老閃(中斷處理解碼去了,PWM波程序被打斷了,PWM用軟件模擬的),
這時想可不可以不用中斷來做呢,就在網上搜了搜,發現一個,就在這個基礎上做了大量優化,最后的解碼程序只有10行左右,
且靈敏度也很好,給大家分享一下。
悄悄告訴你:這個代碼相當好用!各種MCU移植都很方便
上源碼:(只是核心部分)
sbit IR_IO = P1^6; // IR管腳 任意IO
//定時器初始化為125uS中斷一次
void IR_decode_init(void)
{
TMOD |= 0x12; // T1定時方式2
//--------------設定中斷時間------------------------
TH0 = (-125); TL0 = (-125); // 定時125us 12M晶振
ET0 = 1; TR0 = 1; // 啟動T1
EA = 1; // 總中斷允許
}
//解碼的相關數據
bit Irprot_LastState = 0; // 端口狀態位
uchar codeCnt = 0; // 數據碼位計數
uchar irTime; // 碼時間,用于以125us時間計時
uchar IR_data[4]; // 接收數據緩存
//下面為解碼的關鍵部分,大家自己去分析。主思路就是計算下降沿間隔,其余什么高電平多少時間,低電平多少時間都不關心,因此代碼比較精簡。
//125us執行中斷程序一次
void Timer0(void) interrupt 1
{
irTime++;
if(irTime==240) {irTime--; codeCnt=0x3f;} // ir解碼后碼值存放時間, 240*125us = 30ms
if(IR_IO) Irprot_LastState=1; // 記錄IO狀態
else if(Irprot_LastState) // 有下降沿
{
Irprot_LastState = 0; // 下降沿后IO狀態記錄為0
if(irTime<24) // 小于24*125us=3ms的間隔才進行處理
{
codeCnt++; codeCnt &= 0x1f;
IR_data[codeCnt>>3] <<= 1;
if( irTime>15 ) IR_data[codeCnt>>3]++; // 大于15*125us=1.875ms的間隔為數據1
}
irTime = 0; // 下降沿處理完成,將時間清0
}
}
使用時只需查詢codeCnt的值是否等于31(如果解碼完成30ms后才去判斷codeCnt==31,codeCnt將不會再是31,
可以在程序中修改該標志的存活時間),是表示解碼完成,解碼數據放于IR_data[]數組中;
因為該解碼的核心思想是檢測兩個下降沿相隔的時間,所以只要兩個下降沿間隔符合,
不管高低電平時間都會進行解碼,所以如果要提高準確性,需把IR_data[]中的數據進行檢驗,
也就是看是否IR_data[2]==IR_data[3],如果是,99%是正確的.
|