OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 8425|回复: 7

小米遥控器红外接收解码

[复制链接]

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2015-11-2
在线时间
12 小时
发表于 2017-10-25 16:58:28 | 显示全部楼层 |阅读模式
忙了一天终于用STM32F207完成小米遥控器的红外接收,块下班了先贴个源码占个坑,有空再续写。楼主脑残,画板子时候红外接收引脚没有连接到定时器上。只能开一个电平中断,在开个定时器中断在电平中断 控制定时器。
[mw_shl_code=c,true]
#ifndef _IR_MI_H
#define _IR_MI_H

/*Includes -------------------------------------------------------------------------------*/
#include "stm32f2xx.h"
#include "FreeRTOS.h"
#include "queue.h"
/* marco ---------------------------------------------------------------------------------*/
/*数据帧高电平长度等效数据 每个数据帧以2bit表示*/
#define IR_FOURTEEN_VALUE    0x03
#define IR_ELEVEN_VALUE      0x02
#define IR_EIGHT_VALUE       0x01
#define IR_FIVE_VALUE        0x00

/*红外脉冲长度单位us*/
#define IR_LEAD_L            1050
#define IR_LEAD_H            550
#define IR_DATA_IDLE_L       650
#define IR_DATA_FOURTEEN_H   1450
#define IR_DATA_ELEVEN_H     1150
#define IR_DATA_EIGHT_H      850
#define IR_DATA_FIVE_H       585
/*红外脉冲测量精度*/
#define IR_MEAS_ACCURACY     100

/*红外接收状态*/
#define IR_STATE_IDLE        0x00
#define IR_STATE_LEAD_ON     0x01
#define IR_STATE_LEAD_OFF    0x02
#define IR_STATE_DATA_IDLE   0x03
#define IR_STATE_DATA        0x04
#define IR_STATE_END                 0x05

/*单次的数据长度*/
#define IR_DATA_LENGTH       10
/*按键用户数据位(前六个数据脉冲)等效值*/
#define IR_CUSTOM_DATA       0x0860
/*OFF前六个数据脉冲等效值*/
#define IR_CUSTOM_OFF        0x03CC
/*按键的等效值*/
#define IR_OFF               0xCF
#define IR_UP                0x5B
#define IR_DOWN              0x68
#define IR_LEFT              0xB5
#define IR_RIGHT             0xC2
#define IR_ENTER             0xD3
#define IR_HOME              0x86
#define IR_BACK              0x79
#define IR_MANU              0x4A
#define IR_PLUS              0xE0
#define IR_REDUCE            0xF1
/* Global Variable ------------------------------------------------------------------------*/
extern QueueHandle_t IRRxHandle;
/* Global Fuction ------------------------------------------------------------------------*/
void IR_Init(void);
#endif   //_IR_MI_H


/* Includes -------------------------------------------------------------------------------*/
#include "ir_mi.h"
/* Private variables ----------------------------------------------------------------------*/
static uint8_t  ir_state_flag = IR_STATE_IDLE;        //接收状态记录
static uint8_t  ir_data_count = 0;        //接收数据计数
static uint32_t ir_data = 0;                //记录接收数据值
static uint32_t tim_value = 0;                //脉冲宽度测量值记录

/*Global variable -------------------------------------------------------------------------*/
QueueHandle_t IRRxHandle;        //接收数据接收队列只传递最后四位脉冲对应值

/* Private Fuctions -----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------
@brief  复位红外接收标志位与定时器
*------------------------------------------------------------------------------------*/
static void ir_reset_flag(void)
{
        ir_state_flag   = IR_STATE_IDLE;
        ir_data_count   = 0;
        ir_data = 0;
        TIM_Cmd(TIM2, DISABLE);
        TIM_SetCounter(TIM2,0);
}


/* Global Fuctions ------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------
@brief  红外端口与计时时钟初始化
*------------------------------------------------------------------------------------*/
void IR_Init(void)                              
{
        EXTI_InitTypeDef   EXTI_InitStructure;
        GPIO_InitTypeDef   GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
        /*创建队列存储红外信息*/
        IRRxHandle = xQueueCreate( 32, ( unsigned portBASE_TYPE ) sizeof( signed char ) );
       
        /* Enable GPIOD clock */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
        /* Enable SYSCFG clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
        /* Configure PD3 pin as input floating */
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
        GPIO_Init(GPIOD, &GPIO_InitStructure);
       
        /* Connect EXTI Line3 to PD3 pin */
        SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource3);
        /* Configure EXTI Line0 */
        EXTI_InitStructure.EXTI_Line = EXTI_Line3;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;  
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure);

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);                                       
        TIM_TimeBaseStructure.TIM_Period=5000;                                                 //ARR的值
        TIM_TimeBaseStructure.TIM_Prescaler=60-1;                                        //采样分频
        TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;        //向上计数模式
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
        TIM_ARRPreloadConfig(TIM2, DISABLE);                                                    //禁止ARR装载
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                                                 
}

