1.器件簡介ide
本次測試採用R903V1紅外接收頭與NEC協議的紅外遙控器,接收頭原理圖以下:函數
器件的供電電壓VCC在2.7V~5.5V之間,輸出電壓VOUT正常在0.2v ~(VCC-0.3±0.2)v,注意高低電平輸出脈衝寬度最小都在400us~800us之間。測試
NEC 碼的位定義:一個脈衝對應 560us 的連續載波,一個邏輯 1 傳輸須要 2.25ms(560us脈衝+1680us 低電平),一個邏輯 0 的傳輸須要 1.125ms(560us 脈衝+560us 低電平)。而遙控接收頭在收到脈衝的時候爲低電平,在沒有脈衝的時候爲高電平,這樣,咱們在接收頭端收到的信號爲:邏輯 1 應該是 560us 低+1680us 高,邏輯 0 應該是 560us 低+560us 高。同時NEC碼還規定了連發碼由 9ms 低電平+2.5m 高電平+0.56ms 低電平+97.94ms 高電平組成。ui
NEC協議的數據格式:同步碼頭、地址碼、地址反碼、控制碼、控制反碼。同步碼由一個 9ms 的低電平和一個 4.5ms 的高電平組成,地址碼、地址反碼、控制碼、控制反碼均是8 位數據格式。正常是按照低位在前,高位在後的順序發送,可是我測試是按照高位在前,低位在後的。採用反碼是爲了增長傳輸的可靠性(可用於校驗)。spa
2.硬件鏈接設計
簡單說一下,紅外接收器電壓接3.3V,VOUT鏈接單片機的輸入捕獲引腳便可。3d
3.軟件設計code
使用stm32單片機的輸入捕獲功能,用stm32cubemx進行設置:blog
這裏解釋主要參數部分:input
prescaler:預分頻器,設置爲72
counter mode:計數模式,設爲向上計數
counter period:計數週期,設爲65535
polarity selection:邊沿檢測方式,選擇降低沿檢測,程序裏仍是改爲了上升沿檢測
input filter:輸入濾波器,設爲8,是指連續採集到8個同樣的高/低電平才計做高/低電平
在MAIN中開啓輸入捕獲:
while (1) { switch(cap_state) { case 0: __HAL_TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);//設置爲上升沿捕獲 HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_2); //啓動輸入捕獲 cap_state++; break; } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ }
/定時器輸入捕獲中斷回調函數 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕獲中斷髮生時執行 { if(htim->Instance==TIM5) { switch(cap_state) { case 1: rise_value[rise_i] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_2);//取上升沿時刻 __HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING); //設置爲降低沿捕獲 cap_state++; break; case 2: fall_value[fall_i] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_2);//取降低沿時刻 if(fall_value[fall_i] > rise_value[rise_i]) { rising_time[t_i] = fall_value[fall_i] - rise_value[rise_i];//高電平時間獲取 }else { rising_time[t_i] = 65535 + fall_value[fall_i] - rise_value[rise_i];//高電平時間獲取 } //控制碼 if(same_i == 1) { cnt+=1; //地址碼1~8 if(t_i<8) { if(rising_time[t_i]>500&&rising_time[t_i]<600) { address <<= 1; address+=0; }else if(rising_time[t_i]>1500&&rising_time[t_i]<1800) { address <<= 1; address+=1; } }else if(t_i>16&&t_i<25)//控制碼17~24 { if(rising_time[t_i]>500&&rising_time[t_i]<600) { rec <<= 1; rec+=0; }else if(rising_time[t_i]>1500&&rising_time[t_i]<1800) { rec <<= 1; rec+=1; } } t_i++; rise_i++; fall_i++; } //同步碼 if(rising_time[t_i]>4300&&rising_time[t_i]<4700) { //同步碼正確 same_i=1; t_i++; rise_i++; fall_i++; } HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_2); //中止捕獲 cap_state=0; break; } } }
//按鍵中斷回調 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { //KEY0 if (GPIO_Pin==GPIO_PIN_5) { HAL_Delay(20);/* 延時一小段時間,消除抖動 */ if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5)==0) { HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); for(int i=0;i<=fall_i;i++) { if(fall_value[i] > rise_value[i]) { rising_time[i] = fall_value[i] - rise_value[i];//高電平時間獲取 }else { rising_time[i] = 65535 + fall_value[i] - rise_value[i];//高電平時間獲取 printf("hear:%d\r\n",i); } printf("高電平[%d]:%d us 降低沿時刻[%d]:%d us 上升沿時刻[%d]:%d us\r\n",i,rising_time[i],i,fall_value[i],i,rise_value[i]); } printf("地址:%d 控制碼:%lld\r\n",address,rec); rise_i=fall_i=same_i=t_i=cnt=address=rec=0; } __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_5); } }
大體說一下程序流程,在main中循環開啓上升沿檢測輸入捕獲功能(case 0),接着在輸入捕獲中斷回調裏記下上升沿觸發時刻(rise_value),並改成降低沿檢測捕獲,再記下降低沿觸發時刻(fall_value)並關閉捕獲功能。
高電平持續時間(rising_time) = 降低沿觸發時刻(fall_value) - 上升沿觸發時刻(rise_value)
獲取到一系列高電平之後(看示波器圖),根據高電平持續時間進行數值移位換算,能夠獲得對應的地址碼和控制碼,串口打印以下:
打印結果中的hear是降低沿時刻溢出的狀況,計算時須要在降低沿時刻基礎上再加65535才能夠。
感興趣的能夠試一試,須要原工程的留言我發。