51单片机学习之智能小车(2)

说明:

上篇主要介绍了小车用到的模块,此篇为代码部分,以及简单介绍调试中遇到的问题。如有问题请评论指出。(上篇:51单片机学习之智能小车(1))

主要代码内容:

头文件(函数声明和引脚定义)在上篇展示。
一些资源初始化和延时“51car.c”

#include "../HEAD/51car.h"
/****10us延时****/
void Delay10us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 27;
	while (--i);
}			  
/****10ms延时****/
void Delay10ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 117;
	j = 184;
	do
	{
		while (--j);
	} while (--i);
}
/****100ms延时****/
void Delay100ms()		//@12.000MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 5;
	j = 144;
	k = 71;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
/****定时器1,定时器2,串口初始化****/
/****定时器1工作方式1用于产生pwm波所需要的周期定时以及超声波模块周期性开启****/
/****定时器2工作方式3用于产生波特率9600bps****/
/****串口中断用于接收和发送蓝牙模块传输的数据****/
void T1_T2_ES_Init()
{
	TMOD = 0x10;	   //定时器1工作方式1
	
	T2CON = 0x30;	   //定时器2发生波特率

	TH1 = (65535 - 200) / 256;		//定时器0
	TL1 = (65535 - 200)	% 256;		//定时200us

	TH2 = 0xff;		   	//用于产生
	TL2 = 0xdc;		   	//波特率
					   
	RCAP2H = 0xff;	   	//存放
	RCAP2L = 0xdc;	   	//初值

	EA = 1;				//开放总中断
	ES = 1;				//开放串口中断
	ET1 = 1;			//开发定时器T1中断

	TR2 = 1;			//定时器2常开

	REN = 1;			//开启串口接收
	SM0 = 0;			//串口设置为
	SM1 = 1;			//工作方式1

	PS = 1;				//拉高中断优先级
}

电机驱动“metro.c”

#include "../HEAD/51car.h"
#include "../HEAD/metro.h"

unsigned char metro_pwm_count;
unsigned char metro_pwm_pre = 80;
unsigned char metro_pwm_now = 80;

/****前进****/
void Metro_Run()
{

	INA1 = 1;
	INA2 = 0;
	INA3 = 1;
	INA4 = 0;
	
	INB1 = 1;
	INB2 = 0;
	INB3 = 1;
	INB4 = 0;	
}

/****停止****/
void Metro_Stop()
{
	INA1 = 0;
	INA2 = 0;
	INA3 = 0;
	INA4 = 0;
	
	INB1 = 0;
	INB2 = 0;
	INB3 = 0;
	INB4 = 0;
} 

/****左转****/
 void Metro_Turnleft()
{
	INA1 = 1;
	INA2 = 0;
	INA3 = 1;
	INA4 = 0;
	
	INB1 = 0;
	INB2 = 1;
	INB3 = 0;
	INB4 = 1;	
}

/****右转****/
void Metro_Turnright()
{
	INA1 = 0;
	INA2 = 1;
	INA3 = 0;
	INA4 = 1;
	
	INB1 = 1;
	INB2 = 0;
	INB3 = 1;
	INB4 = 0;	
}

蓝牙模块"bulrtooth.c"

/**
蓝牙控制小车运动
输入文本形式数字可控制小车运动
'1' 前进 '2'左转 '3'右转 '4'停止 '5'加速
*/

#include "../HEAD/51car.h"
#include "../HEAD/metro.h"
#include "../HEAD/ultrasonic.h"
#include "../HEAD/buletooth.h"

unsigned char buletooth_recive_data; 
unsigned char buletooth_confirm_data;
unsigned char buletooth_pwm_send;
unsigned char ble_count;


/****字符串发送函数****/
/****通过蓝牙发送一串字符****/
/****************************/
void Bulebooth_Print_String(unsigned char *str)
{
	while(*str)
	{
		SBUF = *(str++);
		while(!TI);
		TI = 0;
	}
}

