基于51单片机的双模式蓝牙跟随智能小车设计详解

1. 功能介绍

智能小车有两种工作模式,分别是蓝牙避障,超声波跟随,其中模式的切换和小车的调速都是通过蓝牙完成。

2. 所需的材料

1,51单片机开发板x1

2,杜邦线(公对公,母对母,公对母)

3,L298N驱动模块

4,电池一枚,以作为电源(需要大于6v)

5,HC-05蓝牙模块

6,蓝牙小车底盘一个

7,面包板一个

8, 红外避障模块 * 4

9, 超声波模块(HC-SR04) * 1

10,stc89c516RD+(stc89c52不能够使用,定时器的个数不够)

3. 各个模块介绍

L298n

  1. 将左右马达分别接在A,B口,顺序无所谓,可以通过代码来调试。

  1. 将电源正极接到12v处,电源的负极街道GND,在引出5v为单片机供电。

  1. 5v输出使能的跳线帽一定要接上,A,B通道的使能与单片机连接(用于PWM)

红外避障模块

  1. 因为该模块对环境光有一定的感应能力,所以在使用时,尽量不要在阳光和强光下使用。

  1. 其有一个发射管和一个接受管,当遇到障碍物时,输出指示灯会亮起,并且输出接口输出低电平。

  1. 该模块检查距离为2~30cm,角度为35°,可以通过调节电位器来调节检测距离。

HC-05蓝牙模块

六个引脚,我们这里主要用其中的四个(GND,5V,RT,TX),其中RT,TX与单片机输入输出口反接,

我们主要是通过串口通信来实现信号的传递。

超声波模块(HC-R04)

该模块我们主要用于跟随模式,其采用Trig引脚触发,给至少10us的高电平脉冲信号

模块自动发送8个40kHz的方波,自动检测是否有信号返回

有信号返回,通过Echo引脚输出一个高电平脉冲,高电平脉冲持续的时间就是超声波从发射到反射返回的时间。距离=(高电平脉冲时间*340)/2

4. 蓝牙APP的开发

这里使用的是App Inventor进行开发,其主要原理是让手机向蓝牙模块发送一个单字节的数,单片机在通过这个信号进行相应的操作。

界面开发

这里要记得添加蓝牙客户端

逻辑开发

初始化

这一部分是比较通用的,大家可以直接抄写。

按钮的逻辑

这里要注意传输的信号与单片机程序里做出的反应要对应。

5. 代码

电机转动

这里主要是控制电机的的正反转和停止来实现小车的前进,后退,停止和左右转。

car.c

#include <REGX52.H>

sbit IN1 = P1^3;
sbit IN2 = P1^2;
sbit IN3 = P1^1;
sbit IN4 = P1^0;


void car_left_motor_forward()  //左电机向前
{
    IN3=0;
    IN4=1;
}
void car_left_motor_back()  //左电机向后
{
    IN3=1;
    IN4=0;
}
void car_right_motor_forward()  //右电机向前
{
    IN1=1;
    IN2=0;
}
void car_right_motor_back()  //右电机向后
{
    IN1=0;
    IN2=1;
}
void car_right_motor_stop()  //右电机停止
{
    IN1=1;
    IN2=1;
}

void car_left_motor_stop()  //左电机停止
{
    IN4=1;
    IN3=1;
}

car.h

#ifndef __CAR_H__
#define __CAR_H__

void car_left_motor_forward();      //左电机向前
void car_left_motor_back();         //左电机向后
void car_right_motor_forward();     //右电机向前
void car_right_motor_back();        //右电机向后
void car_right_motor_stop();        //右电机停止
void car_left_motor_stop();         //左电机停止
#endif

move.c

#include <REGX52.H>
#include "car.h"
void move_go()                      //前进
{
    car_left_motor_forward();      //左电机向前
    car_right_motor_forward();     //右电机向前
}


void move_back()                      //前退
{
    car_left_motor_back();      //左电机向后
    car_right_motor_back();     //右电机向后
}



void move_left()                      //左转
{
    car_left_motor_stop();          //左电机停止
    car_right_motor_forward();     //右电机向前
}


void move_right()                      //右转
{
    car_left_motor_forward();      //左电机向前
    car_right_motor_stop();     //右电机停止
}
void move_stop()
{
    car_right_motor_stop();     //右电机停止
    car_left_motor_stop();          //左电机停止
}
void move_back_left()                      //左转
{
    car_left_motor_stop();          //左电机停止
    car_right_motor_back();     //右电机向前
}
c

void move_back_right()                      //右转
{
    car_left_motor_back();      //左电机向前
    car_right_motor_stop();     //右电机停止
}

move.h

#ifndef __MOVE_H__
#define __MOVE_H__

