0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

紅外通信協(xié)議的發(fā)送與接收處理方法

CHANBAEK ? 來源:小陳學(xué)不停 ? 作者:小陳學(xué)不停 ? 2023-01-12 17:14 ? 次閱讀

一 背景

最近在調(diào)試紅外通信功能的時(shí)候遇到了很多問題,在此總結(jié)一下,希望能幫到未來對此有疑問的自己,如果有幸能幫到其他人也算是做了一件有意義的事情了。

二 紅外發(fā)射頭與紅外接收頭

2.1 發(fā)射頭

發(fā)射管也屬于二極管,只有兩個(gè)腳,通過控制二極管的導(dǎo)通來發(fā)射信號

2.2 接收頭

接收管一般有三個(gè)腳,一個(gè)VCC,一個(gè)GND,還有一個(gè)信號腳。

2.3 起始信號、邏輯0、邏輯1的定義

通常在控制發(fā)射端時(shí),以38KHz的頻率來發(fā)送方波,此時(shí)發(fā)送端需要以高低電平來控制,接收頭收到的是一個(gè)低電平,其他情況下為高電平。

2.3.1 起始信號

參考紅外遙控器中引導(dǎo)碼

-發(fā)送端波形

9ms發(fā)送方波,4.5ms不發(fā)送方波

-接收端波形

9ms是低電平,4.5ms是高電平

2.3.2 邏輯1

2.3.3 邏輯0

三 發(fā)送與接收處理

3.1 延時(shí)API

rtthread官方提供了一個(gè)微妙延時(shí)函數(shù)rt_hw_us_delay,在延時(shí)低于1000us時(shí)會有延時(shí)不準(zhǔn)的問題,這里稍作一些修改,如果想要更準(zhǔn)確的延時(shí)可能要用定時(shí)器的方式了。

void rt_hw_us_delay_2(rt_uint32_t us)
{
  rt_uint32_t ticks;
  rt_uint32_t told, tnow, tcnt = 0;
  rt_uint32_t reload = SysTick->LOAD;


  ticks = us * reload / (1000000UL / RT_TICK_PER_SECOND);
  told = SysTick->VAL;
  while (1)
  {
      tnow = SysTick->VAL;
      if (tnow != told)
      {
          if (tnow < told)
          {
              tcnt += told - tnow;
          }
          else
          {
              tcnt += reload - tnow + told;
          }
          told = tnow;
          if (tcnt >= ticks)
          {
              break;
          }
      }
  }
}


void rt_hw_us_delay(rt_uint32_t us)
{
    if (us < 1000)
    {
      __IO uint32_t currentTicks = SysTick->VAL;
      /* Number of ticks per millisecond */
      const uint32_t tickPerMs = SysTick->LOAD + 1;
      /* Number of ticks to count */
      const uint32_t nbTicks = ((us - ((us > 0) ? 1 : 0)) * tickPerMs) / 1000;
      /* Number of elapsed ticks */
      uint32_t elapsedTicks = 0;
      __IO uint32_t oldTicks = currentTicks;
      do 
      {
        currentTicks = SysTick->VAL;
        elapsedTicks += (oldTicks < currentTicks) ? tickPerMs + oldTicks - currentTicks :
                        oldTicks - currentTicks;
        oldTicks = currentTicks;
      } while (nbTicks > elapsedTicks);
    }
    else
    {
      rt_hw_us_delay_2(us);
    }
}

3.2 時(shí)間相關(guān)的宏定義

#define CONFIG_IR_FREQUENCY_HZ                ((uint32_t)38000)  
#define CONFIG_IR_FREQUENCY_US                ((uint32_t)(1000000UL*1/CONFIG_IR_FREQUENCY_HZ)) 
#define CONFIG_IR_DELAY_US                    (CONFIG_IR_FREQUENCY_US/2) 
#define ROUND_UP(M,N)                         (((M*10/N)+5)/10)
#define CONFIG_IR_TIME_ERROR_PERCENT          (30)  
#define TIME_GET_ERROR_MIN(T)                 (T-((T*CONFIG_IR_TIME_ERROR_PERCENT)/100))
#define TIME_GET_ERROR_MAX(T)                 (T+((T*CONFIG_IR_TIME_ERROR_PERCENT)/100))
#define CONFIG_IR_START_LOW_US                ((uint32_t)9000)   
#define CONFIG_IR_START_HIGH_US               ((uint32_t)4500) 
#define CONFIG_IR_START_HIGH_US_MIN           TIME_GET_ERROR_MIN(CONFIG_IR_START_HIGH_US)
#define CONFIG_IR_START_HIGH_US_MAX           TIME_GET_ERROR_MAX(CONFIG_IR_START_HIGH_US)