/*-----------------------------------------------------------------------------------
@brief  红外接收引脚电平中断
*------------------------------------------------------------------------------------*/
void EXTI3_IRQHandler(void)
{
        if(EXTI_GetITStatus(EXTI_Line3) != RESET)
        {
                tim_value = TIM_GetCounter(TIM2);
                TIM_SetCounter(TIM2,0);
               
                if(!GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_3))            
                {//下降沿触发状态处理                       
                        if(ir_state_flag == IR_STATE_IDLE)
                        {//空闲状态 - 开始接受起始帧
                                TIM_Cmd(TIM2, ENABLE);                //使能定时器
                                ir_state_flag = IR_STATE_LEAD_ON;
                        }
                        else if(ir_state_flag == IR_STATE_LEAD_OFF)
                        {//起始帧高电平结束 - 判断高电平时间进入数据接收
                                if((tim_value>= (IR_LEAD_H - IR_MEAS_ACCURACY))&&(tim_value<= (IR_LEAD_H + IR_MEAS_ACCURACY)))
                                {
                                        ir_state_flag = IR_STATE_DATA_IDLE;
                                }
                                else
                                {
                                        ir_reset_flag();
                                }
                        }
                        else if(ir_state_flag == IR_STATE_DATA)
                        {//数据帧高电平结束-判断高电平时间区分并记录数据
                                ir_state_flag = IR_STATE_DATA_IDLE;
                                if((tim_value>= (IR_DATA_FOURTEEN_H - IR_MEAS_ACCURACY))&&(tim_value<=(IR_DATA_FOURTEEN_H + IR_MEAS_ACCURACY)))
                                {
                                        ir_data <<= 2;
                                        ir_data += IR_FOURTEEN_VALUE;
                                        ir_data_count++;
                                }
                                else if((tim_value>= (IR_DATA_ELEVEN_H - IR_MEAS_ACCURACY))&&(tim_value<=(IR_DATA_ELEVEN_H + IR_MEAS_ACCURACY)))
                                {
                                        ir_data <<= 2;
                                        ir_data += IR_ELEVEN_VALUE;
                                        ir_data_count++;
                                }
                                else if((tim_value>= (IR_DATA_EIGHT_H - IR_MEAS_ACCURACY))&&(tim_value<=(IR_DATA_EIGHT_H + IR_MEAS_ACCURACY)))
                                {
                                        ir_data <<= 2;
                                        ir_data += IR_EIGHT_VALUE;
                                        ir_data_count++;
                                }
                                else if((tim_value>= (IR_DATA_FIVE_H - IR_MEAS_ACCURACY))&&(tim_value<=(IR_DATA_FIVE_H + IR_MEAS_ACCURACY)))
                                {
                                        ir_data <<= 2;
                                        ir_data += IR_FIVE_VALUE;
                                        ir_data_count++;
                                }
                                else
                                {
                                        ir_reset_flag();
                                }
                        }
                        else
                        {//其他错误状态复位标志位
                                ir_reset_flag();
                        }                                       
                }
                else
                {//上升沿状态触发
                        if(ir_state_flag == IR_STATE_LEAD_ON)
                        {//起始帧低电平结束 - 判断电平长度进入起始帧高电平测量
                                if((tim_value>= (IR_LEAD_L - IR_MEAS_ACCURACY))&&(tim_value<= (IR_LEAD_L + IR_MEAS_ACCURACY)))
                                {
                                        ir_state_flag = IR_STATE_LEAD_OFF;
                                }
                                else
                                {
                                        ir_reset_flag();
                                }
                        }
                        else if(ir_state_flag == IR_STATE_DATA_IDLE)
                        {//数据帧低电平结束 - 判断电平长度进入数据帧高电平测量
                         //或结束帧低电平结束 - 判断电平长度等待定时器超时完成接收
                                if((tim_value>= (IR_DATA_IDLE_L - IR_MEAS_ACCURACY))&&(tim_value<= (IR_DATA_IDLE_L + IR_MEAS_ACCURACY)))
                                {
                                        if(ir_data_count < IR_DATA_LENGTH)
                                        {//数据接收未完成继续接受数据
                                                ir_state_flag = IR_STATE_DATA;
                                        }
                                        else
                                        {//数据接收完成等待定时器超时
                                                ir_state_flag = IR_STATE_END;
                                        }
                                }
                                else
                                {
                                        ir_reset_flag();
                                }
                        }
                        else
                        {//其他错误状态复位标志位
                                ir_reset_flag();
                        }
                }       
        }

        EXTI_ClearITPendingBit(EXTI_Line3);
}

