你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【福利三:逢7发帖赢大礼】5、基于STM32G070板子IRDA红外遥控接收解码

[复制链接]
STMWoodData 发布时间:2026-7-15 00:08

IRDA红外通信协议是一种基于850-900nm波长红外线的短距离无线传输技术,由红外数据协会(IRDA)于1993年成立后制定标准,采用脉宽调制(PWM)和脉位调制(PPM)实现二进制信号传输。该协议通过发送端38KHz调制光脉冲、接收端解调电信号完成通信,典型传输距离为1-100厘米,具有定向角30度的直线传输特性 ,但由于红外线对非透明物体的透过性较差,实际传输距离常受环境物体阻隔影响。

本次就来研究一下IRDA红外遥控协议,板上有一个IRDA红外接收头,用于红外遥控控制输入。这里通过GPIO中断和定时器,测量脉冲的宽度和间隔,根据时序还原出二进制数据。 首先打开STM32CubeMX设置IRDA接收头GPIO边沿中断模式,以及定时器TIM6定时100us周期。 image.png image.png

接下来编写获取红外接收脉冲时间捕获。具体代码如下:

#define     IR_TICK_BUFF_LEN    256
union _IRDA_Data
{
    uint32_t    ir_code;
    struct 
    {
        uint8_t ir_data_l;
        uint8_t ir_data_h;
        uint8_t ir_addr_l;
        uint8_t ir_addr_h;
    }ir_data;
    uint8_t     ir_data_buff[8];
};

struct _IRDA
{
    volatile uint16_t   ir_tick_low     : 10;
    volatile uint16_t   ir_tick_flag    : 1;
    volatile uint16_t   ir_tick_ok      : 1;
    volatile uint16_t   ir_tick_print   : 1;
    volatile uint16_t   ir_press_print  : 1;

    volatile uint16_t   ir_tick_index;
    volatile uint16_t   ir_tick_time[IR_TICK_BUFF_LEN];

    volatile uint16_t   ir_timetick;
    volatile uint16_t   ir_timetick_old;


    volatile uint8_t    ir_step         : 3;
    volatile uint8_t    ir_status       : 1;

    volatile uint8_t    ir_press;
    volatile uint8_t    ir_data_index;
    union _IRDA_Data    ir_buff;

}g_IrDA;

//定时器回调
//100us timetick
void IRDA_Timer100us_Handler(void)
{
    g_IrDA.ir_timetick ++ ;
    if((g_IrDA.ir_timetick - g_IrDA.ir_timetick_old) > 10000)
    {
        g_IrDA.ir_timetick = 0;
        g_IrDA.ir_timetick_old = 0;
    }else if((g_IrDA.ir_timetick - g_IrDA.ir_timetick_old) > 1000)
    {
        if(g_IrDA.ir_tick_index)
        {
            if(g_IrDA.ir_tick_ok == 0)
            {
                g_IrDA.ir_tick_ok = 1;
                g_IrDA.ir_tick_print = 1;
            }
        }
        g_IrDA.ir_tick_flag = 0;

        g_IrDA.ir_step = 0;
        g_IrDA.ir_press = 0;
    }
}

//GPIO边沿中断回调
//IO外部下降沿中断调用
uint32_t IRDA_IOFallingIntReceive_Handler(void)
{
    uint32_t Interval_time;

    if(0 == g_IrDA.ir_tick_flag)
    {
        g_IrDA.ir_tick_flag = 1;
        g_IrDA.ir_tick_ok   = 0;
        g_IrDA.ir_tick_index = 0;
        g_IrDA.ir_tick_low = 0;
        //g_IrDA.ir_timetick_old = g_IrDA.ir_timetick;
    }
    Interval_time = g_IrDA.ir_timetick - g_IrDA.ir_timetick_old;
    g_IrDA.ir_timetick_old = g_IrDA.ir_timetick;
    g_IrDA.ir_tick_time[g_IrDA.ir_tick_index % IR_TICK_BUFF_LEN] = Interval_time;
    g_IrDA.ir_tick_index++;
    return Interval_time;
}

//IO外部上升沿沿中断调用
uint32_t IRDA_IORisingIntReceive_Handler(void)
{
    uint32_t Interval_time;

    Interval_time = g_IrDA.ir_timetick - g_IrDA.ir_timetick_old;
    g_IrDA.ir_tick_low = Interval_time;
    g_IrDA.ir_tick_time[g_IrDA.ir_tick_index % IR_TICK_BUFF_LEN] = Interval_time;
    g_IrDA.ir_tick_index++;
    return Interval_time;
}

//中断处理
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == IR_IN_Pin)
    {
        IRDA_IOIntReceivePraseCode_Handler(IRDA_IOFallingIntReceive_Handler());    //Falling edge
    }
}
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == IR_IN_Pin)
    {
        IRDA_IORisingIntReceive_Handler();
    }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM6)
    {
        IRDA_Timer100us_Handler();  //100us
    }
}

接下来通过shell命令测试红外接收捕获时间:

