51单片机项目设计:超声波测距、智能小车(keil+proteus)带仿真 您所在的位置:网站首页 51智能小车设计报告 51单片机项目设计:超声波测距、智能小车(keil+proteus)带仿真

51单片机项目设计:超声波测距、智能小车(keil+proteus)带仿真

2024-07-10 13:10| 来源: 网络整理| 查看: 265

超声波测距小车

资料链接:51单片机超声波测距.rar 链接:https://pan.baidu.com/s/1rEJR5DYoAz_lJZHWJy9sOg 提取码:abcd 取走点赞哦~

项目展示: 在这里插入图片描述 仿真展示 : 在这里插入图片描述

一、项目要求

(一)项目内密

本课题的主要内容是,将超声波传感器安装在一台沿直线行走的小车上,由AT89C51 控制超声波传感器,发出超声信号,记录超声液从发射到接收的所需要的时间,得到其与|被测物体之间的能离。在小车行走的过程中,不断重复测距,得到一组距离数据。由单片机记录测得的距离,经过数据处理,将其显示在液晶屏上。同时,将一组距离数据,由串口传到上位机,由VB程序保存距离数据,并画出曲线,就得到了被测物体的单边轮廓。

(二)课题研究方需

超声波测距仪系统主要由单片机最小系统、超声波模块、LCO显示电路及电源电路组成。系统的主要功能如下:

超声波传感器发射和接收超声波,依据计时时间测量出与被测物体之间的矩离。

AT89CS51单片机作为主控制器,控制超声波信号的发送和接收,可以用来控制发射模块脸发脉冲的开始时间和脉宽,响应接受超声波返回时刻并进行测量和计数发射到返回的时间间隔。

液晶屏显示器实时显示测量距离。

上位机串口通讯,接收距离数据,利用VB程序把则好的距离记下并画出曲线,还原轮那曲线,从而实现通过超声波来测量物体单边轮常测量。

二、项目设计

(一)项目设计思想

1、使用HC-SR04超声波传感器模块测量距离 2、使用LCD1602液晶显示屏显示实时测量距离 3、使用L298N电机驱动,驱动两个电机运转,设置一个按键,按下按键,小车前进一段距离 4、开启串口通信,把距离数据通过串口发送到电脑进行处理

(二)购买材料 1、智能小车底盘 在这里插入图片描述 2、L298N 在这里插入图片描述 3、超声波模块HC-SR04 在这里插入图片描述 4、液晶屏 LCD1602 在这里插入图片描述 再准备一些其他小元件就OK,单片机最小系统、洞洞板、按键、插座等

(三)先设计硬件 根据原理图设计硬件 在这里插入图片描述 这是我设计好的实物图 在这里插入图片描述 在这里插入图片描述

(四)编写代码 main.c

/******************************************** 项目名称:51超声波测距 作者:化作尘 版本:V1.1 更新时间:V1.0 2020年4月12日18:28:02 V1.1 2020年4月23日13:35:00 邮箱:[email protected] *********************************************/ #include "reg52.H"//器件配置文件 #include"lcd.h" //SR04传感器接口 sbit RX = P3^2; sbit TX = P3^3; sbit key = P1^4; char keymode=0; //按键 模式 int keycount=0; //小车运动延时控制 //变量声明 unsigned int time=0; unsigned long S=0; char Mode=0; bit flag=0; bit flag_KEY=0; unsigned char act[]={0xff,0xfa,0xf5,0xf9,0xf6}; //小车动作控制 unsigned char disbuff[4] ={0,0,0,0}; //缓存数组用于存放距离信息 /***************************************************************************/ //延时 void delay_ms(unsigned int m) { unsigned int b,c; for(c=0;c key = 1; delay_ms(1); if(key==0) //检测按键K1是否按下 开关 { delay_ms(10); //消除抖动 一般大约10ms if(key==0) //再次判断按键是否按下 { keymode++; if(keymode == 2)keymode = 0; } while(!key); //检测按键是否松开 } if(keymode==1) //检测到按键按下了一次,就让运动延时一会 { keycount++; if(keycount==550) { keycount=0; keymode=0; } } P1 = act[keymode]; //小车运动控制 } /***************************************************************************/ //超声波测距函数,距离保存到S void Conut(void) { TX=1; //启动一次模块 delay(10); //延时10US TX=0;; while(!RX); //当上次接收完波后,RX引脚是低电平,取反就是1,此while成立,反复判断RX状态。当RX没有接收到返回波时是高电平,取反就是0,此while不成立,跳出 TR0=1; //开启计数 while(RX); //当RX没有接收到返回波,此while成立,程序停在这里一直判断RX状态。当RX接收到返回波,RX引脚变为低电平,此while不成立,跳出 TR0=0; //停止计数 time=TH0*256+TL0; //读出T0的计时数值 TH0=0; TL0=0; //清空计时器 S=(time*1.7)/100; //算出来是CM //声音的速度是340m/s,时间的单位是us,计算到秒需要将时间数据/1000000, //长度=速度*时间,340*time/1000000,长度数据单位是m转换成cm需要乘以100得到340*time/10000, //小数点都向左移两位得到3.4*time/100,因为超声波是往返了,所以再除以2,得到距离数据(time*1.7)/100 if(Mode==0) //非设置状态时 { if(S>=999) //超出测量范围显示“-” { disbuff[0]='o'-0x30; //“-” disbuff[1]='v'-0x30; //“-” disbuff[2]='e'-0x30; //“-” disbuff[3]='r'-0x30; //“-” } else { disbuff[0]=S%1000/100; //将距离数据拆成单个位赋值 disbuff[1]=S%100/10; disbuff[2]='.'-0x30; disbuff[3]=S%10; } } } /***************************************************************************/ //定时器0 void zd0() interrupt 1 //T0中断用来计数器溢出,超过测距范围 { flag=1; //中断溢出标志 } /***************************************************************************/ //定时器初始化 void Timer_Init(void) { TMOD=0x11; //设T0为方式1 TH0=0; TL0=0; TR0=0; //停止计数 ET0=1; //允许T0中断 EA=1; //开启总中断 } /***************************************************************************/ //串口初始化 void UsartInit() { SCON=0X50; //设置为工作方式1 TMOD=0X20; //设置计数器工作方式2 PCON=0X80; //波特率加倍 TH1=0XF3; //计数器初始值设置,注意波特率是4800的 TL1=0XF3; EA=1; //打开总中断 TR1=1; //打开计数器 } /***************************************************************************/ //串口发送距离数据 void Uart_Send(void) { /**将距离数据通过串口发送出去**/ SBUF=S/256;//将数据放入到发送寄存器 while(!TI); //等待发送数据完成 TI=0; //清除发送完成标志位 SBUF=S%256;//将数据放入到发送寄存器 while(!TI); //等待发送数据完成 TI=0; //清除发送完成标志位 } /****************************************************************************/ //主函数 void main(void) { int displaycount=0; Timer_Init(); //初始化定时器 UsartInit(); //串口初始化 9600 LcdInit(); //初始化LCD LcdWritestr(" superwave "); //液晶显示距离 while(1) { Conut(); //计算 displaycount++; if(displaycount==10)//隔一段时间刷新一次显示屏 { displaycount=0; LcdWriteCom(0x80); P1 = 0xff; LcdWritestr("distance:"); //液晶显示距离 LcdWriteData(disbuff[0]+0x30); LcdWriteData(disbuff[1]+0x30); LcdWriteData(disbuff[2]+0x30); P1 = act[keymode]; //小车运动控制 LcdWriteData(disbuff[3]+0x30); LcdWritestr("cm"); } Key(); //按键控制电机运转 Uart_Send();//串口发送距离数据 } } void Usart() interrupt 4 { RI = 0;//清除接收中断标志位 }

