下面對(duì)以下幾種比較流行和成熟的紅外解碼程序做一下研究和總結(jié)
解碼程序一:
/*-----------------------------------------------------------------------------------------
定時(shí)器0中斷處理
-----------------------------------------------------------------------------------------*/
void tim0_isr (void) interrupt 1 using 1
{
irtime++; //用于計(jì)數(shù)2個(gè)下降沿之間的時(shí)間
}
/*-----------------------------------------------------------------------------------------
外部中斷0中斷處理
-----------------------------------------------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中斷0服務(wù)函數(shù)
{
static unsigned char i; //接收紅外信號(hào)處理
static bit startflag; //是否開始處理標(biāo)志位
if(startflag)
{
if(irtime<=54&&irtime>=50)//引導(dǎo)碼 TC9012的頭碼,9ms+4.5ms
{
i=0;
}
irdata[i]=irtime;//存儲(chǔ)每個(gè)電平的持續(xù)時(shí)間,用于以后判斷是0還是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
}
}
else
{
irtime=0;
startflag=1;
}
}
先來分析一個(gè)這個(gè)程序,這個(gè)程序用了兩個(gè)中斷,一個(gè)定時(shí)器中斷,一個(gè)外斷中斷,程序的算法是讓定時(shí)器中斷不停的記數(shù),外部中斷在下降沒來臨的時(shí)候?qū)⑦@個(gè)記數(shù)值并將上一次記的數(shù)值存在一個(gè)數(shù)組中,不過這個(gè)程序有一個(gè)小Bug,就是那個(gè)startflag是沒有起到關(guān)鍵性的作用的啊?!其實(shí)編這個(gè)程序的程序員想的是用startflag,這個(gè)方法可以過濾過那一個(gè)引導(dǎo)碼,但是如果你足夠細(xì)心就會(huì)發(fā)現(xiàn)他沒有做startflag清0的操作,不過詭異的事情是即使這樣也沒有影響正常的解碼程序的運(yùn)行,其實(shí)只要你認(rèn)真分析一下就會(huì)發(fā)現(xiàn)有沒有startflag清0這一個(gè)判斷的條件其實(shí)沒有多大的意義,我的意思是有沒有這一條語句都不會(huì)影響正常的解碼,首先來分析原程序,也就是沒有startflag清0這一語句的情況,第一個(gè)引導(dǎo)碼來的時(shí)候,進(jìn)入else語句,將第一個(gè)引導(dǎo)碼過慮掉,進(jìn)入else語句的就是后面有用的解值了,第一次會(huì)執(zhí)行到if(irtime<54&&irtime>=50)這一條語句,因?yàn)橐龑?dǎo)碼的長(zhǎng)度剛好在這個(gè)范圍內(nèi),所以會(huì)執(zhí)行下會(huì)的一條i=0,也就是會(huì)把數(shù)組的下標(biāo)清0,然后會(huì)把相應(yīng)的32個(gè)紅外編碼存到數(shù)組中,注意這里的數(shù)組的長(zhǎng)度是33,而不是32,因?yàn)閕rdata[0]是用來存放引導(dǎo)碼的,還有一點(diǎn)非常值很注意,就是這32個(gè)有效的紅外數(shù)據(jù)接收完了之后,會(huì)有一個(gè)重復(fù)碼,這個(gè)重復(fù)碼和引導(dǎo)碼長(zhǎng)得很相似,這個(gè)我用示波器看過,這個(gè)重復(fù)碼可以看作是第34個(gè)波形,而且有一點(diǎn)非常值很注意,就是這個(gè)重復(fù)碼只要你按鍵不松手的話是一直會(huì)發(fā)的,所以如何處理這個(gè)重復(fù)碼的問題也是很關(guān)鍵的,至于這個(gè)問題我后面會(huì)有講到,現(xiàn)有我們先來將這個(gè)重復(fù)碼看成是第34個(gè)紅外碼,他的意義在于可以提供一個(gè)下降沿,有了這個(gè)下降沿就會(huì)將第32個(gè)紅外碼值存入data[32]中,所以最終的結(jié)果就是33個(gè)紅外編碼全部存入了容量為33的數(shù)組中,但是這時(shí)還有一個(gè)問題就是如果按鍵按下不放的話,后面還會(huì)有無數(shù)的波形啊,這時(shí)解碼程序還在不停的處理,后面的紅外編碼會(huì)存入第34,35,36……等后面的數(shù)組中,這是不希望看到的,這也會(huì)導(dǎo)致一個(gè)更加可怕的問題,那就是程序的溢出,那天在防真器上出現(xiàn)了這個(gè)問題決對(duì)就是這個(gè)原因.因?yàn)閿?shù)組只有33個(gè)元素,而在接收到這33個(gè)元素之后還沒有停止對(duì)紅外碼的接收,后面的元素繼續(xù)存入只有33個(gè)元素的數(shù)組中,必定會(huì)導(dǎo)致數(shù)據(jù)的溢出,也就是會(huì)彈出那樣的一個(gè)溢出的界面,我還記得當(dāng)天沒有接紅外接收管硬件的時(shí)候也會(huì)有這個(gè)溢出的窗口,那是因?yàn)楫?dāng)時(shí)沒有在中斷進(jìn)入這后將中斷標(biāo)志位清0,所以會(huì)一直有中斷進(jìn)來,從而這33個(gè)元素的數(shù)組就會(huì)很快存滿了,然后還在進(jìn)入不停的進(jìn)入中斷,最后導(dǎo)致這33個(gè)元素的數(shù)組全部存滿了還在不停的往里面存數(shù)據(jù),所以也會(huì)導(dǎo)致程序的溢出.所以以后就有了一條經(jīng)驗(yàn),那就是如果程序溢出了有一種可能性就是往一個(gè)固定長(zhǎng)度的數(shù)組中存入了大于其長(zhǎng)度的數(shù)據(jù).那么如何解決這個(gè)問題呢,一種可行的方法是這樣的,待33個(gè)紅外數(shù)據(jù)全部存完以后,置一個(gè)標(biāo)志,后面接收到的數(shù)據(jù)只要不是引導(dǎo)碼就做一次函數(shù)返回,當(dāng)接收到這個(gè)正確的引導(dǎo)碼以后才可以進(jìn)行下一輪數(shù)據(jù)的接收.
上面的這個(gè)問題暫且放下(只要搖控器發(fā)出的波形只有34個(gè)脈沖就不會(huì)出現(xiàn)上面的問題 ,這種搖控器的特點(diǎn)就是只要你按下一個(gè)按鍵不論你是不松手,它都只會(huì)發(fā)出一幀數(shù)據(jù),不會(huì)有后面的故慮),下面考慮第二幀數(shù)據(jù)的接收情況,當(dāng)?shù)诙䦷瑪?shù)據(jù)來臨的時(shí)候,由于沒有清0 startflag,程序會(huì)進(jìn)入if(startflag)這一個(gè)分支,也就是會(huì)處理引導(dǎo)碼的情況,這里會(huì)到下面的一條語句if(irtime<63&&irtime>=33),而這時(shí)irtime是一個(gè)隨機(jī)的數(shù),所以說這條語句有可能能被執(zhí)行到也有可能不會(huì)被執(zhí)行到,無論其是否能被執(zhí)行到,都無所謂,等下一個(gè)下降沿到來的時(shí)候那個(gè)時(shí)候irtime存入的才是引導(dǎo)碼的數(shù)據(jù),也就是直到第二個(gè)下降沿到來的時(shí)候,irdata的下標(biāo)才會(huì)清0,這時(shí)才會(huì)將引導(dǎo)碼存入irdata的第0個(gè)格子里面.而后的數(shù)據(jù)會(huì)將先前的數(shù)據(jù)覆蓋掉,也就消除了第一次接收到的數(shù)據(jù)的不穩(wěn)定因素.
如果有接收到第33個(gè)元素后將startflag清0.每次接收紅外的時(shí)候就和第一次的一樣了,還過即使是這樣也不能擺脫那個(gè)接收到重復(fù)碼的問題.下面是有startflag清0的程序.
/*-----------------------------------------------------------------------------------------
外部中斷0中斷處理
-----------------------------------------------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中斷0服務(wù)函數(shù)
{
static unsigned char i; //接收紅外信號(hào)處理
static bit startflag; //是否開始處理標(biāo)志位
if(startflag)
{
if(irtime<=54&&irtime>=50)//引導(dǎo)碼 TC9012的頭碼,9ms+4.5ms
{
i=0;
}
irdata[i]=irtime;//存儲(chǔ)每個(gè)電平的持續(xù)時(shí)間,用于以后判斷是0還是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
startflag=0;
}
}
else
{
irtime=0;
startflag=1;
}
}
下面做一個(gè)解決重復(fù)碼問題的程序:
/*-----------------------------------------------------------------------------------------
外部中斷0中斷處理
-----------------------------------------------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中斷0服務(wù)函數(shù)
{
static unsigned char i; //接收紅外信號(hào)處理
static bit startflag; //是否開始處理標(biāo)志位
if(statflag==1)
{
if(irtime<=54&&irtime>=50)//引導(dǎo)碼 TC9012的頭碼,9ms+4.5ms
{
i=0;
ir_flag=0; //接收到正確的引導(dǎo)碼,開始接收數(shù)據(jù)
}
else
{
return; //這個(gè)是33個(gè)紅外碼后面的重復(fù)碼,過濾掉他
}
If(ir_flag==0) //如果接收到引導(dǎo)碼才開始解碼
{
irdata[i]=irtime;//存儲(chǔ)每個(gè)電平的持續(xù)時(shí)間,用于以后判斷是0還是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
startflag=0;
ir_flag=1; //接收完33個(gè)數(shù)據(jù),清0接收數(shù)據(jù)位,即不再接收數(shù)據(jù)
}
}
else
{
startflag==1
i=0;
return;
}
}
這個(gè)程序有一個(gè)關(guān)鍵的地方,那就是那個(gè)引導(dǎo)碼的時(shí)間,程序就是通過這個(gè)時(shí)間來確定是否開始接收一幀數(shù)據(jù)的,真到接收到33個(gè)數(shù)據(jù)后將關(guān)閉數(shù)據(jù)的接收功能,直到有第二個(gè)引導(dǎo)碼的到來,才開始接收第二幀數(shù)據(jù).如果重復(fù)碼我這個(gè)引導(dǎo)碼很像,那么這個(gè)一點(diǎn)的時(shí)間的差別也是很關(guān)鍵的了,所以必須把握好這個(gè)時(shí)間,比如13.5ms,12M的晶振定時(shí)器計(jì)一次時(shí)間是256us比如把這個(gè)時(shí)間卡在13ms到14ms之間就應(yīng)該是13000/256=50,14000/256=54,也就是說應(yīng)該把兩個(gè)時(shí)間卡在50和54之間,這樣的精度才能保證將那些個(gè)重復(fù)碼的脈沖過濾掉,這個(gè)卡的越準(zhǔn)越好越小越好.也就這在邏輯上也是可行完美合理的程序.邏輯上就是要讓一幀數(shù)據(jù)接收完成之后停止數(shù)據(jù)的接收功能.上面各全局變量的初始化情況為ir_flag=0;startflag=0;
想一想如果這個(gè)程序像下面這樣會(huì)有什么后果,即去掉startflag這個(gè)標(biāo)置,會(huì)有什么后果?
/*-----------------------------------------------------------------------------------------
外部中斷0中斷處理
-----------------------------------------------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中斷0服務(wù)函數(shù)
{
static unsigned char i; //接收紅外信號(hào)處理
static bit startflag; //是否開始處理標(biāo)志位
if(irtime<=54&&irtime>=50)//引導(dǎo)碼 TC9012的頭碼,9ms+4.5ms
{
i=0;
ir_flag=0; //接收到正確的引導(dǎo)碼,開始接收數(shù)據(jù)
}
else
{
return; //這個(gè)是重復(fù)碼,過濾掉他
}
If(ir_flag==0)
{
irdata[i]=irtime;//存儲(chǔ)每個(gè)電平的持續(xù)時(shí)間,用于以后判斷是0還是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
ir_flag=1; //接收完33個(gè)數(shù)據(jù),清0接收數(shù)據(jù)位,即不再接收數(shù)據(jù)
}
}
}
這個(gè)程序沒有用startflag這個(gè)標(biāo)置,也就不能保證接收到的第一個(gè)脈沖是引導(dǎo)碼了,這時(shí)會(huì)有一個(gè)隨機(jī)的數(shù)存入irtime,如果這個(gè)隨機(jī)數(shù)是和引導(dǎo)碼的irtime相似的話,就會(huì)造成解碼的開啟,第二個(gè)碼,也就是引導(dǎo)碼會(huì)存入irdata[1]中,后面所有的碼就會(huì)依次往后推移一次,這樣的話第33個(gè)紅外碼就會(huì)丟失掉,也就去直接導(dǎo)致解碼的失敗.所以說完美的程序應(yīng)該是上面的那個(gè)程序.(這段話說的不對(duì),那個(gè)i=0的操作會(huì)把數(shù)組的下標(biāo)做一下清0,也就不存在移位的問題了.)
特別糾正一下本文的錯(cuò)誤之處,上面的兩個(gè)程序都是有問題的,正確的程序應(yīng)該是下面的程序,看完這個(gè)程序再來說明上面程序不正確的地方.
/*-----------------------------------------------------------------------------------------
外部中斷0中斷處理
-----------------------------------------------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中斷0服務(wù)函數(shù)
{
static unsigned char i; //接收紅外信號(hào)處理
static bit startflag; //是否開始處理標(biāo)志位
if(irtime<=54&&irtime>=50)//引導(dǎo)碼 TC9012的頭碼,9ms+4.5ms
{
i=0;
ir_flag=0; //接收到正確的引導(dǎo)碼,開始接收數(shù)據(jù)
}
if(ir_flag==1)
{
irtime=0;
return; //這個(gè)是重復(fù)碼,過濾掉他
}
If(ir_flag==0)
{
irdata[i]=irtime;//存儲(chǔ)每個(gè)電平的持續(xù)時(shí)間,用于以后判斷是0還是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
ir_flag=1; //接收完33個(gè)數(shù)據(jù),清0接收數(shù)據(jù)位,即不再接收數(shù)據(jù)
}
}
}
上面的那兩個(gè)程序都不能按照正常的算法實(shí)現(xiàn),關(guān)鍵在于有一個(gè)原因,那個(gè)else語句沒有做irtime清零的操作,這樣就會(huì)導(dǎo)致一個(gè)問題,就是下一個(gè)下降沿到來的時(shí)候不能反正確的兩個(gè)下降沿之間的時(shí)間存入數(shù)中,存入的是不確定的數(shù),所以說irtime清零這一步操作還是很有必要的,試想下一個(gè)正確的引導(dǎo)碼到的的時(shí)候,沒有irtime清0的操作也就不能識(shí)別能正確的引導(dǎo)碼,也就不能夠?qū)崿F(xiàn)解碼的開啟,也就不能夠?qū)崿F(xiàn)正確的解碼,不過上面的程序還是有一個(gè)問題,那就是他沒有用startflag,也就會(huì)存在上面提到的那個(gè)問題,也說是說當(dāng)有一個(gè)隨機(jī)數(shù),也就是下一幀數(shù)據(jù)開始接收時(shí)的第一個(gè)碼,那個(gè)數(shù)就是一個(gè)隨機(jī)數(shù),如果那個(gè)數(shù)剛好是在引導(dǎo)碼的時(shí)間區(qū)間內(nèi),那么就是惡夢(mèng)的開始,也就是說會(huì)和上面的錯(cuò)誤一樣,這個(gè)隨機(jī)數(shù)會(huì)存入irdata[0],引導(dǎo)碼會(huì)存入irdata[1]中,下面的所有碼都依次往下移一位,也說是說會(huì)有一位碼沒有存入這33個(gè)數(shù)據(jù)碼中(包括引導(dǎo)碼). (這段話說的不對(duì),那個(gè)i=0的操作會(huì)把數(shù)組的下標(biāo)做一下清0,也就不存在移位的問題了.)所以說這個(gè)程序可以說是一個(gè)比效完美的程序了
下面是另一種編程的方法.
/*-----------------------------------------------------------------------------------------
外部中斷0中斷處理
-----------------------------------------------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中斷0服務(wù)函數(shù)
{
static unsigned char i; //接收紅外信號(hào)處理
static bit startflag; //是否開始處理標(biāo)志位
if(statflag==1)
{
if(irtime<=54&&irtime>=50)//引導(dǎo)碼 TC9012的頭碼,9ms+4.5ms
{
i=0;
ir_flag=0; //接收到正確的引導(dǎo)碼,開始接收數(shù)據(jù)
}
if(ir_flag==0)
{
irtime=0;
startflag=0;
return; //這個(gè)是33個(gè)紅外碼后面的重復(fù)碼,過濾掉他
}
If(ir_flag==1) //如果接收到引導(dǎo)碼才開始解碼
{
irdata[i]=irtime;//存儲(chǔ)每個(gè)電平的持續(xù)時(shí)間,用于以后判斷是0還是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
startflag=0;
ir_flag=1; //接收完33個(gè)數(shù)據(jù),清0接收數(shù)據(jù)位,即不再接收數(shù)據(jù)
}
}
else
{
startflag==1
i=0;
return;
}
}
這個(gè)程序的算法是那些重復(fù)碼會(huì)隔一個(gè)進(jìn)入解碼程序一個(gè),進(jìn)處解碼程序的那個(gè)又會(huì)被過濾掉,也說是說第一個(gè)重復(fù)碼的下降沿會(huì)進(jìn)入else starflag=1……的那個(gè)語句.下一個(gè)重復(fù)碼的下降沿會(huì)被過濾掉,因?yàn)樗粷M足那個(gè)引導(dǎo)碼時(shí)間的那個(gè)條件.所以他會(huì)被過濾掉.這就要求那個(gè)引導(dǎo)碼的時(shí)間要足夠的準(zhǔn)確,范圍也要足夠的小,如果重復(fù)碼和引導(dǎo)碼比效相似的話那么事情就不妙了,那個(gè)條件就起不到過濾的作用了.這個(gè)嚴(yán)酷的條件也是這個(gè)程序的精髓.
本文未完下接<幾種比較流行和成熟的紅外解碼程序做一下研究和總結(jié)2>:http://www.zg4o1577.cn/mcu/4353.html