课题的技术要求:本次课题最终要求小车能在无人操作的条件下实现自动避障,避障基于超声波测距的原理实现的,当超声波检测到小车与障碍物的距离大于设定值时,小车按照原先设定的速度正常行驶;当超声波检测到小车和障碍物的距离小于设定值时,单片机控制蜂鸣器发声同时控制小车停止。因为本次设计的小车时两轮驱动的小车,也没有安装舵机,所以小车的转弯通过控制两个车轮间的转速差实现。
课题研究的主要内容:本次设计以超声波避障为研究对象,以自动避障为核心控制功能。要研究内容包括:以STC89C52为控制核心的智能系统的平台搭建、各个模块的选型、多传感器的组合应用、PWM控制电机驱动的相应动作、外置储存器的选型、测距系统的选择与搭建、报警与显示系统的选择与搭建等。
系统总体流程图
STC89C52单片机接通电源后开始运行,首先对LCD1602的寄存器发送数据进行初始化,完成最基本的屏幕显示配置,然后在界面上显示主界面的框架,接下来在While循环中不断采集超声波发送的数据,进行转换后变为整数字节型显示在LCD1602屏幕上,若采集的数值大于设定值即报警。
键盘程序流程图
在键盘处理函数中,分别判断按下的为哪个按键,若按下设定值增加按键,则设定值的数值增加10;若按下设定值减少按键,设定值的数字减少10,并在变动后均存入外部储存器。
#include "reg51.h"
#include < intrins.h >
#define uchar unsigned char
#define uint unsigned int
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^6;
sbit LCD1602_RS=P2^5;
sbit Trig = P1^1;
sbit Echo = P1^0;
sbit BEEP = P2^4;
sbit MotorA_1 = P2^0;
sbit MotorA_2 = P2^1;
sbit MotorB_1 = P2^2;
sbit MotorB_2 = P2^3;
sbit I2C_SDA = P1^2;
sbit I2C_SCL = P1^3;
unsigned char Set_dis = 80;
unsigned char code ASCII[15] = {'0','1','2','3','4','5','6','7','8','9','.','-','M'};
static unsigned char DisNum = 0; //显示用指针
unsigned int time=0;
unsigned long S=0;
bit flag =0;
unsigned char disbuff[4] ={ 0,0,0,0,};
unsigned int DIstance;
void D_10()
{
uchar a, b;
for(b=1; b >0; b--)
{
for(a=2; a >0; a--);
}
}
void IIC_S()
{
I2C_SDA = 1;
D_10();
I2C_SCL = 1;
D_10();
I2C_SDA = 0;
D_10();
I2C_SCL = 0;
D_10();
}
void IIC_ST()
{
I2C_SDA = 0;
D_10();
I2C_SCL = 1;
D_10();
I2C_SDA = 1;
D_10();
}
uchar WD_SB(uchar dat, uchar ack)
{
uchar a = 0,b = 0;
for(a=0; a< 8; a++)
{
I2C_SDA = dat > > 7;
dat = dat < < 1;
D_10();
I2C_SCL = 1;
D_10();
I2C_SCL = 0;
D_10();
}
I2C_SDA = 1;
D_10();
I2C_SCL = 1;
while(I2C_SDA && (ack == 1))
{
b++;
if(b > 200)
{
I2C_SCL = 0;
D_10();
return 0;
}
}
I2C_SCL = 0;
D_10();
return 1;
}
uchar WD_RB()
{
uchar a = 0,dat = 0;
I2C_SDA = 1;
D_10();
for(a=0; a< 8; a++)
{
I2C_SCL = 1;
D_10();
dat < <= 1;
dat |= I2C_SDA;
D_10();
I2C_SCL = 0;
D_10();
}
return dat;
}
void CC_WR(uchar addr,uchar dat)
{
IIC_S();
WD_SB(0xa0, 1);
WD_SB(addr, 1);
WD_SB(dat, 0);
IIC_ST();
}
uchar CC_RD(uchar addr)
{
uchar num;
IIC_S();
WD_SB(0xa0, 1);
WD_SB(addr, 1);
IIC_S();
WD_SB(0xa1, 1);
num=WD_RB();
IIC_ST();
return num;
}
void RUN_UP()
{
MotorA_1 = 1;
MotorA_2 = 0;
MotorB_1 = 1;
MotorB_2 = 0;
}
void RUN_DOWN()
{
MotorA_1 = 0;
MotorA_2 = 0;
MotorB_1 = 0;
MotorB_2 = 0;
}
void RUN_RIGHT()
{
MotorA_1 = 1;
MotorA_2 = 0;
MotorB_1 = 0;
MotorB_2 = 1;
}
/*******************************************************************************
* 函 数 名 : Lcd1602_Delay1ms
* 函数功能 : 延时函数,延时1ms
* 输 入 : c
* 输 出 : 无
* 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c) //误差 0us
{
uchar a,b;
for (; c >0; c--)
{
for (b=199;b >0;b--)
{
for(a=1;a >0;a--);
}
}
}
/*******************************************************************************
* 函 数 名 : LcdWriteCom
* 函数功能 : 向LCD写入一个字节的命令
* 输 入 : com
* 输 出 : 无
*******************************************************************************/
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待数据稳定
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
/*******************************************************************************
* 函 数 名 : LcdWriteData
* 函数功能 : 向LCD写入一个字节的数据
* 输 入 : dat
* 输 出 : 无
*******************************************************************************/
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //写入数据
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
/*******************************************************************************
* 函 数 名 : LcdInit()
* 函数功能 : 初始化LCD屏
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //开显示
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
//按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; // 算出指令码
LcdWriteCom(X); //这里不检测忙信号,发送地址码
LcdWriteData(DData);
}
//按指定位置显示一串字符
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength] >=0x20) //若到达字串尾则退出
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
}
void StartModule() //启动模块
{
Trig=1; //启动一次模块
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
Trig=0;
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Conut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(time*1.7)/100; //算出来是CM
DIstance = S;
if((S >=700)||flag==1) //超出测量范围显示“-”
{
flag=0;
DisplayOneChar(0, 1, ASCII[11]);
DisplayOneChar(1, 1, ASCII[10]); //显示点
DisplayOneChar(2, 1, ASCII[11]);
DisplayOneChar(3, 1, ASCII[11]);
DisplayOneChar(4, 1, ASCII[12]); //显示M
}
else
{
disbuff[0]=S%1000/100;
disbuff[1]=S%1000%100/10;
disbuff[2]=S%1000%10 %10;
DisplayOneChar(0, 1, ASCII[disbuff[0]]);
DisplayOneChar(1, 1, ASCII[10]); //显示点
DisplayOneChar(2, 1, ASCII[disbuff[1]]);
DisplayOneChar(3, 1, ASCII[disbuff[2]]);
DisplayOneChar(4, 1, ASCII[12]); //显示M
}
}
void zd0() interrupt 1 //T0中断用来计数器溢出,超过测距范围
{
flag=1; //中断溢出标志
}
void main()
{
TMOD=0x01; //设T0为方式1,GATE=1;
TH0=0;
TL0=0;
ET0=1; //允许T0中断
EX0=1; //外部中断0开() EX1 为外部中断1 (P3^3)
IT0=1; //低电平触发 IT1为中断1
EX1=1; //外部中断0开() EX1 为外部中断1 (P3^3)
IT1=1; //低电平触发 IT1为中断1
EA=1; //开启总中断
Set_dis = CC_RD(0x01);
LcdInit();
DisplayListChar(4,0,"Car system");
while(1)
{
StartModule();
while(!Echo); //当RX为零时等待
TR0=1; //开启计数
while(Echo); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算
DisplayOneChar(8,1,(char)(Set_dis/100)+'0');
DisplayOneChar(9,1,(char)(Set_dis/10%10)+'0');
DisplayOneChar(10,1,(char)(Set_dis%10)+'0');
if(DIstance >Set_dis)
{
BEEP = 0;
RUN_RIGHT();
}else
{
BEEP = 1;
RUN_UP();
}
}
}
void Key1_INT( ) interrupt 0 // 这里0对应下表
{
Set_dis = Set_dis+10;
CC_WR(0x01,Set_dis);
}
void Key2_INT( ) interrupt 2 // 这里0对应下表
{
Set_dis =Set_dis-10;
CC_WR(0x01,Set_dis);
}
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !