0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

红外通信协议的发送与接收处理方法

CHANBAEK 来源:小陈学不停 作者:小陈学不停 2023-01-12 17:14 次阅读

一 背景

最近在调试红外通信功能的时候遇到了很多问题,在此总结一下,希望能帮到未来对此有疑问的自己,如果有幸能帮到其他人也算是做了一件有意义的事情了。

二 红外发射头与红外接收头

2.1 发射头

发射管也属于二极管,只有两个脚,通过控制二极管的导通来发射信号

2.2 接收头

接收管一般有三个脚,一个VCC,一个GND,还有一个信号脚。

2.3 起始信号、逻辑0、逻辑1的定义

通常在控制发射端时,以38KHz的频率来发送方波,此时发送端需要以高低电平来控制,接收头收到的是一个低电平,其他情况下为高电平。

2.3.1 起始信号

参考红外遥控器中引导码

-发送端波形

9ms发送方波,4.5ms不发送方波

-接收端波形

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

2.3.2 逻辑1

2.3.3 逻辑0

三 发送与接收处理

3.1 延时API

rtthread官方提供了一个微妙延时函数rt_hw_us_delay,在延时低于1000us时会有延时不准的问题,这里稍作一些修改,如果想要更准确的延时可能要用定时器的方式了。

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 时间相关的宏定义

#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 信号发送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 高位先发

3.5 发送指令API

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)//先发送高位
        {
            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可以使用定时器输入捕获的方式来获取上升沿的时间,从而得到当前的信号类型

3.6.1基于红外遥控修改

void ir_timer_init(void)
{
    TIM_IC_InitTypeDef TIM3_Config;  
    htim3.Instance=TIM3;                          
    htim3.Init.Prescaler=(72-1);                   //预分频器,1M的计数频率,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);   //设置中断优先级,抢占优先级1,子优先级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;
}

四 测试

将发射头的信号脚接到PE0,再将接收头的信号脚接到PA6进行测试,

将发射头对准接收头发送指令,可以看到发送与接收的数据完全一致。

msh >ir aa 01
TX:
[aa] [01] [ab] 
msh >
RX:
{aa} {01} {ab}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 二极管
    +关注

    关注

    144

    文章

    9154

    浏览量

    162710
  • 通信协议
    +关注

    关注

    28

    文章

    777

    浏览量

    39975
  • 发射
    +关注

    关注

    1

    文章

    91

    浏览量

    20786
  • 红外遥控器
    +关注

    关注

    3

    文章

    133

    浏览量

    21499
  • 红外通信
    +关注

    关注

    1

    文章

    51

    浏览量

    9774
收藏 人收藏

    评论

    相关推荐

    利用红外通信原理的设计与实现 红外通信协议 含电路图

    电路,经该电路的调制转变成红外光信号在空中传输,然后红外接收电路收到该红外光信号,经过该电路的解调,将此红外光信号还原成可被单片机处理的信号
    发表于 10-23 10:10

    关于单片机通信协议的小讨论

    两个基本的操作函数:发送一个字节数据、接收一个字节数据。所有的数据协议全部建立在这两个操作方法之上。通信中的数据往往以数据包的形式进行传送的
    发表于 11-04 22:58

    关于ARP协议发送与接收, FPGA板子上面与PC端主机通信,出现以下情况怎么办?

    关于ARP协议发送与接收:FPGA板子上面与PC端主机通信,出现以下情况:1:当FPGA板子发送ARP请求时会与PC主机
    发表于 03-26 15:02

    单片机通信协议处理方式介绍

    发送一个字节数据、接收一个字节数据。所有的数据协议全部建立在这两个操作方法之上。通信中的数据往往以数据包的形式进行传送的,我们把这样的一个
    发表于 07-13 09:12

    红外线通信协议IrDA

    红外线通信协议IrDA
    发表于 05-18 08:47

    STM32中的通信协议是什么

    STM32中的通信协议通讯协议是指在嵌入式开发中,不同的硬件系统或者操作系统之间进行数据交换的方式,是一种数据通讯的规约。通讯协议有很多种,而我今天要说的是串口通讯协议,而且是基于ST
    发表于 08-18 07:21

    掌握通信协议的研究方法

    从根本出发,从简单开始,逐步加码,从而让你彻底掌握通信协议的研究方法。就是串口uart,因为uart只有物理层,尤其是TTL电平的uart,就是个很简单很直观的物理层协议。你可以通过学习uart理解
    发表于 01-13 06:09

    Modbus通信协议的相关资料下载

    步骤:1.实现1ms中断计时的定时器;2.实现发送接收数据的串口;3.Modbus程序编写。本节将本着从理论落实到实践的角度对Modbus通信协议进行代码实现。
    发表于 02-09 07:47

    使用通信协议宏实现PLC对变频器的监控

    简要介绍欧姆龙3G3MV变频器Modbus通信协议中数据帧的格式。给出了使用支持软件CX-Protocol生成与变频器通信协议宏序列的方法,如通信
    发表于 03-17 11:10 20次下载

    一种红外遥控信号的发送与接收

    介绍了一种对红外信号发射器中的,键发射芯片进行键功能扩充的实现方法,分析了红外遥控发射器集成电路BA5104的功能特点,给出了一种红外接收软件解码的实现
    发表于 04-30 15:13 79次下载

    使用串行接口IICA实现主发送接收

    本篇应用说明中,主要描述通过使用串行通信接口IICA,实现单主系统中主发送/接收通信(地址发送、数据发送
    发表于 09-13 10:24 3次下载
    使用串行接口IICA实现主<b class='flag-5'>发送</b>和<b class='flag-5'>接收</b>

    使用51单片机进行串口通信发送与接收的资料和程序免费下载

    本文档的主要内容详细介绍的是使用51单片机进行串口通信发送与接收的资料和程序免费下载。
    发表于 08-28 17:29 6次下载
    使用51单片机进行串口<b class='flag-5'>通信</b>的<b class='flag-5'>发送与</b><b class='flag-5'>接收</b>的资料和程序免费下载

    制定通信协议,实现单片机与PC机通信

    接收到的内容,并根据接收的指令执行相应的操作。实验内容1、搭建实验电路,利用proteus仿真2、实现以下效果**效果1:**利用定时器的定时功能,用6位数码管实现时、分、秒的显示及更新;**效果2:**制定通信协议,PC机
    发表于 12-17 18:30 22次下载
    制定<b class='flag-5'>通信协议</b>,实现单片机与PC机<b class='flag-5'>通信</b>

    常用的通信协议有哪些

    通信协议(communications protocol)官方给出的定义是指双方实体完成通信或服务所必须遵循的规则和约定。协议定义了数据单元使用的格式,信息单元应该包含的信息与含义,连接方式,信息
    发表于 05-06 14:36 2w次阅读

    【世说知识】一文搞懂UART通信协议

    UART,即通用异步接收器/发送器,是最常用的设备间通信协议之一,正确配置后,UART可以配合许多不同类型的涉及发送接收串行数据的串行
    的头像 发表于 02-02 10:46 1692次阅读
    【世说知识】一文搞懂UART<b class='flag-5'>通信协议</b>