/****蓝牙控制函数****/
/****向蓝牙发送文本形式数字实现控制小车运动****/
/**********************************************/
void Buletooth_contrel_Metro()
{	
	//蓝牙接收到'1'	小车前进
	if(buletooth_recive_data == '1')
	{
		TR1 = 1;
		if(metro_pwm_count <= metro_pwm_now)
			Metro_Run();										  						  
		if(metro_pwm_count > metro_pwm_now)
			Metro_Stop();					  		         
		led2 = 0;										  //用于指示小车运动状态  前进亮
	}	
	//蓝牙接收到'2'	小车左转
	if(buletooth_recive_data == '2')
	{
		if(metro_pwm_count < metro_pwm_pre)
			Metro_Turnleft();
		if(metro_pwm_count >= metro_pwm_pre)
			Metro_Stop();
	}
	//蓝牙接收到'3'	小车右转
	if(buletooth_recive_data == '3')
	{
		if(metro_pwm_count < metro_pwm_pre)
			Metro_Turnright();
		if(metro_pwm_count >= metro_pwm_pre)
			Metro_Stop();
	}
	//蓝牙接收到'4' 小车停止
	if(buletooth_recive_data == '4')
	{
		TR1 = 0;
		Metro_Stop();
		metro_pwm_count = 0;
		led2 = 1;							              //用于指示小车运动状态	停止灭
	}
	//蓝牙接收到'5' 小车加速————只在前进中起作用
	if(buletooth_recive_data == '5')
	{
		metro_pwm_now += 10;	
		if(metro_pwm_now > 100)
		{
			metro_pwm_now = 80;
		}
		Bulebooth_Print_String("\nSpeed Up !!!\n");
		Bulebooth_Print_String("\nThe speed: ");
		Buletooth_Send_Pwm();
		buletooth_recive_data = '1';
	}		
}

/****pwm占空比回显函数****/
/****自动发送当前pwm占空比(速度百法比)发送格式:..%****/
/*****************************/
void Buletooth_Send_Pwm()
{
	unsigned char ble_count;
	ES = 0;					 //关闭串口中断
	for(ble_count = 0;ble_count < 4;ble_count++)              //发送4字节数据
	{
		switch (ble_count)
		{	
			case 0:
				buletooth_pwm_send = metro_pwm_now / 100 + 48;//发送速度占空比百位
				SBUF = buletooth_pwm_send;
				while(!TI);
				TI = 0;
			break;																   
																   
			case 1:
				buletooth_pwm_send = metro_pwm_now / 10 % 10 + 48; 		//发送速度占空比十位
				SBUF = buletooth_pwm_send;
				while(!TI);
				TI = 0;
				
			break;
			
			case 2:													//发送速度占空比个位
				buletooth_pwm_send = '0';
				SBUF = buletooth_pwm_send;
				while(!TI);
				TI = 0;
			break;			

			case 3:													//发送'%'
				buletooth_pwm_send = '%'; 
				SBUF = buletooth_pwm_send;
				while(!TI);
				TI = 0;
			break;
		}
	}
	ES = 1;														    //重新开启
}

循迹以及避障"avoidobstacle.c"

/**
超声波避障
模块:超声波模块,电机驱动模块,电机,led模块
不断进行障碍物检测
若检测到障碍物立即停止
*/

#include <reg52.h>
#include <intrins.h>
#include "../HEAD/51car.h"
#include "../HEAD/metro.h"
#include "../HEAD/ultrasonic.h"
#include "../HEAD/buletooth.h"
#include "../HEAD/tracing.h"

unsigned int ultra_time;	
unsigned long ultra_dis;
unsigned int ultra_con_time;
unsigned char ultra_send_data;
unsigned int ultra_send_count;

/****超声波初始化函数****/
/****防止与主函数串口通信混乱****/
/********************************/
void Ultra_Void()
{
	TMOD = 0x11;

	TH0 = 0;		   				//从0开始
	TL0 = 0;						//计时

	TH1 = (65535 - 200) / 256;		
	TL1 = (65535 - 200)	% 256;
		
	EA = 1;
	ET1 = 1;

	TR1 = 1;

}

/****超声波控制函数****/
/****每80ms启动一次计算小车到障碍物的距离****/
/**************/
void Ultra_Con()
{
	trg = 1;		  		 //向控制端
	Delay10us();	  		 //提供
	Delay10us();	 		 //20us
	trg = 0;		  		 //的高电平
}


/****超声波距离计算函数****/
/****计算小车到障碍物的距离单位:cm****/
/**************************************/
void Ultra_Dis_Count()
{	
	while(ech)						//未收到回响定时器0待定   
	{
		if(buletooth_recive_data == 'T')
		break;
	}				 							 
		TR0 = 0;				 
										  
	while(!ech)
	{
		if(buletooth_recive_data == 'T')
		{
			break;
		}
	}
		TR0 = 1;				   //收到回响定时器0开始计时
	ultra_time = TH0 * 256 + TL0;  //读取T1定时器时间

	ultra_dis = (long)(ultra_time * 0.017); //计算小车到障碍物的距离(cm)
								  	
	TH0 = 0;				 	//重装
	TL0 = 0;				 	//定时器0
}

