stm32與紅外遙控器(NEC協議)

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 */
  }
main循環體
/定時器輸入捕獲中斷回調函數
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才能夠。

感興趣的能夠試一試,須要原工程的留言我發。

相關文章
相關標籤/搜索