今天下午的時候,調試努力之下,終於把紅外解碼弄出來了。其實以前有次比賽的時候就已經用到了紅外,只是那次用的是51單片機,用的是外部中斷和延時檢測脈寬來進行解碼,因為51的時鐘這些比較簡單,所以解碼很容易就正確了。但是現在換到了ARM7平台下,由於對它的不是很熟悉,怎麼用普通語句實現精確延時對我來說是個痛點。最後考慮用兩個方案來實現紅外的解碼。方案一是用外部中斷加定時器延時檢測脈寬進行解碼,但是結果並沒有我想的那樣美好,調試了半天也沒有實現正確的解碼,個人認為是任務節拍的影響,但是確實不知道該怎麼修改,最後放棄方案一,改用方案二,用定時器捕獲實現紅外的解碼,並最終實現。
LPC2103晶片帶有定時器捕獲,可以設定為下降沿,上升沿或雙邊沿捕獲中斷。因為結合到此款紅外編碼方式,所以採用下降沿進行捕獲。定時器0因為用作了系統節拍定時器,所以我選擇了定時器1的捕獲。
定時器1進行如下的初始化。
void SetTimer(void){T1TCR = 0x02;//關閉複位定時器1T1PR = 10;//11分頻,約1us計時一次(外設時鐘11.0592MHZ)T1CCR = 0x06;//下降沿捕獲併產生中斷T1IR = 0x10;//清除定時器1捕獲0中斷T1TCR = 0x01;//開啟定時器1VICVectAddr1 = (uint32)Timer1_Handler;//中斷向量相關設定 VICVectCntl1 = (0x20 | 0x05);VICIntEnable |= (1 << 5);}
然後在定時器1中斷服務函數裡,就算出相鄰兩次下降沿之間的差值。然後通過訊息郵箱把訊息發送到脈寬檢測任務進行處理。
void Timer1_Exception(){static uint32 tOld; //儲存舊的下降沿捕獲值uint32 tNew;//儲存新的下降沿捕獲值static i;OS_ENTER_CRITICAL();T1IR = 0x10;//清除定時器1捕獲0中斷tNew = T1CR0;tValue = tNew - tOld;//得到兩次下降沿之間的差值tOld = tNew; //以便下次中斷處理OSMboxPost(Msg,(void*)tValue); //發送訊息郵箱,行為同步OS_EXIT_CRITICAL();VICVectAddr = 0x00;}
在檢測脈寬任務裡,我只需要根據測定脈寬與本來編碼原有的脈寬進行比較判斷,然後進行相關移位元據操作,得到資料碼值。
因為我的遙控器有點不同,地址碼與地址反碼不互反,所以不能進行地址的判斷,所以濾除掉了引導碼與地址碼,直接進行了資料碼的處理。
只要資料碼與資料反碼取反相同,則調試LED閃爍一下。
當然我還沒有具體知道遙控器按鍵對應的具體碼制是多少,而且還沒有檢測到連發碼,留待下次把碼制通過串口發送到上位機進行顯示。
這是檢測脈寬任務的核心代碼:
while (1){OSMboxPend(Msg, 0, &err);//等待脈寬檢測訊息if(tValue>2145 && tValue<2345)//進行脈寬檢測{ucTemp = 1;//邏輯1}else if(tValue>1025 && tValue<1225){ucTemp = 0;//邏輯0}else if(tValue>13400 && tValue<13600){ucCounter = 0;//引導碼usData0 = 0;usData1= 0;flag = 1;}else{continue;}if(flag)//資料處理過程{ucCounter++;if(ucCounter<16){usData0 |= (uint16)ucTemp;usData0 <<= 1;}else if(ucCounter == 16){usData0 |= (uint16)ucTemp;}else if(ucCounter < 32){usData1 |= (uint16)ucTemp;usData1 <<= 1;}else if(ucCounter == 32){usData1 |= (uint16)ucTemp;flag = 0;OSSemPost(Sem);//發送訊號量,進行碼制轉換任務,我的工作只是簡單的實現了判斷解碼是否成功。}}}