#define CONFIG_IR_COMMON_LOW_US               ((uint32_t)500)   
#define CONFIG_IR_COMMON_LOW_US_MIN           TIME_GET_ERROR_MIN(CONFIG_IR_COMMON_LOW_US)
#define CONFIG_IR_COMMON_LOW_US_MAX           TIME_GET_ERROR_MAX(CONFIG_IR_COMMON_LOW_US)


#define CONFIG_IR_LOGIC_0_HIGH_US             ((uint32_t)800)   
#define CONFIG_IR_LOGIC_0_HIGH_US_MIN         TIME_GET_ERROR_MIN(CONFIG_IR_LOGIC_0_HIGH_US)
#define CONFIG_IR_LOGIC_0_HIGH_US_MAX         TIME_GET_ERROR_MAX(CONFIG_IR_LOGIC_0_HIGH_US)


#define CONFIG_IR_LOGIC_1_HIGH_US             ((uint32_t)1500)  
#define CONFIG_IR_LOGIC_1_HIGH_US_MIN         TIME_GET_ERROR_MIN(CONFIG_IR_LOGIC_1_HIGH_US)
#define CONFIG_IR_LOGIC_1_HIGH_US_MAX         TIME_GET_ERROR_MAX(CONFIG_IR_LOGIC_1_HIGH_US)

3.3 信號發(fā)送API

#define IR_H() {GPIOE->BSRR = GPIO_PIN_0;}
#define IR_L() {GPIOE->BRR = GPIO_PIN_0;}


void ir_send_signal(uint16_t wave_us,uint16_t high_us)
{
    if (wave_us)
    {
        wave_us = ROUND_UP(wave_us,CONFIG_IR_FREQUENCY_US);
        while (wave_us--)
        {
            IR_H(); 
            rt_hw_us_delay(CONFIG_IR_DELAY_US); 
            IR_L(); 
            rt_hw_us_delay(CONFIG_IR_DELAY_US); 
        }
    }


    if (high_us)
    {
        high_us = ROUND_UP(high_us,CONFIG_IR_FREQUENCY_US);
        while (high_us--)
        {
            rt_hw_us_delay(CONFIG_IR_FREQUENCY_US); 
        }
    }
}

3.4 紅外通信指令的定義

3.4.1 指令組成

起始信號+cmd+data+sum

3.4.2 高位先發(fā)

3.5 發(fā)送指令A(yù)PI

void ir_send_data(uint8_t set_type,uint8_t set_data)
{
    unsigned char i;
    for (i = 0; i < 8; i++)
    {
        if (set_data & 0x80)//先發(fā)送高位
        {
            ir_send_signal(CONFIG_IR_COMMON_LOW_US,CONFIG_IR_LOGIC_1_HIGH_US);
        }
        else
        {
            ir_send_signal(CONFIG_IR_COMMON_LOW_US,CONFIG_IR_LOGIC_0_HIGH_US);
        }
        set_data <<= 1;
    }
}
void ir_send_cmd(uint8_t set_cmd,uint8_t set_data)
{
    uint8_t send_idx = 0;
    //start 
    ir_send_signal(CONFIG_IR_START_LOW_US,CONFIG_IR_START_HIGH_US);
    ir_send_data(set_cmd);
    ir_send_data(set_data);
    ir_send_data(set_cmd+set_data);
    ir_send_signal(CONFIG_IR_COMMON_LOW_US,0);
}

3.6 接收處理

stm32可以使用定時(shí)器輸入捕獲的方式來獲取上升沿的時(shí)間,從而得到當(dāng)前的信號類型

3.6.1基于紅外遙控修改

