准备工作:
(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;
}