紅外遙控是一種比較常用的通訊方式,目前紅外遙控的編碼方式中,應用比較廣泛的是NEC協議。
NEC協議的特點如下:
其邏輯1與邏輯0的表示,如下圖所示:

可以看到,邏輯1的位時間為2.25ms,脈沖時間560us;邏輯0的位時間為1.12ms,脈沖時間560us。
一個完整的NEC數據包如下:

首次發送的是9ms高電平+4.5ms低電平,為引導碼。
接下來是8bit的地址碼+8bit地址碼的反碼+8bit命令碼+8bit命令碼的反碼。
以上是一個正常的數據包,但可能存在一種情況:當長按某個鍵時,發送的是以110ms為周期的重復碼,如下圖所示:

重復碼由9ms高電平和2.25ms的低電平以及560us的高電平組成。
二、解碼程序? ? ? ??
在上面的圖中可以看到,邏輯1和邏輯0的位時間是不同的,占空比也不同。所以我們可以根據位時間的長短來解碼,也可以根據占空比的不同(1/2或1/4)來解碼,或者二者同時作為解碼條件,這里我們介紹根據位時間來解碼。
需要注意的是,很多紅外一體接收頭為了提高接受靈敏度。輸入高電平,其輸出的是相反的低電平。
下圖為示波器實際捕獲的一組數據:



uint32_t TIM3_Over_Cnt = 0;//tim3溢出次數uint32_t TIM3_Sum_Cnt = 0;//兩次下降沿之間的時間間隔uint32_t cnt0 = 0;uint8_t IR_Data[60];void TIM3_IRQHandler(void){/* USER CODE BEGIN TIM3_IRQn 0 *//* USER CODE END TIM3_IRQn 0 */// HAL_TIM_IRQHandler(&htim3);/* USER CODE BEGIN TIM3_IRQn 1 */if(__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE)) //定時器溢出中斷{__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_UPDATE); //清除中斷標記TIM3_Over_Cnt++;}cnt0 = __HAL_TIM_GET_COUNTER(&htim3);TIM3_Sum_Cnt = (TIM3_Over_Cnt << 16) + cnt0;//獲取計數器的值__HAL_TIM_SetCounter(&htim3,0);//清零重新計數TIM3_Over_Cnt = 0;//清零重新計數if (__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_CC1) != RESET)//TIM3CH1捕獲中斷{if(StartRevFlag == 1)//接收到引導碼,開始解碼{if(TIM3_Sum_Cnt > 36000)//大于36ms認為是結束{RevComplete = 1;//解碼完成IR_Tick = 0;}else if(RevComplete == 0){if(TIM3_Sum_Cnt > 1000 && TIM3_Sum_Cnt < 1300)//1ms~1.3ms認為是低電平IR_Data[IR_Idx] = 0;else if(TIM3_Sum_Cnt > 2100 && TIM3_Sum_Cnt < 2400)//2.1ms~2.4ms認為是高電平IR_Data[IR_Idx] = 1;else //接收錯誤,重新開始StartRevFlag = 0;IR_Idx++;if(IR_Idx > 59)IR_Idx = 59;}}else{if(TIM3_Sum_Cnt > 13000 && TIM3_Sum_Cnt < 14000)//13~14ms引導碼{StartRevFlag = 1;}IR_Tick = 0;RevComplete = 0;//解碼完成標志置零IR_Idx = 0;//有效解碼位TIM3_Over_Cnt = 0;TIM3_Sum_Cnt = 0;//定時器計數清零}__HAL_TIM_CLEAR_IT(&htim3, TIM_IT_CC1);}/* USER CODE END TIM3_IRQn 1 */}
解碼程序根據每次捕獲下降沿之間的間隔判斷是引導碼還是邏輯1或邏輯0,接收到引導碼之后,再開始將解碼的數據保存下來,最后通過也是時長來判斷解碼結束。這里沒有判斷重復碼,有興趣的小伙伴可以自己加上。
void IR_Rev(){uint8_t num = IR_Idx / 8;uint8_t IRValue[8];if(RevComplete == 1 && StartRevFlag == 1 && IR_Tick > 20){if(num > 7)num = 7;for(uint8_t j=0;j//將每一位解碼數據組合成字節數據 {for(uint8_t i = 0;i< 8;i++){IRValue[j] = IRValue[j]>>1;if(IR_Data[j*8+i])IRValue[j] |= 0x80;}}if(IRValue[0] == 0x00 && IRValue[1] == 0xFF)//地址碼正確{??????switch(IRValue[2])//判斷數據碼{case 0x46:KeyValue = S_key_Menu;break;case 0x43:KeyValue = S_key_Set;break;case 0x40:KeyValue = S_key_Rst;break;case 0x15:KeyValue = S_key_Down;break;case 0x09:KeyValue = S_key_Up;??????????break;}}StartRevFlag = 0;RevComplete = 0;IR_Tick = 0;}}

END
來源:嵌入式技術開發
→點關注,不迷路←