void ir_timer_init(void)
{
    TIM_IC_InitTypeDef TIM3_Config;  
    htim3.Instance=TIM3;                          
    htim3.Init.Prescaler=(72-1);                   //預(yù)分頻器,1M的計(jì)數(shù)頻率,1us加1.
    htim3.Init.CounterMode=TIM_COUNTERMODE_UP;   
    htim3.Init.Period=10000;                      
    htim3.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_IC_Init(&htim3);
    TIM3_Config.ICPolarity=TIM_ICPOLARITY_RISING;    //上升沿捕獲
    TIM3_Config.ICSelection=TIM_ICSELECTION_DIRECTTI;
    TIM3_Config.ICPrescaler=TIM_ICPSC_DIV1;          
    TIM3_Config.ICFilter=0x03;                     
    HAL_TIM_IC_ConfigChannel(&htim3,&TIM3_Config,TIM_CHANNEL_1);
    HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);  
    __HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE);  
}
  
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if (htim->Instance==TIM3)
  {
    __HAL_RCC_TIM3_CLK_ENABLE(); 
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    HAL_NVIC_SetPriority(TIM3_IRQn,1,3);   //設(shè)置中斷優(yōu)先級,搶占優(yōu)先級1,子優(yōu)先級3
    HAL_NVIC_EnableIRQ(TIM3_IRQn);         //開啟ITM4中斷
  }
}


void TIM3_IRQHandler(void)
{
   rt_interrupt_enter();
   HAL_TIM_IRQHandler(&htim3);
   rt_interrupt_leave(); 
} 


enum
{
    ST_NONE = 0,
    ST_START = 1,
    ST_LOGIC_0,
    ST_LOGIC_1,
    ST_ERROR,
};


typedef struct 
{
    uint8_t type:3;//0-2
    uint8_t rising_capture_ok:1;//3
    uint8_t start_capture_ok:1;//4-7
    uint8_t reserve:3;//4-7
}ir_signal_t;


typedef struct 
{
    union
    {
        uint8_t byte;
        ir_signal_t ir_signal;
    }val;
}status_val_t;


volatile status_val_t ir_check = {0};


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM3)
    {   
        static uint16_t count = 0;

        if (1 == ir_check.val.ir_signal.start_capture_ok)
        {
            ir_check.val.ir_signal.rising_capture_ok = 0;

            if (count>=30)
            {
                count = 0;
                ir_check.val.ir_signal.start_capture_ok = 0;
            }
            else
            {
                count++;
            }
        }
    }  
}


volatile uint8_t temp_byte = 0;
volatile uint8_t byte_length = 0;
volatile uint8_t bit_cnt = 0;
volatile uint8_t ir_data_buf[3] = {0};


void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) 
{
    if (htim->Instance==TIM3)
    {
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6))
        {
            TIM_RESET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1);  
            TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); 
            __HAL_TIM_SET_COUNTER(&htim3,0);  
          ir_check.val.ir_signal.rising_capture_ok = 1;
        }
        else // 
        {
            uint32_t rising_time = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);       
            TIM_RESET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1);
            TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); 

            if (1 == ir_check.val.ir_signal.rising_capture_ok)  
            {
                if (1 == ir_check.val.ir_signal.start_capture_ok) 
                {
                    if ((rising_time>=CONFIG_IR_LOGIC_0_HIGH_US_MIN) && (rising_time<=CONFIG_IR_LOGIC_0_HIGH_US_MAX))
                    {
                        temp_byte <<= 1;
                        bit_cnt++;
                    }
                    else if ((rising_time>=CONFIG_IR_LOGIC_1_HIGH_US_MIN) && (rising_time<=CONFIG_IR_LOGIC_1_HIGH_US_MAX))
                    {
                        temp_byte <<= 1;
                        temp_byte += 1;
                        bit_cnt++;
                    }
                }
                else if ((rising_time>=CONFIG_IR_START_HIGH_US_MIN) && (rising_time<=CONFIG_IR_START_HIGH_US_MAX))
                {
                    ir_check.val.ir_signal.start_capture_ok = 1;
                    temp_byte = 0;
                    byte_length = 0;
                    bit_cnt = 0;
                }
            }

            if (8 == bit_cnt)
            {
                ir_data_buf[byte_length++] = temp_byte;
                temp_byte = 0;
                bit_cnt = 0;
            }

            ir_check.val.ir_signal.rising_capture_ok = 0;
        }

    }
}