/*-----------------------------------------------------------------------------------
@brief  红外接收10ms定时器溢出中断
*------------------------------------------------------------------------------------*/
void TIM2_IRQHandler(void)//计时使用每10MS中断
{
        uint8_t tmp = 0;
        portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
        {
                TIM_Cmd(TIM2, DISABLE);
                if(ir_state_flag == IR_STATE_END)
                {//结束接收状态判断并发送数据
                        /*前六个数据脉冲数据帧的符合用户数据位或者OFF前六帧则为有效数据否则抛弃*/
                        if(((ir_data>>8) == IR_CUSTOM_DATA) ||((ir_data>>8) == IR_CUSTOM_OFF))
                        {
                                tmp = (uint8_t)ir_data;
                                xQueueSendFromISR( IRRxHandle, &tmp, &xHigherPriorityTaskWoken );
                        }
                }
                else
                {
                        ir_reset_flag();
                }
                TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        }
        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

}

/* -------------------------------------------END OF FILE-----------------------------------------------*/
[/mw_shl_code]


小米遥控器

小米遥控器
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

50

主题

1805

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6662
金钱
6662
注册时间
2016-5-29
在线时间
910 小时
发表于 2017-12-16 23:08:49 | 显示全部楼层
开个电平中断来接收挺好的.比定时引脚来说IO随便选呀.
多个中断运行,单片机也不觉得累..没毛病.
回复 支持 1 反对 0

使用道具 举报

39

主题

127

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2290
金钱
2290
注册时间
2015-5-6
在线时间
248 小时
发表于 2017-10-25 21:32:14 | 显示全部楼层
不错,我也有一个这样的遥控器
回复 支持 反对

使用道具 举报

3

主题

18

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
336
金钱
336
注册时间
2016-4-22
在线时间
163 小时
发表于 2018-12-12 08:07:39 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2018-6-4
在线时间
5 小时
发表于 2018-12-12 09:56:55 | 显示全部楼层
11111111111111111111
回复 支持 反对

使用道具 举报

0

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2014-10-24
在线时间
24 小时
发表于 2019-8-29 19:54:02 | 显示全部楼层
楼主 这红外发射接收用的啥协议? 解码接收移动2bit?
回复 支持 反对

使用道具 举报

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
83
金钱
83
注册时间
2015-11-2
在线时间
12 小时
 楼主| 发表于 2019-11-21 17:42:22 | 显示全部楼层
Cainiao2014 发表于 2019-8-29 19:54
楼主 这红外发射接收用的啥协议? 解码接收移动2bit?

我也不知道它用的啥协议,领导只给了我一个遥控器。
我先用示波器抓取波形,然后根据波形写的解码程序。波形根据脉宽可以分为起始帧,数据帧,结束帧,因为数据帧包含了四种不同脉宽的波形,所以我用2bit表示四种波形(2^2=4),不断移位因为一个数据帧包由几个脉冲组成并不是一个。
过程就是:接收一个脉冲判断为起始帧,进入数据帧接收,来一个脉冲就是2bit记录,再来一个脉冲还是数据帧将之前的2bit位移,并记录。直到接收到结束帧。然后数据帧不同脉宽与数量组合就以一个数据的形式呈现了。然后再查表(我用的#define )就知道是哪个按键了。(如果你一直按住一个按键不放,它会连续发送四五次然后就静默了需要特别处理)
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
2
金钱
2
注册时间
2020-7-26
在线时间
0 小时
发表于 2020-7-26 16:36:45 | 显示全部楼层
微信截图_20200726163034.png 搞了个小米红外协议,这个数据结构怎么解读?

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 17:55

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表