void move_go() ;                     //前进
void move_back();                      //后退
void move_left();                      //左转
void move_right();                      //右转
void move_stop();
void move_back_left();                      //左转
void move_back_right();                     //左转
#endifc

PWM调速

PWM调速主要使用到的是定时器0,通过控制L298N上ENL和ENR两对使能引脚,对电机进行控制。

timer_PWM.c

#include <REGX52.H>

sbit ENL1 = P1^4;
sbit ENL2 = P1^5;
sbit ENR1 = P1^7;
sbit ENR2 = P1^6;
int count = 0;
int speed_left = 0;
int speed_right = 0;
void Timer0Init(void)		//定时器0初始化,100微秒@11.0592MHz
{
			
		
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xAE;		//设置定时初始值
	TH0 = 0xFB;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
    ET0=1;
    EA=1;
}
void time() interrupt 1
{
    
    TL0 = 0xAE;		//设置定时初始值
	TH0 = 0xFB;		//设置定时初始值
    count++;
    count%=100;
    if(count>=speed_left)
    {
        ENL1 = 0;
        ENL2 = 0;
    }
    else
    {
        ENL1 = 1;
        ENL2 = 1;
    }
    if(count>=speed_right)
    {
        ENR1 = 0;
        ENR2 = 0;
    }
    else
    {
        ENR1 = 1;
        ENR2 = 1;
    }
    
}

###timer_PWM.h

#ifndef __TIMER_PWM_H__
#define __TIMER_PWM_H__
extern int count;
extern int speed_left;
extern int speed_right;


void Timer0Init(void);		//定时器0初始化,100微秒@11.0592MHz
void time(); 

#endif

蓝牙模块

  1. 模式的转换,主要是通过pattern变量的值来判断,其为1时表示为蓝牙避障模式,其为2时为超声波跟随模式。

  1. 蓝牙主要使用的是串口通信,我们要先对串口进行初始化,在通过SBUF接收到值进行响应。

bluetooth.c

#include <REGX52.H>
#include "move.h"
#include "timer_PWM.h"
unsigned int key = 0;		//接受蓝牙数据
unsigned int pattern = 0;   //模式选择
unsigned int launch = 0;	//跟随停止和开始
void bluetooth_UartInit()		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
    ES=1;
    EA=1;
}
void bluetooth_move_take(unsigned int key)
{
    switch(key)
    {
        case 1:if(pattern == 1){move_go();} break;        //前进
        case 2:if(pattern == 1){move_back();} break;      //后退    
        case 3:if(pattern == 1){move_left();}break;       //左转    
        case 4:if(pattern == 1){move_stop(); }break;      //停止
        case 5:if(pattern == 1){move_right(); }break;     //右转
		
        case 6:speed_left = 50;speed_right = 50;break;  //速度1
        case 7:speed_left = 100;speed_right = 100;break;//速度2  
		
		case 8:move_stop();pattern = 1; break;			//蓝牙避障模式
		case 9:launch = 0;move_stop();pattern = 2; break;		//超声波跟随模式	
		
		case 10:if(pattern == 2){launch = 1;move_stop();}break;						//开始跟随
		case 11:if(pattern == 2){launch = 0;move_stop();} break;						//停止跟随
    }
}
void bluetooth_uart_pass() interrupt 4
{
    
    if(RI==1)
    {
        key = SBUF;
        if(key <= 5)
        {
            move_stop();
        }
		
        bluetooth_move_take(key);
        
            
            
        RI = 0;
    }
    
}

bluetooth.h

#ifndef __BLUETOOTH_H__
#define __BLUETOOTH_H__

void bluetooth_UartInit();
void bluetooth_move_take(unsigned int key);
void bluetooth_uart_pass();
extern unsigned int key;
extern unsigned int pattern;
extern unsigned int launch;
#endif

红外避障

红外模块四个角各一个,当前面遇到障碍时,小车后退并停止,当后面遇到障碍时,小车向前行驶并停止。

sbit PIR1 = P0^0;
sbit PIR2 = P0^1;
sbit PIR3 = P0^2;
sbit PIR4 = P0^3;
void PIR_work()                 //红外避障模块
{
    if(PIR1 == 0 || PIR2 == 0)
        {
            move_stop();
            move_back();
            Delay(150);
            move_stop();
           
            
        }
        if(PIR3 == 0 || PIR4 == 0)
        {
            move_stop();
            move_go();
            Delay(150);
            move_stop();
            
        }
}

超声波模块

该模块使用的是定时器2,但其只用于计时,不触发中断。

当Echo接受到高电平时,定时器开启,高电平结束,定时器关闭。

UT.C

