前言

本文设计的智能车带有循迹、测速以及计时的功能,它能够在设定的范围内沿着特定的路线在前进过程中,方向可以根据线路自动更改,并且可以显示速度和运行时间。


一、结构

1.我们先看下物品清单:

万向轮 1
橡胶车轮 2
亚克力板 1
电位器10K 1
电机码盘 1
直流减速电机 2
L298N电机驱动模块 1
TCRT5000红外传感器 2
LCD1602液晶显示屏 1
STC89C51单片机 1
测速传感器模块 1
USB转TTL下载器 1
1.5V干电池 4
杜邦线、铜柱、螺丝 若干

2.接下来看下重要部件以及最终实物图片

(1)电位器

在这里插入图片描述

(2)L298N电机驱动模块

在这里插入图片描述

(3)电机码盘

在这里插入图片描述

(4)TCRT5000红外传感器

在这里插入图片描述

(5)LCD1602液晶显示屏

在这里插入图片描述

(6)测速传感器模块

在这里插入图片描述

(7)小车正面

在这里插入图片描述

(8)小车背面

在这里插入图片描述
(9)LCD1602液晶屏幕实现效果

在这里插入图片描述

二、接线

1.我们先来看LCD1602液晶显示屏的接线

在这里插入图片描述

1.直接接地

2.接VCC

3.接在一个滑动变阻上再与地相接。VEE(V0)为液晶显示器对比度调整端,我们通过一个10K的电位器再与地相接用以调整对比度。(不接电位器也要接地)

4.接RS->P2.7 (RS在感应到高电平时是数据寄存器、低电平时是指令寄存器)

5.接RW->P2.6

6.接E使能端->P2.5。当E端由高电平信号跳变成低电平信号时,液晶模块执行命令

7-14.接数据写入->P0.0-P0.7

15.我们通过连接一个电阻再与VCC相连,电阻可以防止显示屏烧坏

16.直接接地(屏幕背光灯的负极)

2.测速传感器模块接线

除了接好ACC和GND外,需要把DO口接在单片机的T0计数器P3.2口上。

3.其余模块的接线较为简单,具体可以参考我的视频资料以及个人博客里的程序。

三、程序

#include<AT89X52.H>
#include <intrins.h>     //Keil外部函数库包含文件,_nop_函数在此库中

#define uint unsigned int 
//定义uint为无符号整型       
#define uchar unsigned char 
//定义uchar为无符号整型
void delayXms(uint );   //声明Xms延时函数
void delay1ms(void);    //声明1ms延时函数
/*********************变量定义***************************/
uint i,n,sec,min,hour;
uchar sec_ge,sec_shi,min_ge,min_shi,hour_ge,hour_shi,bai,shi,ge;
long int s,M;
/***************小车驱动模块输入IO口*****************/ 
   sbit IN1=P1^2; 
   sbit IN2=P1^3;
   sbit IN3=P1^4;
   sbit IN4=P1^5; 
/********************液晶屏I/O口定义**********************/
sbit RS=P2^7;	//寄存器选择位,将RS位定义为P2.0引脚			
sbit RW=P2^6;	//读写选择位,将RW位定义为P2.1引脚
sbit E =P2^5;		//使能信号位,将E位定义为P2.2引脚
/********传感器接线定义********/
    #define Left_led        P3_7	  		//接循迹模块L0,左
    #define Right_led       P3_6	       	//接循迹模块R0,右
	#define Left_go      {P1_2=1,P1_3=0;}   //左电机向前走
	#define Left_back    {P1_2=0,P1_3=1;} 	//左电机向后转
	#define Left_Stop    {P1_2=0,P1_3=0;}   //左电机停转                     
	#define Right_go     {P1_4=1,P1_5=0;}	//右电机向前走
	#define Right_back   {P1_4=0,P1_5=1;}	//右电机向后走
	#define Right_Stop   {P1_4=0,P1_5=0;}   //右电机停转   							 
/*******************初使化显示数组*********************/
uchar dis1[]={"Time:  h  m  s"};					  
uchar dis2[]={"Speed:   mm/s"};
/************************驱动函数**************************/
//前速前进
     void  run(void)
{
	 Left_go ;   //左电机往前走
	 Right_go ;  //右电机往前走
}

//后退函数 
     void  backrun(void)
{
	 Left_back;   //左电机往后走
	 Right_back;  //右电机往后走
}

//左转
     void  leftrun(void)
{
	 Right_go ;  //右电机往前走
     Left_back;  //左电机后走
}

//右转
     void  rightrun(void)
{ 
     Left_go  ;   //左电机往前走
	 Right_back;  //右电机往后走	
}

//停止
     void  stop(void)
{	 
	 Right_Stop ;  //右电机停止
     Left_Stop  ;  //左电机停止
}												  
/********************X毫秒延时函数**********************/
void delayXms(uint ms)
{
	uint k;
	for(k=0;k<ms;k++)
	  {delay1ms();}
} 
void delay1ms(void)
{
    uint j;
    for(j=0;j<=120;j++)
      {_nop_();}
}
/*******************液晶显示函数*********************/
uchar lcd_busy()	    /*判断液晶模块的忙碌状态*/
{
	bit result;
	RS=0;
	RW=1;
	E=1;
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	result = (bit)(P0&0x80);
	E=0;
	return result;
}
void lcd_wcmd(uchar cmd)   /*写指令数据到LCD*/
{
	while(lcd_busy());
	RS=0;
	RW=0;
	E=0;
	_nop_();
	_nop_();
	P0=cmd;
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	E=1;
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	E=0;		
}