/****超声波测距回显****/
/****自动发送当前小车距离障碍物的距离****/
void Ultra_Buletooth_Send()
{
	if(buletooth_recive_data == '9')
	{		
		if(ultra_send_count == 50)//周期为超声波周期*50
		{	 
			ultra_send_count = 0;
			
 			if(ultra_dis > 50)
				Bulebooth_Print_String("GO GO GO !!!");
			if(ultra_dis <= 50)
				Bulebooth_Print_String("Encounter obstacles !!!");
			for(ultra_send_count;ultra_send_count < 6;ultra_send_count++)
			{
				switch (ultra_send_count)
				{
					case 5:							//发送'm'
						ultra_send_data = 'm';
						SBUF = ultra_send_data;
						while(!TI);
						TI = 0;
					break;
	
					case 4:												     //发送'c'
						ultra_send_data = 'c';
						SBUF = ultra_send_data;
						while(!TI);
						TI = 0;
					break;
	
					case 3:
						ultra_send_data = (ultra_dis % 10) + 48;			  //发送个位
						SBUF = ultra_send_data;
						while(!TI);
						TI = 0;
					break;
	
					case 2:
						ultra_send_data = (ultra_dis / 10 % 10) + 48;		  //发送十位
						SBUF = ultra_send_data;
						while(!TI);
						TI = 0;
					break;													  
	
					case 1:
						ultra_send_data = (ultra_dis / 100 % 10) + 48;		  //发送百位
						SBUF = ultra_send_data;
						while(!TI);
						TI = 0;
					break;
	
					case 0:
						ultra_send_data = (ultra_dis / 1000) + 48;		      //发送千位
						SBUF = ultra_send_data;
						while(!TI);
						TI = 0;
					break;
				}
			}
		}
	}
		
}

/****超声波控制电机函数****/
/***距离大于50cm电机转速不变*****/
/***距离小于50cm电机停止停止*****/
/********************************/
void Ultra_Metro() 
{	
	/*小车处在循迹避障模式距离障碍物距离大于20cm*/
	if(ultra_dis > 50 && buletooth_recive_data == '9')	 		
	{
		led2 = 0;			//小车前进 指示灯亮
		if(metro_pwm_count < 70)
			Metro_Run();
		if(metro_pwm_count >= 70)
			Metro_Stop();											 											  		
	}
	/*小车处在循迹避障模式距离障碍物距离较近*/
	if(ultra_dis <= 50 && buletooth_recive_data == '9')	
	{
		led2 = 1;			//距离小于20cm 指示灯灭
		Metro_Stop();												   	
	}
}

main.c

#include <reg52.h>
#include <intrins.h>
#include "../../HEAD/buletooth.h"
#include "../../HEAD/ultrasonic.h"
#include "../../HEAD/metro.h"
#include "../../HEAD/tracing.h"
#include "../../HEAD/51car.h"