int main(void)
{
    while(1)
    {
        if  (3 == byte_length)
        {
            uint8_t idx = 0;
            uint8_t check_sum  = 0;

            for (idx = 0; idx < (LENGTH_OF_ARRAY(ir_data_buf) - 1); idx++)
            {
                check_sum  += ir_data_buf[idx]; 
            }

            APP_MAIN_PRINTF("\\t\\r\\n");

            if (check_sum  == ir_data_buf[byte_length - 1])
            {
                for(idx = 0; idx < LENGTH_OF_ARRAY(ir_data_buf); idx++)
                {
                    APP_MAIN_PRINTF("{%02x} ",ir_data_buf[idx]);
                }

                APP_MAIN_PRINTF("\\r\\n"); 
            }

            byte_length = 0;
            temp_byte = 0;
            bit_cnt = 0;
        }
    }
    return 0;
}

四 測試

將發(fā)射頭的信號腳接到PE0,再將接收頭的信號腳接到PA6進(jìn)行測試,

將發(fā)射頭對準(zhǔn)接收頭發(fā)送指令,可以看到發(fā)送與接收的數(shù)據(jù)完全一致。

msh >ir aa 01
TX:
[aa] [01] [ab] 
msh >
RX:
{aa} {01} {ab}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 二極管
    +關(guān)注

    關(guān)注

    147

    文章

    9410

    瀏覽量

    164420
  • 通信協(xié)議
    +關(guān)注

    關(guān)注

    28

    文章

    810

    瀏覽量

    40121
  • 發(fā)射
    +關(guān)注

    關(guān)注

    1

    文章

    92

    瀏覽量

    20820
  • 紅外遙控器
    +關(guān)注

    關(guān)注

    3

    文章

    133

    瀏覽量

    21579
  • 紅外通信
    +關(guān)注

    關(guān)注

    1

    文章

    51

    瀏覽量

    9797