lcd.h

#ifndef __LCD_H_ #define __LCD_H_ /********************************** 当使用的是4位数据传输的时候定义, 使用8位取消这个定义 **********************************/ //#define LCD1602_4PINS /********************************** 包含头文件 **********************************/ #include //---重定义关键词---// #ifndef uchar #define uchar unsigned char #endif #ifndef uint #define uint unsigned int #endif /********************************** PIN口定义 **********************************/ #define LCD1602_DATAPINS P0 sbit LCD1602_E=P2^7; sbit LCD1602_RW=P2^5; sbit LCD1602_RS=P2^6; /********************************** 函数声明 **********************************/ /*在51单片机12MHZ时钟下的延时函数*/ void Lcd1602_Delay1ms(uint c); //误差 0us /*LCD1602写入8位命令子函数*/ void LcdWriteCom(uchar com); /*LCD1602写入8位数据子函数*/ void LcdWriteData(uchar dat) ; /*LCD1602初始化子程序*/ void LcdInit(); void LcdWritestr(uchar *dat); void LcdWritenum(uint num); void LcdClean(void); #endif

lcd.c

#include "lcd.h" /******************************************************************************* * 函 数 名 : Lcd1602_Delay1ms * 函数功能 : 延时函数,延时1ms * 输 入 : c * 输 出 : 无 * 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。 *******************************************************************************/ void Lcd1602_Delay1ms(uint c) //误差 0us { uchar a,b; for (; c>0; c--) { for (b=20;b>0;b--) { for(a=1;a>0;a--); } } } /******************************************************************************* * 函 数 名 : LcdWriteCom * 函数功能 : 向LCD写入一个字节的命令 * 输 入 : com * 输 出 : 无 *******************************************************************************/ #ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时 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; } #else void LcdWriteCom(uchar com) //写入命令 { LCD1602_E = 0; //使能清零 LCD1602_RS = 0; //选择写入命令 LCD1602_RW = 0; //选择写入 LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 // Lcd1602_Delay1ms(1);//注释让lcd写快一点 LCD1602_E = 0; LCD1602_DATAPINS = com LCD1602_E = 0; //使能清零 LCD1602_RS = 1; //选择写入数据 LCD1602_RW = 0; //选择写入 LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 // Lcd1602_Delay1ms(1); LCD1602_E = 0; LCD1602_DATAPINS = dat LcdWriteCom(0x32); //将8位总线转为4位总线 LcdWriteCom(0x28); //在四位线下的初始化 LcdWriteCom(0x0c); //开显示不显示光标 LcdWriteCom(0x06); //写一个指针加1 LcdWriteCom(0x01); //清屏 LcdWriteCom(0x80); //设置数据指针起点 } #endif /******************************************************************************* * 函 数 名 : LcdWritestr * 函数功能 : 向LCD写入多个字节的数据 * 输 入 : *dat * 输 出 : 无 *******************************************************************************/ void LcdWritestr(uchar *dat) //写入字符串 { while(*dat != '\0') { LcdWriteData(*dat); dat++; } }

博主能力有限,如有不到之处还请各位批评指正 。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有