• 沒有找到結果。

C51 输入/输出接口与红外线导航

现在许多遥控装置和PDA都使用频率低于可见光的红外线进行通信,而机器人则可以使 用红外线进行导航。本章使用一些价格非常便宜且应用广泛的部件,让机器人的C51微控制 器可以收发红外光信号,从而实现机器人的红外线导航。

使用红外线发射和接收器件探测道路

如果你已经学习和实践过《基础机器人制作与编程》课程,可以忽略此小节,直接进入 后面的实践任务。

前一章的触须接触导航是依靠接触变形来探测物体,而在许多情况下,你希望不必接触 物体就能探测到物体。许多机器人使用雷达(RADAR)或者声纳(SONAR)来探测物体而不需 同物体接触。本章的方法是使用红外光来照射机器人前进的路线,然后确定何时有光线从被 探测目标反射回来,通过检测反射回来的红外光就可以确定前方是否有物体。由于红外遥控 技术的发展,现在红外线发射器和接收器已经很普及并且价格很便宜。这对于机器人爱好者 而言是一个好消息。不过如何使用,可还需要你花一些功夫来学习。

红外前灯

你将要在机器人上建立的红外光探测物体系统在许多方面就象汽车的前灯系统。当汽车 前灯射出的光从障碍物体反射回来时,人的眼睛就发现了障碍物体,然后大脑处理这些信息,

并据此控制身体动作驾驶汽车。机器人使用红外线二极管LED作为前灯,如图5-1所示。

图5-1 用红外光探测障碍物 图5-2 本章需要用到的新部件

红外线二极管发射红外光,如果机器人前面有障碍物,红外线从物体反射回来,相当于 机器人眼睛的红外检测(接收)器,检测到反射回的红外光线,并发出信号来表明检测到从 物体反射回红外线。机器人的大脑——单片机AT89S52基于这个传感器的输入控制伺服电机。

红外线(IR)接收/检测器有内置的光滤波器,除了需要检测的980 nm波长的红外线外,

它几乎不允许其它光通过。红外检测器还有一个电子滤波器,它只允许大约38.5 kHz 的电 信号通过。换句话说,检测器只寻找每秒闪烁38,500次的红外光。这就防止了普通光源象太

阳光和室内光对IR的干涉。太阳光是直流干涉(0Hz)源,而室内光依赖于所在区域的主电 源,闪烁频率接近100或120 Hz。由于120 Hz在电子滤波器的38.5 kHz通带频率之外,它完 全被IR探测器忽略。

任务一 搭建并测试IR发射和探测器对

本任务中,你将搭建并测试红外线发射和检测器对。

元件清单:

(1) 两个红外检测器 (2) 两个IR LED (3) 四个470Ω电阻 (4) 两个9013三极管 搭建红外线前灯

电路板的每个角安装一个IR组(IR LED和检测器)。

z 断开主板和伺服系统的电源

z 建立图5-3所示的电路,可参考实物图5-4

图 5-3 左侧和右侧IR组原理图

图5-4 左右IR组实物参考图 这里为何要使用三极管9013?

因为C51的IO驱动能力较弱,这里我们加入三极管使其工作在开关状态。

三极管是一种控制元件,主要用来控制电流大小,简单地说,是用小电流去控制大电流。

通过工艺的方法,把两个二极管背靠背地连接起来就组成了三极管。按PN 结的组合方 式不同分为PNP 型和 NPN 型。本任务中用到的是 NPN 型三极管 9013,结构示意图及符号 图如5-5,管脚图如 5-6。

5-5 结构图及符号图 5-6 9013 管脚图

现在简单地说下9013 的工作原理。它的基区做得很薄,当按图 5-3 连接时,发射结正 偏,集电结反偏,发射区向基区注入电子,这时由于集电结反偏,对基区的电子有很强的吸 引力,所以由发射区注入基区的电子大部分进入集电区,于是集电极的电流得到了增大。

在这个任务中,三极管相当于一个开关:当 P1_3(P3_6)置高时,从集电区经基区到 发射区电路导通,加载在IR LED 上的电压为 VCC(5V),IR LED 向外发射红外线;当 P1_3

(P3_6)置低时,电路又断开,IR LED 停止发射。

测试红外发射探测器

下面你要用P1_3发送持续1毫秒的38.5kHz的红外光,如果红外光被小车路径上的物体反 射回来,红外检测器将给微控制器发送一个信号,让它知道已经检测到反射回的红外光。