收藏 人收藏

    評論

    相關(guān)推薦

    利用紅外通信原理的設(shè)計(jì)與實(shí)現(xiàn) 紅外通信協(xié)議 含電路圖

    電路,經(jīng)該電路的調(diào)制轉(zhuǎn)變成紅外光信號在空中傳輸,然后紅外接收電路收到該紅外光信號,經(jīng)過該電路的解調(diào),將此紅外光信號還原成可被單片機(jī)處理的信號
    發(fā)表于 10-23 10:10

    關(guān)于單片機(jī)通信協(xié)議的小討論

    兩個(gè)基本的操作函數(shù):發(fā)送一個(gè)字節(jié)數(shù)據(jù)、接收一個(gè)字節(jié)數(shù)據(jù)。所有的數(shù)據(jù)協(xié)議全部建立在這兩個(gè)操作方法之上。通信中的數(shù)據(jù)往往以數(shù)據(jù)包的形式進(jìn)行傳送的
    發(fā)表于 11-04 22:58

    關(guān)于ARP協(xié)議發(fā)送與接收, FPGA板子上面與PC端主機(jī)通信,出現(xiàn)以下情況怎么辦?

    關(guān)于ARP協(xié)議發(fā)送與接收:FPGA板子上面與PC端主機(jī)通信,出現(xiàn)以下情況:1:當(dāng)FPGA板子發(fā)送ARP請求時(shí)會與PC主機(jī)
    發(fā)表于 03-26 15:02

    單片機(jī)通信協(xié)議處理方式介紹

    發(fā)送一個(gè)字節(jié)數(shù)據(jù)、接收一個(gè)字節(jié)數(shù)據(jù)。所有的數(shù)據(jù)協(xié)議全部建立在這兩個(gè)操作方法之上。通信中的數(shù)據(jù)往往以數(shù)據(jù)包的形式進(jìn)行傳送的,我們把這樣的一個(gè)
    發(fā)表于 07-13 09:12

    紅外通信協(xié)議IrDA

    紅外通信協(xié)議IrDA
    發(fā)表于 05-18 08:47

    Modbus通信協(xié)議的相關(guān)資料下載

    步驟:1.實(shí)現(xiàn)1ms中斷計(jì)時(shí)的定時(shí)器;2.實(shí)現(xiàn)發(fā)送接收數(shù)據(jù)的串口;3.Modbus程序編寫。本節(jié)將本著從理論落實(shí)到實(shí)踐的角度對Modbus通信協(xié)議進(jìn)行代碼實(shí)現(xiàn)。
    發(fā)表于 02-09 07:47

    使用通信協(xié)議宏實(shí)現(xiàn)PLC對變頻器的監(jiān)控

    簡要介紹歐姆龍3G3MV變頻器Modbus通信協(xié)議中數(shù)據(jù)幀的格式。給出了使用支持軟件CX-Protocol生成與變頻器通信協(xié)議宏序列的方法,如通信
    發(fā)表于 03-17 11:10 ?20次下載

    STM32單片機(jī)通過SPI發(fā)送與接收FLSAH應(yīng)用案例

    使用STM32單片機(jī)通過SPI發(fā)送與接收FLSAH應(yīng)用案例,部分程序可以轉(zhuǎn)移到其他單片機(jī)上。
    發(fā)表于 10-28 15:25 ?14次下載

    Modbus通信協(xié)議教程

    Modbus通信協(xié)議教程Modbus通信協(xié)議教程Modbus通信協(xié)議教程
    發(fā)表于 12-08 14:14 ?74次下載

    CAN總線通信協(xié)議的分析和實(shí)現(xiàn) CAN總線通信協(xié)議以及其實(shí)現(xiàn)方法

    CAN總線通信協(xié)議的分析和實(shí)現(xiàn) CAN總線通信協(xié)議以及其實(shí)現(xiàn)方法
    發(fā)表于 09-04 08:45 ?40次下載
    CAN總線<b class='flag-5'>通信協(xié)議</b>的分析和實(shí)現(xiàn) CAN總線<b class='flag-5'>通信協(xié)議</b>以及其實(shí)現(xiàn)<b class='flag-5'>方法</b>

    使用串行接口IICA實(shí)現(xiàn)主發(fā)送接收

    本篇應(yīng)用說明中,主要描述通過使用串行通信接口IICA,實(shí)現(xiàn)單主系統(tǒng)中主發(fā)送/接收通信(地址發(fā)送、數(shù)據(jù)發(fā)送
    發(fā)表于 09-13 10:24 ?3次下載
    使用串行接口IICA實(shí)現(xiàn)主<b class='flag-5'>發(fā)送</b>和<b class='flag-5'>接收</b>

    使用51單片機(jī)進(jìn)行串口通信發(fā)送與接收的資料和程序免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用51單片機(jī)進(jìn)行串口通信發(fā)送與接收的資料和程序免費(fèi)下載。
    發(fā)表于 08-28 17:29 ?6次下載
    使用51單片機(jī)進(jìn)行串口<b class='flag-5'>通信</b>的<b class='flag-5'>發(fā)送與</b><b class='flag-5'>接收</b>的資料和程序免費(fèi)下載

    討論使用UART通信協(xié)議的基本原則

    UART,即通用異步接收器/發(fā)送器,是最常用的設(shè)備間通信協(xié)議之一,正確配置后,UART可以配合許多不同類型的涉及發(fā)送接收串行數(shù)據(jù)的串行
    的頭像 發(fā)表于 02-01 17:54 ?904次閱讀

    常用的通信協(xié)議有哪些

    通信協(xié)議(communications protocol)官方給出的定義是指雙方實(shí)體完成通信或服務(wù)所必須遵循的規(guī)則和約定。協(xié)議定義了數(shù)據(jù)單元使用的格式,信息單元應(yīng)該包含的信息與含義,連接方式,信息
    發(fā)表于 05-06 14:36 ?2.2w次閱讀

    UART串口通信協(xié)議是什么?

    ,廣泛應(yīng)用于嵌入式領(lǐng)域。 在UART串口通信協(xié)議中,數(shù)據(jù)以字節(jié)的形式進(jìn)行傳輸。發(fā)送接收端的通信流程如下: 1、通信波特率設(shè)置:
    的頭像 發(fā)表于 03-19 17:26 ?960次閱讀