void main()
{	
	//初始化
	T1_T2_ES_Init();

	P0 = 0xF0;
	 
	P2 = 0xff;
	  
	while(1)
	{	
	 
		Bulebooth_Print_String("\nWelcome to 51 smart car.");
		Delay100ms();Delay100ms();
		Bulebooth_Print_String("\nSelect function mode.");
		Delay100ms();Delay100ms();
		
		//向蓝牙发送'0' 小车进入蓝牙控制模式
		if(buletooth_recive_data == '0')
		{
			Bulebooth_Print_String("\nYou've chosen Bluetooth mode.");
			Bulebooth_Print_String("\nNow you can control the car's motion through Bluetooth !!!");
			while(1)
			{
				led1 = 0;
				Buletooth_contrel_Metro();				//蓝牙控制函数详见:buletooth.c

				//向蓝牙发送'T'	小车退出蓝牙控制模式
				if(buletooth_recive_data == 'T')		//蓝牙接收到'T' 退出蓝牙控制模式
				{
					led1 = 1;
					led2 = 1;
					TR1 = 0;
					Bulebooth_Print_String("\nYou're out of Bluetooth mode.");
					break;
				}				
			}		
		} 

		//向蓝牙发送'9' 小车进入循迹避障模式
		
		if(buletooth_recive_data == '9')
		{	
			led1 = 0;
				
		   	if(buletooth_recive_data == '9')
				Metro_Run();//初始化一下,没有的话会出问题,可能在代码上看不出来但是调试的时候确实存在
			if(buletooth_recive_data == 'T')
				Metro_Stop();

			Ultra_Void();         //循迹避障模式
			
			Bulebooth_Print_String("You've chosen track and obstacle avoidance mode.");
			Bulebooth_Print_String("Now the car can automatically track and avoid obstacles !!!\n");

			tracing_flag_left0 = 1;tracing_flag_left1 = 1;tracing_flag_right0 = 1;tracing_flag_right1 = 1;			
			while(1)
			{	//只能用while判断,if也会出问题,若要用if的话要改变代码结构,测试后此结构while为最佳
				while((tracing_flag_left0 == 1 || tracing_flag_left1 == 1) 
				   && (tracing_flag_right0 == 1 || tracing_flag_right1 == 1))//在轨迹上
				{	
					//Bulebooth_Print_String("On the track");
					Ultra_Dis_Count();
					Ultra_Metro();
					if(buletooth_recive_data == 'T')		   //蓝牙接收到'T' 退出循迹避障模式
					{	
						TR1 = 0;
						led1 = 1;
						led2 = 1;
						Bulebooth_Print_String("You're out of track and block mode");					 
						break;
					}	
				}
				while((tracing_flag_left0 == 0 || tracing_flag_left1 == 0) &&
					  (tracing_flag_right0 == 0 || tracing_flag_right1 == 0))//不在轨迹上 
				{
					//Bulebooth_Print_String("Not on the track");
					Metro_Stop();
					if(buletooth_recive_data == 'T')		   //蓝牙接收到'T' 退出循迹避障模式
					{	
						TR1 = 0;
						led1 = 1;
						led2 = 1;
						Bulebooth_Print_String("You're out of track and block mode");					 
						break;
				}
				}
				while((tracing_flag_left0 == 1 || tracing_flag_left1 == 1) &&
				      (tracing_flag_right0 == 0 || tracing_flag_right1 == 0))
				{	
					//Bulebooth_Print_String("Adjustment in progress");
					if(metro_pwm_count <= 80)
						Metro_Turnleft();
					if(metro_pwm_count > 80)
						Metro_Stop();
					if(buletooth_recive_data == 'T')		   //蓝牙接收到'T' 退出循迹避障模式
					{	
						TR1 = 0;
						led1 = 1;
						led2 = 1;
						Bulebooth_Print_String("You're out of track and block mode");					 
						break;
					}		
				}
				while((tracing_flag_left0 == 0 || tracing_flag_left1 == 0) && 
					  (tracing_flag_right0 == 1 || tracing_flag_right1 == 1))
				{
					//Bulebooth_Print_String("Adjustment in progress");
					if(metro_pwm_count <= 80)
						Metro_Turnright();
					if(metro_pwm_count > 80)
						Metro_Stop();
					if(buletooth_recive_data == 'T')		   //蓝牙接收到'T' 退出循迹避障模式
					{	
						TR1 = 0;
						led1 = 1;
						led2 = 1;
						Bulebooth_Print_String("You're out of track and block mode");					 
						break;
					}
				}
				if(buletooth_recive_data == 'T')		   //蓝牙接收到'T' 退出循迹避障模式
				{	
					TR1 = 0;
					led1 = 1;
					led2 = 1;
					Bulebooth_Print_String("You're out of track and block mode");					 
					break;
				}	
			
			}			
		} 
	}
}


void T1_ser() interrupt 3
{	
	TH1 = (65535 - 200) / 256;		//定时器1
	TL1 = (65535 - 200)	% 256;		//定时200us

	metro_pwm_count++;					  //pwm计数 常开
	
	if(buletooth_recive_data == 'T')	  //收到退出信号
	{
		TR1 = 0;						  //关闭定时器
		led3 = 1;						  //熄灭led3
	}
										  
	if(metro_pwm_count >= 100)
	{
	
		metro_pwm_count = 0;			  //pwm计数清零
	}

	if(buletooth_recive_data == '9')	  //接收到'9' 超声波模块开启
	{	
		
		ultra_con_time++;				  //超声波模块控制计数 收到蓝牙信息'9'后开启
		if(ultra_con_time >= 150)
		{
			led3 = ~led3;				  //指示灯3闪烁工作正常
			ultra_con_time = 0;			  //超声波模块控制计数清零
			Ultra_Con();				  //向模块控制端发送20us高电平信号
			ultra_send_count++;
		}
		Ultra_Buletooth_Send();			  //超声波检测距离回显
	}

	
}

