1.NEC協(xié)議
?????????紅外遙控是一種比較常用的通訊方式,目前紅外遙控的編碼方式中,應(yīng)用比較廣泛的是NEC協(xié)議。NEC協(xié)議的特點(diǎn)如下:
- 載波頻率為 38KHz
- 8位地址和 8位指令長度
- 地址和命令2次傳輸(確??煽啃裕?/span>
- PWM 脈沖位置調(diào)制,以發(fā)射紅外載波的占空比代表“0”和“1”
????????其邏輯1與邏輯0的表示如圖所示:
????????可以看到,邏輯1的位時(shí)間為2.25ms,脈沖時(shí)間560us;邏輯0的位時(shí)間為1.12ms,脈沖時(shí)間560us。
????????一個(gè)完整的NEC數(shù)據(jù)包如下:
????????首次發(fā)送的是9ms高電平+4.5ms低電平,為引導(dǎo)碼。
????????接下來是8bit的地址碼+8bit地址碼的反碼+8bit命令碼+8bit命令碼的反碼。
????????以上是一個(gè)正常的數(shù)據(jù)包,但可能存在一種情況:當(dāng)長按某個(gè)鍵時(shí),發(fā)送的是以110ms為周期的重復(fù)碼,如下圖:
????????重復(fù)碼由9ms高電平和2.25ms的低電平以及560us的高電平組成。
2.解碼程序
????????在上面的圖中可以看到,邏輯1和邏輯0的位時(shí)間是不同的,占空比也不同。所以我們可以根據(jù)位時(shí)間的長短來解碼,也可以根據(jù)占空比的不同(1/2或1/4)來解碼,或者二者同時(shí)作為解碼條件。這里我們介紹根據(jù)位時(shí)間來解碼。
????????需要注意的是,很多紅外一體接收頭為了提高接受靈敏度。輸入高電平,其輸出的是相反的低電平。下圖為示波器實(shí)際捕獲的一組數(shù)據(jù):
?
????????可以看到,空閑時(shí)為高電平,引導(dǎo)碼為9ms低電平+4.5ms高電平。根據(jù)位時(shí)間解碼的話,我們就不必關(guān)系高低電平各自的時(shí)間,只需關(guān)系總時(shí)間就行,即:引導(dǎo)碼-13.5ms,邏輯1-2.25ms,邏輯0-1.12ms。
????????首先用STM32CubeMx配置定時(shí)器。系統(tǒng)時(shí)鐘等的配置這里不在贅述,參考其它教程。
????????這里使用TIM3的Channel1作為捕獲通道配置如下:
- 定時(shí)器時(shí)鐘為內(nèi)部時(shí)鐘
- Channel1配置為輸入捕獲模式
- 分頻系數(shù)為63,因?yàn)橄到y(tǒng)時(shí)鐘為64M,這樣定時(shí)器實(shí)際時(shí)鐘為64/(63+1)=1M,主要是為了程序中方便計(jì)算。
- 捕獲方式為下降沿捕獲
- 最后別忘了打開定時(shí)器的中斷
????????最后生成代碼。在生成的TIM3中斷函數(shù)中,屏蔽生成的中斷處理還是,添加自己的解碼程序如下:
uint32_t TIM3_Over_Cnt = 0;//tim3溢出次數(shù)
uint32_t TIM3_Sum_Cnt = 0;//兩次下降沿之間的時(shí)間間隔
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)) //定時(shí)器溢出中斷
{
__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_UPDATE); //清除中斷標(biāo)記
TIM3_Over_Cnt++;
}
cnt0 = __HAL_TIM_GET_COUNTER(&htim3);
TIM3_Sum_Cnt = (TIM3_Over_Cnt << 16) + cnt0;//獲取計(jì)數(shù)器的值
__HAL_TIM_SetCounter(&htim3,0);//清零重新計(jì)數(shù)
TIM3_Over_Cnt = 0;//清零重新計(jì)數(shù)
if (__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_CC1) != RESET)//TIM3CH1捕獲中斷
{
if(StartRevFlag == 1)//接收到引導(dǎo)碼,開始解碼
{
if(TIM3_Sum_Cnt > 36000)//大于36ms認(rèn)為是結(jié)束
{
RevComplete = 1;//解碼完成
IR_Tick = 0;
}
else if(RevComplete == 0)
{
if(TIM3_Sum_Cnt > 1000 && TIM3_Sum_Cnt < 1300)//1ms~1.3ms認(rèn)為是低電平
IR_Data[IR_Idx] = 0;
else if(TIM3_Sum_Cnt > 2100 && TIM3_Sum_Cnt < 2400)//2.1ms~2.4ms認(rèn)為是高電平
IR_Data[IR_Idx] = 1;
else //接收錯(cuò)誤,重新開始
StartRevFlag = 0;
IR_Idx++;
if(IR_Idx > 59)
IR_Idx = 59;
}
}
else
{
if(TIM3_Sum_Cnt > 13000 && TIM3_Sum_Cnt < 14000)//13~14ms引導(dǎo)碼
{
StartRevFlag = 1;
}
IR_Tick = 0;
RevComplete = 0;//解碼完成標(biāo)志置零
IR_Idx = 0;//有效解碼位
TIM3_Over_Cnt = 0;
TIM3_Sum_Cnt = 0;//定時(shí)器計(jì)數(shù)清零
}
__HAL_TIM_CLEAR_IT(&htim3, TIM_IT_CC1);
}
/* USER CODE END TIM3_IRQn 1 */
}
????????解碼程序根據(jù)每次捕獲下降沿之間的間隔判斷是引導(dǎo)碼還是邏輯1或邏輯0。接收到引導(dǎo)碼之后,再開始將解碼的數(shù)據(jù)保存下來。最后通過也是時(shí)長來判斷解碼結(jié)束。這里沒有判斷重復(fù)碼,有興趣的小伙伴可以自己加上。
?????????中斷函數(shù)中,只是將每一位解碼并保存,最后還需要在主程序中組合成字節(jié)并判斷處理。文章來源:http://www.zghlxwxcb.cn/news/detail-436833.html
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<num;j++)//將每一位解碼數(shù)據(jù)組合成字節(jié)數(shù)據(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])//判斷數(shù)據(jù)碼
{
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;
}
}
???????文章來源地址http://www.zghlxwxcb.cn/news/detail-436833.html
到了這里,關(guān)于STM32定時(shí)器實(shí)現(xiàn)紅外接收與解碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!