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

来源:互联网 发布:淘宝客服发票话术 编辑:程序博客网 时间:2024/04/30 11:04

准备工作:

(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;        }