让每个IR LED 探测器组工作的关键是发送1毫秒频率为38.5 kHz的红外信号,然后立刻 将IR探测器的输出存储到一个变量中。下面是一个例子,它发送38.5 kHz信号给连接到P1_3

z 输入、保存并运行程序TestLeftIrPair.c

#include<BoeBot.h>

#include<uart.h>

int P1_2state(void) {

return (P1&0x04)?1:0;

}

int main(void) {

int counter;

int irDetectLeft;

uart_Init();

printf("Program Running!\n");

while(1)

irDetectLeft=P1_2state();

printf("irDetectLeft=%d\n",irDetectLeft);

delay_nms(100);

} }

z 保持机器人与串口电缆的连接,因为你需用调试终端来测试你的IR组 z 放一个物体,比如手或一张纸,距离左侧IR组大约2到3厘米,参考图5-1

z 验证当你放一个物体在IR组前时,调试终端是否会显示“irDetecfLeft=0”;当你将 物体移开时,它是否显示“irDetectLeft=1”,如图5-7:

图5-7 测试左IR组

z 如果调试终端显示的是预料的值,没发现物体显示1,发现物体显示0,转到例程后的 该你了部分

z 如果调试终端显示的不是预料的值,试试排错部分里的步骤进行排错 排错

z 如果调试终端显示的不是预料的值,检查电路和输入的程序

z 如果你总是得到0,甚至当没有物体在机器人前面时也是0,可能是附近的物体反射了 红外线。机器人前面的桌面是常见的始作俑者。调整红外发射器的角度,使IR LED 和探测器不会受桌面等物体的影响

z 如果机器人前面没有物体时绝大多数时间读数是1,但是偶尔是0,这可能是附近的荧 光灯的干扰。关掉附近的荧光灯,重新测试

函数延时的不精确性

如果你有数字示波器,你可以测量一下P1_3产生的方波的频率并不是严格的38.5kHz,

而是比38.5kHz略低。为什么会这样呢?这是因为上面例程中除了延时函数本身严格产生 13us的延时外,延时函数的调用过程也会产生延时,因此实际产生的延时会比13微秒更长。

函数调用时,CPU会先进行一系列的操作,这些操作是需要时间的,至少几个us,而现在所 要求的延时也是微秒级,这就造成了延时的不精确性。怎么办呢,有没有更精确的方法呢?

下面介绍一种常用的延时方法,这在实际工程中用的非常广泛。

如果你把Keil uVision2 IDE安装在了C盘,那么你将在C:\Program Files\Keil\C51\INC

目录下发现头文件“INTRINS.H”,这个头文件里声明了空函数_nop_(void),它能延时1us。

这是当我们的单片机在12MHz晶振下计算的,单片机AT89S52一个时钟周期(即晶振频率的倒 数)为:

T=1/12M=(1/12)*10-6S

而单片机的操作是用机器周期来计算的,一个机器周期为十二个时钟周期。因此 t=12*T=1*10-6s=1us

由于教学板的晶振选用11.0592MHz,它能产生延时的时间是1.08us,比1us有稍许误差。

延时还有很多方法,比如使用中断。中断的应用我们会在后续章节介绍。

该你了

z 将程序TestLeftIrPair.c另存为TestRightIrPair.c z 更改名称和注释使适合于右侧IR组

z 采用刚刚讨论过的产生约12微秒延时的程序片断替代延时函数delay_nus(13) z 将变量名irDetectLeft 改为 irDetectRight

z 将函数名P1_2state改为P3_5state,并将函数体中的0x04改为0x20 z 重复本前面的测试步骤,将IR LED连接到P3_6,检测器连接到P3_5

任务二 探测和避开障碍物

int irDetectLeft int irDetectRight

调用一个函数void IRLaunch(unsigned char IR)来进行红外线发射。