void lcd_pos(uchar pos)	 /*指定字符显示的实际地址*/ 
{
	lcd_wcmd(pos|0x80);
}
void lcd_wdat(uchar dat)		/*将数据(字符的标准ASCII码)写入液晶模块*/
{
	while(lcd_busy());
	RS=1;
	RW=0;
	E=0;
	P0=dat;
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	E=1;
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	E=0;	
}
void LcdInit()		/*LCD1602初始化函数*/
{
	delayXms(12);
	lcd_wcmd(0x38);
	delayXms(4);
	lcd_wcmd(0x38);	
	delayXms(4);
	lcd_wcmd(0x38);
	delayXms(4);
	lcd_wcmd(0x0c);
	delayXms(4);
	lcd_wcmd(0x06);
	delayXms(4);
	lcd_wcmd(0x01);
	delayXms(4);	
}
/*******************定时器1初使化函数**********************/
void T1_Init()
{
	TMOD = 0x10;	            //定时器1设置为8位自动加载模式
	ET1=1;			        	//开定时器中断
	EA=1;                       //打开总中断
	IP=0x04;                    //设置中断优先级
	TH1 = (65535-50000)/256;	//初使加载50毫秒
	TL1 = (65535-50000)%256;
}
/*******************外部中断初使化***********************/
void INT_Init()
{
	IT0 = 1;			//设置外部中断0为下降沿触发 
	EX0 = 1;  			//开外部中断0
	EA = 1;				//开总中断
}
/********************外部中断**************************/
void my_INT0(void) interrupt 0
{
	M=M++;			    //每中断一次变量加1
}
/******************定时器1中断*************************/
void timer1() interrupt 3
{   
    TR1=0;                      //停止T1
	TH1 = (65535-50000)/256;    //求整放在高8位
	TL1 = (65535-50000)%256;    //求余放在低8位
	n=n+1;                      //n++
	if(n==20)				  	//定时1秒(20个50ms为1秒)
	{     
		s=M/20.00*3.14*65;	    //1秒钟小车左轮走s1毫米,车轮胎直径为65MM
		bai=(s/100)+48;		    //百位转换成字符
		shi=(s%100/10)+48;		//十位转换成字符
		ge=(s%100%10)+48;	    //个位转换成字符
		n=0;                    //定时器中断次数归零
		sec++;					//1s时间											  
   		if(sec==60)             //如果秒为60,则清零,分加1
  		 {
   	   	    sec=0;
   		    min++;
   		}
   		if(min==60)             //如果分为60,则清零,时加1
   		{
    		min=0;
    		hour++;
   		}
   		if(hour==24)            //如果时为24,则清零
   		{
    		hour=0;
   		}
		sec_ge=sec%10+48;      //秒的个位和十位
		sec_shi=sec/10+48;
		min_ge=min%10+48;      //分的个位和十位
		min_shi=min/10+48;														
		hour_ge=hour%10+48;    //时的个位和十位
		hour_shi=hour/10+48;
		s=0;                   //小车左轮走的路程s1归零
		M=0;                   //外部中断0中断次数归零
	}
	 TR1=1;                    //启动T1
}
/************************主函数******************************/
void main()
{  
	T1_Init();                    //定时器T1初使化
	INT_Init();                   //外部中断初使化
	LcdInit();                    //1602液晶显示初使化
	TR1=1;			              //启动定时器T1
	lcd_pos(0x01);
	i=0;								   
	while(dis1[i] != '\0')        //1602液晶显示器第一行初使化显示
	{
		lcd_wdat(dis1[i]);
		i++;
	};											
	i=0;
	lcd_pos(0x41);
	while(dis2[i] != '\0')		  //1602液晶显示器第二行初使化显示
	{
		lcd_wdat(dis2[i]);
		i++;	
	};
/******while(1)无限循环******/ 
	while(1)                        
	{   
		if(Left_led==0&&Right_led==0)      //有信号为0  没有信号为1	  
			run();                             //调用前进函数		 
		else
		{			  
			if(Left_led==1&&Right_led==0)  //左边检测到黑线
			{
				leftrun();		               //调用小车左转函数
			}			   
			if(Right_led==1&&Left_led==0)  //右边检测到黑线
			{	  
				rightrun();		               //调用小车右转函数
			}
			if(Right_led==1&&Left_led==1)  //悬空状态  避悬崖
			{	  
				stop();		                   //调用小车停止		
			}									  
		}							 
	/****行驶时间显示***/                                   
	    lcd_pos(0x06);            
	    lcd_wdat(hour_shi);           
		lcd_pos(0x07);            
		lcd_wdat(hour_ge);                 			  
		lcd_pos(0x09);                 
		lcd_wdat(min_shi);         
        lcd_pos(0x0a);            
	    lcd_wdat(min_ge);          
		lcd_pos(0x0c);          
		lcd_wdat(sec_shi);  
		lcd_pos(0x0d);          
		lcd_wdat(sec_ge);         
	/****平均速度显示****/                                   
		lcd_pos(0x47);		     	
		lcd_wdat(bai);          
		lcd_pos(0x48);           
		lcd_wdat(shi);                    
		lcd_pos(0x49);                      
		lcd_wdat(ge);                      						  
    }	
}

具体的程序我就不讲解了,里面的注释也清晰明了,小车安装视频教程可去这里下载,本来设置不用积分下载的,不知道为什么每次都自动加上去了,没有积分的兄弟萌可以去百度云链接下载。链接:https://pan.baidu.com/s/1drKI1TT4TpylFfub0z32RA 提取码:zu15

四、运行视频

智能小车循迹

智能小车时间和速度显示

总结

我的智能小车功能比较简单,适合入门练手,具体的操作步骤和源码可以去我的个人博客里下载相关资料。# 51智能红外循迹小车(含测速和LCD显示)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