STM32 录制与播放空调/TV遥控器的红外信号

准备工作:

(1)红外线接收管 IR receiver
(2)红外线发射灯 IR transmitter
(3)STM32控制板
(4)面包线 Jumper cables
(5)空调/TV遥控器

硬件

1、 模块
IR发射管VCC,GND,DATA; IR接受管VCC,GND,DATA;

软件

为验证红外录制其录制可靠,先尝试录制大信号;
录制条件:
1、 录制过程循环捕捉PIN上电平;
2、 红外脉宽计算的时基必须可靠;
3、 数据类型溢出处理;
4、 避免外部红外信号干扰;

以下代码在小米电视/美的空调上测试成功,先录制,然后播放,可以正确识别。

部分代码

uint32_t micros(void)
{
    uint16_t m,t;
    uint32_t dat;

    //disableInterrupts();
    m = T2_overflow;

    t = TIM_GetCounter(TIM2);//250us irq
    //enableInterrupts();
    dat = (uint32_t)m * 250 + t;

    return dat;
}

void custom_delay_usec(unsigned long uSecs) {
    if (uSecs > 4) {
        unsigned long start = micros();
        unsigned long endMicros = start + uSecs - 4;
//      Printf("endMicros = %d\tstart = %d\r\n",endMicros,start);
        if (endMicros < start) { // Check if overflow
            while ( micros() > start ) {} // wait until overflow
        }
        while ( micros() < endMicros ) {} // normal wait
    }
}
#ifdef IRremote_TX
    //如果处于播放状态 
        if(isPlay) {
            Printf("startPlaying\r\n");
            LED2_ON;//串口和指示灯示意播放中
            //信号长度
            u32 times = IR_loc_ON;
            u8 i = 0;
            //播放数组中的信息,由于第0位是高电平(暨没有收到信号)长度,所以舍去不播放
            for(i = 0; i < times; i++) {
                if( 0 == (i & 0x01) ) 
                {//奇数位为红外接收头低电平=红外发射头高电平
                    TIM_Cmd(TIM3, ENABLE); 
                    custom_delay_usec(IR_res_key_1[i]);
                    TIM_GenerateEvent(TIM3, TIM_EventSource_Update);
                    TIM_Cmd(TIM3, DISABLE);
                } 
                else//偶数位为不发射
                {
                    custom_delay_usec(IR_res_key_1[i]);
                }
            }
            isPlay = 0;
            //每次发射中间应该有间隔
            IWDG_Feed();
            delay(900);
            LED2_OFF;//关闭指示灯
        }
        #endif
        #ifdef IRremote_RX
        //如果处于录制状态 
        while(isRecord){
            if ( (0 == GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_4) ) ){
                SysTime_buf = micros();
                LED2_ON;
                #if 1
                while(1){
                    if ( Ir_Status != ( GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_4) ) ){//等待脉冲信号改变
                        currentTime = micros();//SysTime_us 
                        if ( currentTime > previousTime )
                            cycleTime = currentTime - previousTime;//计算时长
                        else
                            cycleTime = 0xffffffff - previousTime + currentTime ;//计算时长
                        previousTime = currentTime;//记录起点 GetSysTime(); //ms                    

                        Ir_Status = ( (!Ir_Status) & 0x01 );//状态改变,下一次检测相反状态
                        IR_res[IR_loc1++] = cycleTime;//将结果存入buffer
                    }
                    if((micros() - SysTime_buf> 200000) /*&& IR_loc1>100*/) {//如果超时没有记录到新信息,且已经收集到有效信息,则记录结束
                        for( int i = 1; i<IR_loc1; i++) {//在串口打印输出的信息,因为IO很慢很浪费时间,所以放在信息采集完之后进行,否则会很大程度影响采集到的信息的准确度
                            Printf("%d\t,",IR_res[i]);
                            DelayMs(100);
                            IWDG_Feed();
                        }
                        Printf("IR_loc1len = %d\r\n",IR_loc1);
                        IR_loc = IR_loc1;
                        IR_loc1=0;
                        isRecord = 0;

                        LED2_OFF;//关闭指示灯
                        break;
                    }
                }
                #else
                #endif
            }
            else
                LED2_OFF;
        }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
格力空调遥控信号的编码格式为自定义格式,需要先进行信号录制和解码,然后根据解码结果来编写解析程序。以下是基于 STM32 的格力空调遥控信号解析程序: ```c #include "stm32f10x.h" #define IR_PIN GPIO_Pin_0 #define IR_GPIO GPIOA #define IR_EXTI EXTI_Line0 #define IR_EXTI_PORT_SOURCE GPIO_PortSourceGPIOA #define IR_EXTI_PIN_SOURCE GPIO_PinSource0 #define IR_TIM TIM2 volatile uint32_t irData[128]; volatile uint8_t irCount = 0; volatile uint8_t irState = 0; void IR_TIM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 8999; // 90us TIM_TimeBaseStructure.TIM_Prescaler = 71; // 1MHz TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(IR_TIM, &TIM_TimeBaseStructure); TIM_Cmd(IR_TIM, ENABLE); } void IR_EXTI_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); GPIO_InitStructure.GPIO_Pin = IR_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(IR_GPIO, &GPIO_InitStructure); GPIO_EXTILineConfig(IR_EXTI_PORT_SOURCE, IR_EXTI_PIN_SOURCE); EXTI_InitStructure.EXTI_Line = IR_EXTI; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void EXTI0_IRQHandler(void) { static uint16_t lastValue = 0; uint16_t duration = (uint16_t)(IR_TIM->CNT); IR_TIM->CNT = 0; if (duration < 10000) { // ignore noise if (irState == 0 && duration > 8000 && duration < 9000) { // start bit irCount = 0; irState = 1; } else if (irState == 1 && duration > 400 && duration < 600) { // 0 bit irData[irCount++] = 0; irState = 2; } else if (irState == 1 && duration > 1200 && duration < 1400) { // 1 bit irData[irCount++] = 1; irState = 2; } else if (irState == 2) { // next bit irState = 1; } else { // invalid bit irData[irCount++] = lastValue; // use previous value } lastValue = irData[irCount-1]; } else { // stop bit irState = 0; } EXTI_ClearITPendingBit(IR_EXTI); } int main(void) { IR_TIM_Config(); IR_EXTI_Config(); while(1) { if (irState == 0 && irCount == 70) { // valid data if (irData[0] == 0 && irData[1] == 1 && irData[2] == 0 && irData[3] == 1) { // check start code uint16_t addr = 0; uint16_t cmd = 0; for (int i = 0; i < 8; i++) { addr = (addr << 1) | irData[4+i]; } for (int i = 0; i < 8; i++) { cmd = (cmd << 1) | irData[20+i]; } // do something with addr and cmd } irCount = 0; } } } ``` 此程序可以解析格力空调遥控信号,使用了 TIM2 定时器和 EXTI 外部中断来计时和捕获信号。当接收到有效的红外线信号时,会将信号值存储在 `irData` 数组中,并根据信号格式和状态机来判断是否解析完整个数据包。如果解析成功,可以获取地址码和命令码并执行相应的操作。 需要注意的是,格力空调遥控信号的编码格式可能存在差异,此程序只是一个简单的解析例程,实际使用时需要根据具体的遥控器型号和编码格式进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值