本文代码用于初学,更为浅显易懂,比原子的代码好理解,建议结合原子代码学习红外模块
注意!!!
1 由下图可以看出经过红外发光管发出的信号经红 外接收头已经进行了解调,并且将信号进行了反向
2 同时还可以看出’0’ 码 ’1’码只是低电平时的时 间不同,既然这样我们就可以通过时间来判断 是’0’ 码 ’1’码.
红外发送器发送出来的信号已经经过处理,在接收器中接收到的信号是相反的信号!!
比如发送器发送5ms高电平,接收器会接收到5ms低电平,其中原理见另一篇文章
红外基础
遥控器编码:
前进:46
后退:15
左转:44
右转:43
停止:40
中断函数
第一阶段
首先,发生中断函数的前提是产生一个下降沿,已知端口为上拉输入,也就是说正常情况下io口为高电平,如果引导码出现,发送器发送9ms高电平,接收器会收到9ms低电平,因此,下降沿便是函数的入口,如上图.
进入函数后,
①:15x014=2.1ms ,延时2.1ms之后进入②判断
②:判断此时是否为低电平,是的话说明是引导码9ms的低电平到来了,否则return退出函数
③:连发信号,结合主函数可知200ms内无接收到信号则保持小车停止
④:等待上升沿的到来,等待高电平,进入下一阶段,读四个字节的数据
第二阶段
开始读数据,这边0和1解码如下
(注意:
1.这边高低电平不限制,只需更改相应边沿触发即可,但是时间一定要严格限制
2.下图为发送器的时序图,接收器中高低电平相反,也就是0.56ms为低电平后面为高电平)
图1
①:等待下图中的①下降沿
②:等待②中的②上升沿
③:等待下图中的③下降沿
最终计算高电平时间
0: ------------0.56ms
1:---------------1.685ms
第三个while中一个N为0.14ms
8个N为1.12ms
if N大于8(高电平时间超过1.12ms) 则 该位为1
else 该位为0
图2
第三部分
• 引导码
IRCOM【4】=客户码1+客户码2+操作码+操作反码
客户码进行比对
如果失败则退出
成功则进入switch语句
判断是哪个按键
最后ir_rec_flag设置为1标志读到数据
/*******************************************************************************
红外io口设置了上拉输入
下降沿触发中断
中断函数
*******************************************************************************/
void IRIntIsr(void)
{
unsigned char j,k,N=0;
DelayIr(15); //2.1ms
if (IRIN==1)
{
return;
}
continue_time = 40;//连发信号,表示指令持续 40*5 = 200ms 无指令停车
//确认IR信号出现
while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。
{DelayIr(1);}
for (j=0;j<4;j++) //收集四组数据
{
for (k=0;k<8;k++) //每组数据有8位
{
while (IRIN) //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
{DelayIr(1);}
while (!IRIN) //等 IR 变为高电平
{DelayIr(1);}
while (IRIN) //计算IR高电平时长
{
DelayIr(1);
N++;
if (N>=30)
{
return;} //0.14ms计数过长自动离开。
} //高电平计数完毕
IRCOM[j]=IRCOM[j] >> 1; //数据最高位补“0”
if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;} //数据最高位补“1”
N=0;
}//end for k
}//end for j
k = ~IRCOM[3];
if (IRCOM[2] != k)
{
return; }
//指令转换
switch(IRCOM[2])
{
case 0x46: ctrl_comm = COMM_UP;break;
case 0x15: ctrl_comm = COMM_DOWN;break;
case 0x44: ctrl_comm = COMM_LEFT;break;
case 0x43: ctrl_comm = COMM_RIGHT;break;
case 0x40: ctrl_comm = COMM_STOP;break;
default : return;
}
ir_rec_flag = 1;
}
main函数
int main(void)
{
delay_init();
GPIOCLKInit();
UserLEDInit();
LCD1602Init();
IRCtrolInit();
TIM2_Init();
MotorInit();
// ServoInit();
while(1)
{
if(tick_5ms >= 5)//5ms
{
tick_5ms = 0;
tick_200ms++;
if(tick_200ms >= 40)
{
tick_200ms = 0;
LEDToggle(LED_PIN);
}
continue_time--;//200ms 无接收指令就停车 (如果接收到指令则会赋值continue_time=40)
if(continue_time == 0)
{
continue_time = 1;
CarStop();
}
//do something
if(ir_rec_flag == 1)//接收到红外信号
{
ir_rec_flag = 0;
switch(ctrl_comm)
{
case COMM_UP: CarGo();break;
case COMM_DOWN: CarBack();break;
case COMM_LEFT: CarRight();break;
case COMM_RIGHT: CarLeft();break;
case COMM_STOP: CarStop();break;
default : break;
}
LCD1602WriteCommand(ctrl_comm);
}
}
}
}
/*******************************************************************************
* 函 数 名 :DelayIr
* 函数功能 :0.14MS 延时
* 输 入 :无
* 输 出 :无
*******************************************************************************/
void DelayIr(unsigned char x)
{
while(x--)
{
DelayUs(140);
}
}