
队员1
姓名:周葛
学院:仪器科学与电器工程学院 专业:测控技术与仪器
年级:大一
教学号:65130109
邮箱:zhouge94@live.cn
队员2
姓名:成妍
学院:药学院 专业:生物医学工程(再生医学)
年级:大一
教学号:73130430
邮箱:lianyungangcheng@sina.cn
作品类别:基本电子技术应用类
目录
一、引言 1
二、总体设计 1
三、单元电路设计 2
1)单片机最小驱动模块 2
2)红外接收模块 3
方案选择 3
方案确定 3
理论分析与方案论证 3
3)电机驱动模块 4
4)避障循迹贴墙模块 5
方案选择 5
方案确定 5
理论分析与方案论证 6
5)电源模块 7
6)人体感应模块 7
四、软件设计 8
五、整体测试 8
六、结论 9
【参考文献】 9
【附录】 10
源程序 10
一、引言
以STCC52单片机为核心,制作一款红外线遥控小车,小车具有自动驾驶、手动驾驶和循迹前进等功能。自动驾驶时,小车在前进过程中可以自动躲避障碍物。手动驾驶时,可以手动遥控小车前进、后退、左转、右转、加速等操作。寻迹时小车可以按轨迹前进。
红外遥控的特点是利用红外线进行点对点通信的技术,不影响周边环境,不干扰其他电器设备。室内近距离(小于10米),信号无干扰、传输准确度高、体积小、功率低的特点,遥控中得到了广泛的应用。
本系统采用成品红外发射遥控器,具有21个按键,采用NEC红外传输协议。接收端使用1838一体化接受头,通过单片机中断程序处理红外信号。
二、总体设计
本系统由硬件和软件两部分组成。硬件部分由红外线接受电路,控制电路,直流电机驱动,障碍物检测电路,人体感应电路五部分组成,完成红外编码信号的接受,直流电机的驱动,障碍物检测、墙体检测、地面检测,人体感应检测等功能。软件部分主要完成信号的检测和处理、直流电机的控制,障碍物的规避等功能。STCC52单片机主要完成对红外信号解码,判断是否遇到障碍物,判断小车是否离开地面,控制直流电机的正反转、启动、停止、急速减速等工作。系统结构框图如图l所示。
图一
三、单元电路设计
1)单片机最小驱动模块
单片机只有连好最小驱动电路后才会运行存储在其内部的程序。如图二。
单片机最小系统复位电路的极性电容C3的大小直接影响单片机的复位时间,一般采用10~30uF,51单片机最小系统容值越大需要的复位时间越短。
单片机最小系统晶振Y1也可以采用6MHz或者11.0592MHz,在正常工作的情况下可以采用更高频率的晶振,51单片机最小系统晶振的振荡频率直接影响单片机的处理速度,频率越大处理速度越快。
单片机最小系统起振电容C1、C2一般采用15~33pF,并且电容离晶振越近越好,晶振离单片机越近越好。
图二
2)红外接收模块
方案选择
⏹方案1:使用BL9148自制发射电路,使用BL9149接受处理信号。优点是程序简单,缺点增加了电路复杂性。
⏹方案2:使用成品遥控器,遥控器使用CD2025纽扣电池供电,方便携带。接收电路使用红外接收管,自制滤波整合电路对红外信号进行处理。使用在通过单片机中断程序处理解码信号。虽然增加了程序的复杂性,但是简化了电路。
⏹方案3:在方案二的基础上,使用1838一体化接受头代替红外接收管。
方案确定
⏹为提高电路的可靠性,遥控器的便携性,我们选择方案三。
理论分析与方案论证
红外接收电路通常被厂家集成在一个元件中,成为一体化红外接收头。如图三。
内部电路包括红外监测二极管,放大器,限副器,带通滤波器,积分电路,比较器等。红外监测二极管监测到红外信号,然后把信号送到放大器和限幅器,限幅器把脉冲幅度控制在一定的水平,而不论红外发射器和接收器的距离远近。交流信号进入带通滤波器,带通滤波器可以通过30khz到60khz的负载波,通过解调电路和积分电路进入比较器,比较器输出高低电平,还原出发射端的信号波形。注意输出的高低电平和发射端是反相的,这样的目的是为了提高接收的灵敏度。
图三
3)电机驱动模块
使用L298电机驱动模块如图。
此L298模块可以驱动两台直流电机。分别为M1和M2。引脚ENA,ENB可用于输入PWM脉宽调制信号对电机进行调速控制。(如果无须调速可将两引脚接5V,使电机工作在最高速状态,既将短接帽短接)实现电机正反转就更容易了,输入信号端IN1接高电平输入端IN2接低电平,电机M1正转。(如果信号端IN1接低电平, IN2接高电平,电机M1反转。)控制另一台电机是同样的方式,输入信号端IN3接高电平,输入端IN4接低电平,电机M2正转。(反之则反转),PWM信号端A控制M1调速,PWM信号端B控制M2调速。
图四
4)避障贴墙模块
方案选择
⏹方案1:使用超声波模块,根据超声波测出的障碍物距离,控制小车规避障碍物,优点反应距离远,抗干扰能力强。缺点体积庞大,且超声波模块只能用于避障,不能用于循迹功能。
⏹方案2:使用红外反射式光耦。前方左右各一个可检测障碍物。底部左右两个可用于循迹,中部左右各一个可用于贴墙走功能。当有障碍物时反射红外光,时红外接收管反向导通性增强,通过一定的电路形成电位变化,输入单片机。
⏹方案3:在方案二的基础上加一个LM393电压比较器,将红外接收管端连续变化的电位信号转化为清晰的高低电平信号。
方案确定
综合设计的实用性,简易性,可靠性,我选择方案三。
理论分析与方案论证
障碍物检测和轨迹检测原理是一样的,其电路如图5所示。从经济的角度考虑,该模块选用了六个反射式光耦,反射式光耦由一个红外发射管和一个光敏三极管组成。LM393P是电压比较器,当3脚的电压大于2脚电压时,输出端1脚输出高电平,反之输出低电平。高低电平的电缝值取决于2脚的电压,调整电位器R23使2脚电压为3V。避障电路安装在小车头部的左右两边,用于检测左右障碍物。工作过程是:当无障碍物时,不反射红外线,光敏i极管截止。3脚在R16的上拉作用下为高电平(5V),大于2脚电压(3V),1脚输出高电平;反之,当遇到障碍物时,l脚输出低电平。左边遇到障碍物时小车右转,右边遇到障碍物时小车左转。
底部地面电路安装在小车底部,当小车处于地面时,地面发射红外线,传感器接收到让小车工作。当小车离开地面时,传感器接收不到信号,小车不工作。
图五
5)电源模块
7805三端稳压集成电路,电子产品中,常见的三端稳压集成电路有正电压输出的78 ×× 系列和负电压输出的79××系列。顾名思义,三端IC是指这种稳压用的集成电路,只有三条引脚输出,分别是输入端、接地端和输出端。
本系统电池采用两节锂电池供电,正常供电电压为7.4v,电机驱动模块使用原始电压,单片机及其他模块采用7805芯片降压稳压至5v供电,调高了系统的稳定性。7805降压稳压模块电路图如图六
图六
6)人体感应模块
本模块采用HC-SR501 人体红外感应模。HC-SR501 是基于红外线技术的自动控制模块,采用德国原装进口LHI778 探头设计,灵敏度高,可靠性强,超低电压工作模式,广泛应用于各类自动感应电器设备。人进入其感应范围则输出高电平,人离开感应范围则自动延时关闭高电平,输出低电平。当小车工作在此模式时,小车工作一段时间自动停止检测车周围是否有人。当没有人时,小车自动进行避障行走;当有人时,自动停止,等待人通过遥控器发出下一步指令。
四、软件设计
程序流程图如图八:
图八
五、整体测试
本设计在调试过程中也遇到很多问题。在后来的调试过程中一一进行了改正与调整。本电路总共设计了14个输入按键。图七是遥控器的功能图七。
| 手动遥控 | 自动避障 | 贴墙行走 |
| 人体感应 | 前进 | |
| 右转 | 静止 | 左转 |
| 后退 | ||
| 加速 | ||
| 差速左拐 | 原速 | 差速右拐 |
| 减速 |
六、结论
经实践表明,本文所设计制作的红外线遥控小车运行稳定、遥控灵敏、占用系统硬件资源少。且在不改变硬件电路,仅通过软件编程小车就可以实现多处障碍物检测、报警等功能。
由于目前的遥控装置大多对某一设备进行单独控制,而在本设计中的红外遥控电路设计了多个控制按键,可以对不同的设备,也可以对同一设备的多个功能进行不同的控制。基本符合技术要求。
本想在底部增加循迹功能,但出于传感器数量有限,底部只剩下两个红外传感器,实现循迹困难。因此改为检查是否离地的功能模块。
但是本遥控电路也有不完善的地方,它只能单通道实现对多个设备的控制,即它不能同时控制两个或者两个以上的设备。
在设计过程中,通过大量的查阅资料,认真研究教材,对单片机有了更为深刻的理解,在设计软件时,须仔细的分析硬件电路,画出程序流程图,培养了我的耐性和刻苦钻研的精神。
【参考文献】
1、《实例解读51单片机完全学习与应用(配教学视频)》,杨欣编著,电子工业出版社。
2、《爱上单片机》,杜洋著,人民邮电出版社。
3、《全国大学生电子设计竞赛教程--基于ti器件设计方法》,黄春根等著,电子工业出版社。
【附录】
源程序
#include unsigned char IrValue[6]; unsigned char jd1,jd2,m1,m2,count,Time,i,value,flag; sbit IRIN=P3^2; sbit pwm1=P2^0; sbit pwm2=P2^1; sbit left1=P2^2; sbit left2=P2^3; sbit right1=P2^5; sbit right2=P2^4; sbit led=P2^6; sbit person=P2^7; sbit xia1=P1^2; sbit xia2=P1^0; sbit qian1=P1^1; sbit qian2=P1^3; sbit hou1=P1^4; sbit hou2=P1^5; void IrInit(); void DelayMs(unsigned int ); void Timer0_Init(); void go(); void back(); void turnleft(); void turnleft1(); void turnright(); void turnright1(); void add(); void pluse(); void yaokong(); void bizhang(); void stop(); void stop1(); void main() { pwm1=0; pwm2=0; count=0; led=1; jd1=85;//右轮速度初始化取值范围0~200 jd2=70;//左轮速度初始化取值范围0~200 IrInit(); Timer0_Init(); left1=0; left2=0; right1=0; right2=0; qian1=1; qian2=1; //xia1=0; //xia2=0; hou1=1; hou2=1; flag=0; //preson=1; while(1) { while(flag==1)//手动遥控 { if ((xia1==1)|(xia2==1)) stop(); else if((xia1==0)&(xia2==0)) yaokong(); } while (flag==2) //贴墙走 { if ((xia1==1)&(xia2==1)) stop(); else { if ((hou1==1)&(hou2==1)) stop(); else if ((hou1==0)&(hou2==1)&((qian1==1)|(qian2==1))) {go();} else if ((hou1==0)&(hou2==1)&((qian1==0)&(qian2==0))) {turnright();DelayMs(5000);} else if ((hou1==1)&(hou2==0)&((qian1==1)|(qian2==1))) {go();} else if ((hou1==1)&(hou2==0)&((qian1==0)&(qian2==0))) {turnleft();DelayMs(5000);} } } while (flag==3){ if ((xia1==1)&(xia2==1)) stop(); else bizhang();}//避障 while (flag==4) { if ((xia1==1)&(xia2==1)) stop(); else { if(person==1) bizhang(); else if(person==0) { stop(); } } } }} void Timer0_Init() //函数功能:定时器初始化,每1us执行一次 { TMOD=0x01; TH0=0xff;//65436/256 TL0=0x9c;//65436%256 TR0=1; EA =1; //打开总中断 ET0=1; //打开定时器0中断 TR0=1; //启动定时器0 } void Timer0_Int() interrupt 1//中断程序 { TH0=0xff; TL0=0x9c; m1=count; m2=count; if(m1 if(m2 count++; count%=200; //20m秒需要数200次 } void yaokong() { switch(value) { case 0x15:stop();break; //按键 case 0x40:go();break; case 0x19:back();break; case 0x07:turnleft();break; case 0x09:turnright();break; case 0x1c:stop1();break; case 0x08:turnleft1();break; case 0x5a:turnright1();break; default:break; } } void go() { led=~led; left1=0; left2=1; right1=0; right2=1; //value=0; } void stop() { led=~led; left1=0; left2=0; right1=0; right2=0; //value=0; } void back() { led=~led; left1=1; left2=0; right1=1; right2=0; //value=0; } void turnright() { led=~led; left1=1; left2=0; right1=0; right2=1; //value=0; } void turnright1() { unsigned int j,k; j=0;k=0; while (j<3) { jd1=jd1-10; j++; } DelayMs(1000); while (k<3) { jd1=jd1+10; k++; } } void turnleft() { led=~led; left1=0; left2=1; right1=1; right2=0; //value=0; } void stop1(void) { jd1=85;//右轮速度初始化取值范围0~200 jd2=70;//左轮速度初始化取值范围0~200 } void turnleft1() { unsigned int m,n; m=0;n=0; while (m<3) { jd2=jd2-10; m++; } DelayMs(1000); while (n<3) { jd2=jd2+10; n++; } } void add() { jd1=jd1+10; jd2=jd2+10; if(jd1>145) jd1=145; if(jd2>130) jd2=130; } void pluse() { jd1=jd1-10; jd2=jd2-10; if(jd1<65) jd1=65; if(jd2<50) jd2=50; } void bizhang() { //Timer0_Init(); if((qian1==1)&(qian2==1)) go(); else if((qian1==0)&(qian2==0)) { DelayMs(1000);back();DelayMs(800);turnright();DelayMs(800); } else if((qian1==1)&(qian2==0)) { back();DelayMs(1000);turnleft();DelayMs(800); } else if((qian1==0)&(qian2==1)) { back();DelayMs(1000);turnright();DelayMs(800); } } void DelayMs(unsigned int x) //延迟函数,0.14ms误差 0us { unsigned char i; while(x--) { for (i = 0; i<13; i++) {} } } void IrInit() // 初始化红外线接收 { IT0=1;//下降沿触发 EX0=1;//打开中断0允许 IRIN=1;//初始化端口 } void ReadIr() interrupt 0//读取红外数值的中断函数 返回值value { unsigned char j,k; unsigned int err; Time=0; DelayMs(70); if(IRIN==0) //确认是否真的接收到正确的信号 { err=1000; //1000*10us=10ms,超过说明接收到错误的信号 /*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时 侯,程序死在这里*/ while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去 { DelayMs(1); err--; } if(IRIN==1) //如果正确等到9ms低电平 { err=500; while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去 { DelayMs(1); err--; } for(k=0;k<4;k++) //共有4组数据 { for(j=0;j<8;j++) //接收一组数据 { err=60; while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去 // while (!IRIN) { DelayMs(1); err--; } err=500; while((IRIN==1)&&(err>0)) //计算高电平的时间长度。 { DelayMs(1);//0.14ms Time++; err--; if(Time>30) { EX0=1; return; } } IrValue[k]>>=1; //k表示第几组数据 if(Time>=8) //如果高电平出现大于565us,那么是1 { IrValue[k]|=0x80; } Time=0; //用完时间要重新赋值 } } value=IrValue[2]; switch(value) { case 0x45:flag=1;led=~led;break; case 0x47:flag=2;led=~led;break; case 0x46:flag=3;led=~led;break; case 0x44:flag=4;led=~led;break; case 0x18:add();led=~led;break; case 0x52:pluse();led=~led;break; default:break; } //判断模式 } } }