void ES_ser() interrupt 4				 //串口中断
{
	if(RI == 1)							 //中断被拉高
	{
		RI = 0;							 //重新置位RI使之重新接受数据
		buletooth_recive_data = SBUF;	 //存储接受的数据

		Delay10ms();
		
	/*						 
		buletooth_confirm_data = 'F';		 //接收到数据那就返回F
		SBUF = buletooth_confirm_data;			 //发送数据
		while(!TI);							 //发射失败停留直到成功
		TI = 0;								 //重新置位TI使之重新发送数据
	*/
				   
	}

	if(buletooth_recive_data == '1')
	{
		Bulebooth_Print_String("Moving Forward !!!\n");
	}
	if(buletooth_recive_data == '2')
	{
		Bulebooth_Print_String("Turn Left !!!\n");
	}
	if(buletooth_recive_data == '3')
	{
		Bulebooth_Print_String("Turn Right !!!\n");
	}
	if(buletooth_recive_data == '4')
	{
		Bulebooth_Print_String("Stop !!!\n"); 
	} 
}  

调试过程中遇到的问题

1.电源和接地问题

单片机上的供电口不够的情况的,可以通过外加电池组的方式(并不建议,最好是航模电池或者是直流稳压电源之类的可以输出稳定电压的电池,干电池电池组电压输入并不理想,一是输出电压不理想没法输出想要的电压,二是小车没有考虑功耗的问题干电池消耗比较大,干电池的电压很容易受影响)解决。接地不够用的情况下,可以外接出来母线接排针的方法解决,也可以通过P0口拉低来模拟接地(最好是不要,学长后来给我说对单片机不好,而且吸收电流能力也不是很强,低功耗的还可以带起来)。

2.电机驱动模块(小汇总)

首先驱动模块不能直接接电池组,电池组的工作电流远超过驱动模块的正常工作电流,直接接上电池组后模块就会短时间内发热,极易烧坏,并且不能接P0模拟地,工作电流远远大于P0口能接受的电流,电流太小带不动电机。可能会出现电机转速不同或一侧转动一侧不转动的问题,这个问题看似驱动问题,实则电压问题,TT马达的最小工作电压在3v左右,若PWM占空比较低,就会造成转速不一致的现象,所以调速最好是从3V左右的电压为最小限度进行调速。

3.手机无法与蓝牙模块连接

因模块协议老旧(蓝牙协议虽然兼容性很强但是确实出现这个问题了,明明设备以及是配对好了但是就是无法连接),部分手机中蓝牙串口助手不支持。在应用商店选择合适的即可。

4.蓝牙无法与手机进行通信

此模块可接P0模拟地,但过高或过低的电压都会造成模块无法正常通信。排除电源问题后,首先查看接线,若接线正确则因代码原因。若接线错误(蓝牙RXD与单片机RXD相连,接线错误可能会使模块损坏)手机与蓝牙可通信,但数据不会储存在已定义的变量中,通信不起控制作用,实际上是通过TTL转串口模块(串口、COM口、UART口, TTL、RS-232、RS-485区别详解这篇文章有介绍,简单说就是TTL和串口的协议不同,TTL转串口模块就是用来进行协议转化的。)(已和PC相连)与PC通信了(简单说就是串口被占用了),此时通过串口助手可看到蓝牙模块接收的数据。在对单片机进行烧录的时候,已连接蓝牙模块不能烧录原因就是烧录的时候会占用TXD和RXD接口。

5.超声波模块无法判断距离

此模块同蓝牙模块也可接模拟地,也需要合适的电压。首先是接线问题。接线正确则为程序错误,我看另外一同学,他写的超声波模块控制是在循环结构中,利用延时函数反复循环执行,这种方法易受其他程序的影响,因此发射超声波波数量较少(能理解吧…),模块很大可能接收不到回波,因此改为在T1定时器中断函数中执行超声波控制函数,此方法超声波模块的启动周期较短(周期一定要合适大概为100ms也可以稍微高一点不要超过300ms),不易受其他程序影响,因此发射的超声波数也较大,能够解决超声波模块接收不到回波的问题。

6.小车无法循迹(这个问题对于不同的板子和代码差异比较大,可能在一个人的板子没问题但是换一个就有问题了,单独进行功能实现可能没有问题,但是要结合项目可能就有问题了,所以要根据自己的条件进行调试)

此模块虽对电压要求不高,但是对接地有一定要求,不能接模拟地。最初因此问题花时间较久,但经过不断调试,问题锁定为单片机无法判断循迹模块的返回状态。这与单片机IO口的结构有关系,IO口在准输入/输出模式下(查数据手册,里面有具体说明),应在判断前拉高初始化,因为IO口的下拉能力很强,循迹模块无法将其拉高,反之IO口的上拉能力很弱,能够被循迹模块拉低。

7.一个模块化编程的问题

编写多个文件,用起来相当方便,但是一定要注意功能间的时序。

结语

到此小车项目就讲完了,若我所说的有问题,请一定评论指出,感谢观看。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ydon?tkwhmeIS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值