void IRLaunch(unsigned char IR) {

int counter;

if(IR=='L')

for(counter=0;counter<38;counter++)//左边发射 {

LeftLaunch=1;

_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

for(counter=0;counter<38;counter++)//右边发射 {

else if(irDetectLeft==0)//只有左边接收到红外线 Right_Turn();

else if(irDetectRight==0)//只有右边接收到红外线 Left_Turn();

z 验证机器人的行为和运行程序RoamingWithWhiskers.c时除了不需接触是否非常像

#include<BoeBot.h>

#define RightLaunch P3_6 //右边红外发射连接到P3_6

void IRLaunch(unsigned char IR) {

int counter;

if(IR=='L') //左边发射

for(counter=0;counter<38;counter++) //发射时间比胡须长 {

for(counter=0;counter<38;counter++) {

RightLaunch=1;

_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

void Forward(void) //向前行走子程序 {

void Left_Turn(void) //左转子程序 {

}

void Right_Turn(void) //右转子程序 {

int main(void) {

int irDetectLeft,irDetectRight;

uart_Init();

printf("Program Running!\n");

while(1) {

IRLaunch('R'); //右边发射

irDetectRight = RightIR;//右边接收 IRLaunch('L'); //左边发射

irDetectLeft = LeftIR;//左边接收

if((irDetectLeft==0)&&(irDetectRight==0))//两边同时接收到红外线 {

Backward();

Left_Turn();

Left_Turn();

z 输入、保存并运行程序FastIrRoaming.c

#include<BoeBot.h>

void IRLaunch(unsigned char IR) {

int counter;

if(IR=='L') //左边发射

for(counter=0;counter<38;counter++)

for(counter=0;counter<38;counter++)//右边发射 {

int main(void) {

int pulseLeft,pulseRight;

int irDetectLeft,irDetectRight;

uart_Init();

printf("Program Running!\n");

do

if((irDetectLeft==0)&&(irDetectRight==0))//向后退 {

pulseLeft=1300;

pulseRight=1700;

}

else if((irDetectLeft==0)&&(irDetectRight==1))//右转 {

pulseLeft=1700;

pulseRight=1700;

}

else if((irDetectLeft==1)&&(irDetectRight==0))//左转 {

pulseLeft=1300;

int pulseLeft,pulseRight;

int irDetectLeft,irDetectRight;

前面,你学习了当型循环控制语句while,它的一般表达式为:while(表达式) 语句;

在do循环体中,发送38.5 kHz的IR信号给每个IR LED。当脉冲发送完后,变量立即存储 IR检测器的输出状态。这是很有必要的,因为如果你等待的时间太长,无论是否发现物体,

将返回没有探测到物体的状态1。

IRLaunch('R'); //右边发射

irDetectRight = RightIR; //右边接收 IRLaunch('L'); //左边发射

irDetectLeft = LeftIR; //左边接收

在if…else语句中,程序不是发送脉冲或调用导航程序而是设置发送的脉冲持续时间。

if((irDetectLeft==0)&&(irDetectRight==0)) {

pulseLeft=1300;

pulseRight=1700;

}

else if(irDetectLeft==0) {

pulseLeft=1700;

pulseRight=1700;

}

else if(irDetectRight==0) {

pulseLeft=1300;

pulseRight=1300;

} else {

pulseLeft=1700;

pulseRight=1300;

}

在重复循环体之前,要做的最后一件事是发送脉冲给伺服电机。

P1_1=1;

delay_nus(pulseLeft);

P1_1=0;

P1_0=1;

delay_nus(pulseRight);

P1_0=0;

delay_nms(20);

该你了

z 将程序FastIrRoaming.c另存为FastIrRoamingYourTurn.c z 用LED来指示机器人探测到物体

z 试着更改pulseLeft和pulseRight的值,使机器人以一半的速度行走

z 例程中while语句是否可以替换do…while语句呢?以前使用while语句的地方是否能 替换成do...while语句呢?尝试一下!

任务四 俯视的探测器

到目前为止,当机器人探测到前面有障碍物时,主要使机器人做避让动作。也有一些场 合,当没有检测到障碍物时,机器人也必需采取避让动作。例如,如果机器人在桌子上行走,

IR检测器向下监测桌子表面。只要IR探测器都能够“看”到桌子表面,程序会使机器人继续 向前走。换句话说,只要行走的桌子表面能够被检测到,机器人就会继续向前走。

z 断开主板和伺服系统的电源 z 使IR组向外向下,如图5-8所示

图5-8 俯视的探测器 推荐材料:

(1)卷装黑色聚氯乙烯绝缘带——¾″ (19 mm) 宽 (2)一张白色招贴板——22 x 125 in (56 x 71 cm) 用绝缘带模拟桌子的边沿

由绝缘带制作边框的白色招贴板能够很容易地模拟桌子的边沿,这对机器人没有什么危 险。

z 如图5−9所示,建立一块有绝缘带边界的场地。使用至少3条绝缘带,绝缘带边之间连 接紧密,没有白色漏出来

z 如图5−9所示,建立一块有绝缘带边界的场地。使用至少3条绝缘带,绝缘带边之间连 接紧密,没有白色漏出来