void IRDA_Init(void)
{    
    g_IrDA.ir_buff.ir_code = 0;

    g_IrDA.ir_tick_low = 0;
    g_IrDA.ir_tick_flag = 0;
    g_IrDA.ir_tick_ok = 0;
    g_IrDA.ir_tick_print = 0;
    g_IrDA.ir_press_print = 0;

    g_IrDA.ir_timetick = 0;
    g_IrDA.ir_timetick_old = 0;

    g_IrDA.ir_tick_index = 0;


    g_IrDA.ir_data_index = 0;
    g_IrDA.ir_press = 0;
    g_IrDA.ir_status = 0;
    g_IrDA.ir_step = 0;


}

//读红外按键编码
uint32_t IRDA_GetCode(uint32_t *Ir_num)
{  
    *Ir_num = 0;
    if(g_IrDA.ir_status)          //recvive ok
    {   
        g_IrDA.ir_status = 0; 
//        if(
//            (g_IrDA.ir_buff.ir_data.ir_addr_h + g_IrDA.ir_buff.ir_data.ir_addr_l) == 0xff 
//          (g_IrDA.ir_buff.ir_data.ir_data_h + g_IrDA.ir_buff.ir_data.ir_data_l) == 0xff
//        )
        {
            *Ir_num = g_IrDA.ir_buff.ir_code;
            return 1;
        }
    }

    if(g_IrDA.ir_press & g_IrDA.ir_press_print)
    {
        *Ir_num = g_IrDA.ir_press;
        g_IrDA.ir_press_print = 0;
        return 2;
    }
    return  0;
}

#if UART_SHELL == 3
#include "lsy_shell_core.h"
//LSY_SHELL
int cmd_irda_control(int argc, char **argv)
{
    uint32_t time,re;
    uint32_t key;

    printf("irda test 20s timeout.\r\n");
    IRDA_Init();
    HAL_TIM_Base_Start_IT(&htim6);
    time = HAL_GetTick();
    while(1)
    {
        if(g_IrDA.ir_tick_print)
        {
            g_IrDA.ir_tick_print = 0;
            printf("irda tick: %d\r\n",g_IrDA.ir_tick_index);
            for(int i=0;i<(g_IrDA.ir_tick_index%IR_TICK_BUFF_LEN);i++)
            {
                printf("%4d ",g_IrDA.ir_tick_time[i]);
            }
            printf("\r\n");
            time = HAL_GetTick();
        }

        re = IRDA_GetCode(&key);
        if(re)
        {
            printf("irda key = 0x%08X,re=%d\r\n",key,re);
        }


        if((HAL_GetTick() - time) > 20000)
        {
            printf("timeout.\r\n");
            break;
        }
    }
    return SHELL_OK;
}
LSY_SHELL_CMD_EXPORT(irda, cmd_irda_control, "test irda key data.");


#else

#endif

使用手头上风扇遥控器测试一下,输出接收的低电平脉冲时间和周期脉冲时间。 image.png 可以看到这个遥控器不是NEC协议,这里有6个字节。根据周期脉冲30100us和15100us左右时间区分0和1。前面有178*100us的前导标志。 通过获取时间间隔就可以解析出红外数据编码了。

//IO通过脉冲时间解析红外编码
void IRDA_IOIntReceivePraseCode_Handler(uint16_t plus_time)
{
    //解析编码数据
    switch(g_IrDA.ir_step)
    {
        case 0:
            g_IrDA.ir_step = 1;
            g_IrDA.ir_press = 0;
            break;

        case 1:
            if( (plus_time >= 100)&&(plus_time <= 200))
            {
                g_IrDA.ir_step = 2;
            }else
            {
                g_IrDA.ir_step = 0;
                g_IrDA.ir_data_index = 0;
            }
            break;

        case 2:
            if( (plus_time >= 8)&&(plus_time <= 20))//1.5ms ->0
            {
                g_IrDA.ir_buff.ir_data_buff[g_IrDA.ir_data_index>>3] = g_IrDA.ir_buff.ir_data_buff[g_IrDA.ir_data_index>>3]<<1;
                g_IrDA.ir_data_index++;                                
            }else if( (plus_time>=21)&&(plus_time<=36) )   //3.0ms ->1
            {
                g_IrDA.ir_buff.ir_data_buff[g_IrDA.ir_data_index>>3] = g_IrDA.ir_buff.ir_data_buff[g_IrDA.ir_data_index>>3] << 1;
                g_IrDA.ir_buff.ir_data_buff[g_IrDA.ir_data_index>>3] = g_IrDA.ir_buff.ir_data_buff[g_IrDA.ir_data_index>>3] | 0x01;
                g_IrDA.ir_data_index++;                                   
            }else//error recv
            {
                g_IrDA.ir_step = 0;
                g_IrDA.ir_buff.ir_code = 0;
                g_IrDA.ir_data_index   = 0;
            }

            if(g_IrDA.ir_data_index == 48)
            {         
                g_IrDA.ir_status = 1;   //recv ok
                g_IrDA.ir_press = 1;    //press key
                g_IrDA.ir_press_print = 1;
                g_IrDA.ir_step = 3;
                g_IrDA.ir_data_index = 0;
            } 
            break; 
        case 3:
            if(plus_time < 1000)    //100ms
            {
                if(g_IrDA.ir_press) g_IrDA.ir_press ++;    //press
                g_IrDA.ir_press_print = 1;
            }else
            {
                g_IrDA.ir_step = 0;
            } 
            break;
        default :
            g_IrDA.ir_step = 0;
            break;
    }
}

image.png

收藏 评论0 发布时间:2026-7-15 00:08

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版