TCRT5000
TCRT5000传感器的红外发射二级管可以不断发射红外线
当发射出的红外线 没有 被反射回来或被反射回来但强度不够大时, 红外接收管一直处于关断状态,此时 模块的输出端为高电平 ,指示二极管一直处于 熄灭状态被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和,此时 模块的输出端为低电平 ,指示 二极管被点亮总结就是: 反射的强度不够时,DO为高,开关指示灯不亮;反之DO为低,开关指示灯亮
接线方式:
VCC -> 电源正
GND -> 电源负
DO -> TTL开关信号输出0或1
AO -> 模拟信号输出(不同距离输出不同的电压,此脚可以不接)
循迹小车原理
根据上述模块了解可知,TCRT5000的DO和灯会根据红外线的反射强度而变化,而查阅资料可知:
由于黑色具有较强的吸收能力,当循迹模块发射的红外线照射到
黑线
时,红外线将会被黑线吸收,导致循迹模块上光敏三极管处于关闭状态,
DO输出高电平且
模块上一个LED熄灭。在没有检测到黑线时,模块上两个LED常亮。
总结就是一句话,有感应到黑线,D0输出高电平 ,灭灯。
将传感器固定在小车上后编写代码:
循迹小车的编程实现
main.c
#include "reg52.h"
#include <intrins.h>
#include <delay.h>
#include <motor.h>
sbit Left_Sensor = P2^4;
sbit Right_Sensor = P2^5;
sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
void main()
{
while(1)
{
//
// 下方小车两个模块都能反射回来红外,输出低电平,灯亮,直走
// 上方小车左模块遇到黑线,红外被吸收,左模块输出高电平,右模块输出低电平,左转,反之右转
if(Left_Sensor == 0 && Right_Sensor == 0)
{
Motor_front();//前
}
Delay1000ms();
if(Left_Sensor == 1 && Right_Sensor == 0)
{
Motor_Left();//左转
}
Delay1000ms();
if(Left_Sensor == 0 && Right_Sensor == 1)
{
Motor_Right();//右转
}
Delay1000ms();
if(Left_Sensor == 1 && Right_Sensor == 1)
{
Motor_Stop();
}
}
}
1. 由于我的桌面是黑色的,所以如果不用白纸,那么就模拟了不在轨道上,轮子不会动;
2. 当白纸遮挡了左边传感器,就相当于右侧检测到黑线,模拟了小车向左偏离了轨道,需要右转修正,因此只有左轮动;
3. 当白纸遮挡了右边传感器,就相当于左侧检测到黑线,模拟了小车向右偏离了轨道,需要左转修正,因此只有右轮动;
4. 当白纸同时遮挡了两个传感器,就相当于黑线在传感器之间,模拟了小车正常行驶,需要直行,所以左右轮一起转动;
实际循迹中的问题
这样乍一看似乎已经成功实现了,然而其实有些问题:当我在轨道上试运行的时候,小车还是会经常性的跑离轨道,这就是小车的速度和灵敏度的配合问题了:用螺丝刀调整传感器的灵敏度(顺时针变灵敏逆时针变迟钝),并使用之前两轮分别进行调速的代码对左右轮进行微调,我修改代码让两个定时器分别控制左右轮
timer.c
#include <motor.h>
#include "reg52.h"
char speedLeft;
char cntLeft = 0;
char speedRight;
char cntRight = 0;
void Time0Init()
{
//1.配置定时器0工作模式为16位计时
TMOD &= 0xF0;
TMOD |= 0x01;
//2.给初值,定一个500us=0.5ms出来
TL0 = 0x33; //设置定时初始值
TH0 = 0xFE;
//3、开始计时
TR0 = 1;
TF0 = 0;
//4.打开定时器0中断 ET0
ET0 = 1;
//5.打开总中断EA
EA = 1;
}
void Time1Init()
{
//1.配置定时器1工作模式为16位计时
TMOD &= 0x0F;
TMOD |= 0x10;
//2.给初值,定一个500us=0.5ms出来
TL1 = 0x33; //设置定时初始值
TH1 = 0xFE;
//3、开始计时
TR1 = 1;
TF1 = 0;
//4.打开定时器1中断 ET0
ET1 = 1;
//5.打开总中断EA
EA = 1;
}
void Time1_Handler() interrupt 3
{
cntRight++;//统计爆表的次数
//重新给初值
TL1 = 0x33;
TH1 = 0xFE;
//控制pwm波形
if(cntRight < speedRight)
{
//右前进
Motor_forward_right();
}
else
{
//右停止
Motor_stop_right();
}
if(cntRight == 40)//爆表40次,经过了20ms
{
cntRight = 0;//当40次表示20ms,重新让cnt从0开始,计算下一次的20ms
}
}
void Time0_Handler() interrupt 1
{
/*
// if(TF0 == 1)//当爆表的时候,硬件会修改bit5(TF0)位上面的数据,改成1(置1),向cpu请求中断
// {
// TF0 = 0;//不用中断,我们代码清零
使用了中断,直接清零了的*/
cntLeft++;//统计爆表的次数
//重新给初值
TL0 = 0x33;
TH0 = 0xFE;
//控制pwm波形
if(cntLeft < speedLeft)
{
//左前进
Motor_forward_left();
}
else
{
//左停止
Motor_stop_left();
}
if(cntLeft == 40)//爆表40次,经过了20ms
{
cntLeft = 0;//当40次表示20ms,重新让cnt从0开始,计算下一次的20ms
}
//}
}
main.c
#include "reg52.h"
#include <delay.h>
#include <motor.h>
#include <uart.h>
#include <Timer.h>
sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
sbit Left_Sensor = P2^4;
sbit Right_Sensor = P2^5;
extern char speedLeft;
extern char speedRight;
void main()
{
Time0Init();
Time1Init();
UartInit();
while(1)
{
if(Left_Sensor == 0 && Right_Sensor == 0)
{
speedLeft = 40;
speedRight = 40;
}
Delay1000ms();
if(Left_Sensor == 1 && Right_Sensor == 0)
{
speedLeft = 10;//10份单位时间全速运行,30份停止,所以慢,20ms是40份的500us
speedRight = 40;
}
Delay1000ms();
if(Left_Sensor == 0 && Right_Sensor == 1)
{
speedLeft = 40;
speedRight = 10;
}
Delay1000ms();
if(Left_Sensor == 1 && Right_Sensor == 1)
{
speedLeft = 0;
speedRight = 0;
}
}
}
PS:可以看到,经过调整过后小车行驶过程中其实还是不太平滑,那么其实细化平滑的方法也不难,方法之一就是细化PWM波,现在调整PWM波的最小单位是0.5ms,如果减小这个时间,理论上就可以更加细化的调整速度。