#include <REGX52.H>
#include <INTRINS.H>
sbit Trig = P2^1;
sbit Echo = P2^0;
void Delay50ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 90;
	j = 163;
	do
	{
		while (--j);
	} while (--i);
}

void Delay15us()		//@11.0592MHz
{
	unsigned char i;

	i = 4;
	while (--i);
}


void Timer2_Init(void)        
{
    T2MOD = 0;    //初始化模式寄存器
    T2CON = 0;    //初始化控制寄存器
    TL2 = 0x00;    //设置定时初值
    TH2 = 0x00;    //设置定时初值
    TR2 = 0;        //定时器2关闭计时
}
int judge(float cm , float number)
{
	float n = cm - number;
	if(n <= 3 && n >= -3)     
	{
		return 1;          //停止   
	}else if(n < -3)
	{
		return 2;			//后退   
	}else if(n > 3)
	{
		return 3;			//前进    
	}
	return 1;
}
void Delay25ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 45;
	j = 208;
	do
	{
		while (--j);
	} while (--i);
}

int UT_work()
{
	
	float number = 8;
	float s = 0;
	float cm = 0;
	int n = 0;
	Trig = 0;
	Echo = 0;
	
	
	Trig = 1;
	Delay15us();
	Trig = 0;		
	while(!Echo);	
	
	TR2 = 1;	
	while(Echo);
	TR2 = 0;			//关闭计时器
	s = (float)((TH2 * 256 + TL2) * 0.000001);
	cm = s * 340 / 2 * 100;		
	n =judge(cm , number);		
	cm = 0;
	s = 0;		
	TH2 = 0x00;
	TL2 = 0x00;			//清除定时器数值
	Delay25ms();
	return n;

	
		
		
	
	
}

// 

UT.H

#ifndef __UT_H__
#define __UT_H__
void Timer2_Init(void);
int judge(float cm , float number);
int UT_work();
#endif

跟随模式的红外转弯

该模式下,主要使用PIR1和PIR2前面两个红外避障模块。

PIR1和PIR2全部输出低电平或高电平时,则继续保持原来的运动。

PIR1为低电平时,PIR为高电平时,说明跟随物在小车左端,小车左转。

PIR1为高电平时,PIR为低电平时,说明跟随物在小车右端,小车右转。

sbit PIR1 = P0^0;
sbit PIR2 = P0^1;
void PIR_turn()			//红外拐弯
{
	if(PIR1 == 0 && PIR2 == 1)  //右拐
	{
		move_left();
		
		
	}
	if(PIR1 == 1 && PIR2 == 0)  //左拐
	{
		move_right();		
	}
	
	
}

延迟函数

Delay.c

#include <intrins.h>
#include <REGX52.H>


void Delay(unsigned int a)		//@11.0592MHz
{
	unsigned char i, j;
	while(a--)
	{
			_nop_();
			i = 2;
			j = 199;
			do
			{
				while (--j);
			} while (--i);
	}	
}
void Delay10us()		//@11.0592MHz
{
	unsigned char i;
	i = 2;
	while (--i);
}

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int a);
void Delay10us();
#endif

main.c

#include <REGX52.H>
#include "car.h"
#include "move.h"
#include "DELAY.H"
#include "TIMER_PWM.H"
#include "bluetooth.h"

sbit PIR1 = P0^0;
sbit PIR2 = P0^1;
sbit PIR3 = P0^2;
sbit PIR4 = P0^3;
void PIR_work()                 //红外避障模块
{
    if(PIR1 == 0 || PIR2 == 0)
        {
            move_stop();
            move_back();
            Delay(150);
            move_stop();
           
            
        }
        if(PIR3 == 0 || PIR4 == 0)
        {
            move_stop();
            move_go();
            Delay(150);
            move_stop();
            
        }
}
void PIR_turn()			//红外拐弯
{
	if(PIR1 == 0 && PIR2 == 1)  //右拐
	{
		move_left();
		
		
	}
	if(PIR1 == 1 && PIR2 == 0)  //左拐
	{
		move_right();		
	}
	
	
}

void main()
{
    int n = 0;
	Timer0Init();
    bluetooth_UartInit();
	
	Timer2_Init();
    speed_left=50;
    speed_right=50;
	
    while(1)
    {
        if(pattern == 1)
		{
			PIR_work();
		}
		if(pattern == 2)
		{
			
			if(launch)
			{
				PIR_turn();
				n = UT_work();
					
				switch(n)
				{
					case 1:move_stop();break;
					case 2:move_back();break;
					case 3:move_go();break;
				}
			}
		}
		

               
    }
}

6. 成品展示

外观

物联沃分享整理
物联沃-IOTWORD物联网 » 基于51单片机的双模式蓝牙跟随智能小车设计详解

发表评论