简单易上手 51蓝牙 PWM调速 避障 循迹小车(最强小车)

目录

一、前言

二、硬件

三、软件

四、手机端设置

五、总结


一、前言

基于前面的51小车模块,我增加了循迹模块,先给大家看看效果吧:

简单易上手 51蓝牙 PWM调速 避障 循迹小车(最强小车)_第1张图片

二、硬件

循迹模块

简单易上手 51蓝牙 PWM调速 避障 循迹小车(最强小车)_第2张图片

1.循迹模块三个IO,硬件原理,亮灯返回1,灭灯返回0,当检测到黑线时返回0,检测到白色时返回1,因此可以设置寻黑线设置

2.P16接左边循迹,P17接右边循迹

三、软件

完整代码可在本文末尾下载

main.c

#include 
#include "UART.h"
#include "Timer0.h"
#include "Nixie.h"
#include "Delay.h"

sbit IN1 = P1^0; // 左上
sbit IN2 = P1^1; // 左下
sbit IN3 = P1^2; // 右上
sbit IN4 = P1^3; // 右上
sbit ENA = P2^6; //使能A
sbit ENB = P2^7; //使能B

sbit out0 = P2^0; // 右边避障,有障碍物就亮,输出0
sbit out1 = P2^1; // 左边避障,有障碍物就亮,输出0

sbit outleft = P1^6; //左边循迹,亮灯返回值为1
sbit outright = P1^7; //右边循迹,检测到黑线灭灯,返回0

unsigned char PWM; //PWM波
unsigned char date;//输入缓冲区
static unsigned char speed = 100; //设置速度初始值

void stop() // 停
{
	IN1=0;
	IN2=0;
	IN3=0;
	IN4=0;
}

void forward() // 向前
{
	IN1=1;
	IN2=0;
	IN3=1;
	IN4=0;	  
}

void back() // 向后
{
	IN1=0;
	IN2=1;
	IN3=0;
	IN4=1;	
}

void left() // 向左,只有左轮动
{
	IN1=1;
	IN2=0;
	IN3=1;
	IN4=1;
}

void avoid_left()//向左,左右伦同时转动
{
	IN1=1;
	IN2=0;
	IN3=0;
	IN4=1;
}

void right() // 向右,只有右轮动
{
	IN1=1;
	IN2=1;
	IN3=1;
	IN4=0;
}

void avoid_right()//向左,左右伦同时转动
{
	IN1=0;
	IN2=1;
	IN3=1;
	IN4=0;
}

void increase(void)//加速
{
	speed += 5; // 每次增加5
	if(speed >= 100) // 上限是100
	{
		speed = 100;
	}
}
	
void reduce(void)//减速
{
	speed -= 5; // 每次减少5
	if(speed <= 0) // 下限是0
	{
		speed = 0;
	}
}

void avoid(void)//避障模式
{
	if(out0 == 0) // 右边有障碍物,左转
	{
		avoid_left();
	}
	if(out1 == 0) // 左边有障碍物,右转
	{
		avoid_right();
	}
	if(out0 == 1 && out1 == 1) // 没有障碍物,前进
	{
		 forward();
	}
	if(out0 == 0 && out1 == 0) // 有障碍物,停止
	{
		 stop();
	}
}

void Follow_the_trail (void)
{
	if(outleft == 0 && outright == 0)//悬空,停止移动
	{
		stop();
	}
	if(outleft == 1 && outright == 1) //在赛道上,直线行驶
	{
		forward();
	}
	if(outleft == 1 && outright == 0) //偏离赛道向右,因向左行驶
	{
		left();
	}
	if(outleft == 0 && outright == 1) //偏离赛道向左,因向右行驶
	{
		right();
	}
}

//串口中断
void Time_Int () interrupt 4
{
	if(RI == 1) // RI为1时软件置0
	{
		RI = 0; // 清除接受标志
		date = SBUF; // 接收数据缓存在date中
		switch (date)
		{
			case ('1'):
			{
				forward();
				break;
			}
			case ('2'):
			{
				back();
				break;
			}
			case ('3'):
			{
				left();
				break;
			}
			case ('4'):
			{
				right();
				break;
			}
			case ('0'):
			{
				stop();
				break;
			}
			case ('5'):
			{
				increase();
				break;
			}
			case ('6'):
			{
				reduce();
				break;
			}
		}
	}
}

//定时器0
void time_control() interrupt 1
	{
		TL0 = 0x66;		//设置定时初值
		TH0 = 0xFC;		//设置定时初值
		PWM++;
		if (PWM == 100)
		{
			PWM = 0;
		}
		if(PWM <= speed)//大于PWM波则打开使能
		{
			ENA = 1;
			ENB = 1;
		}
		if(PWM > speed)//小于PWM波则关闭使能
		{
			ENA = 0;
			ENB = 0;
		}
	}

void main ()
{
	UsartConfiguration(); // 串口初始化
	Timer0Init();//定时器0初始化
	while(1)
	{
		//在数码管可以看到当前的速度是多少
		Nixie(1, speed/100);
		Delay(5);
		Nixie(2, (speed/10)%10);
		Delay(5);
		Nixie(3, speed%10);
		Delay(5);
		//启动避障模式,将此模式存放在主函数当中
		if(date == '7')
		{
			avoid();
		}
		//启动循迹模式,将此模式存放在主函数当中
		if(date == '8')
		{
			Follow_the_trail();
		}
	}
}

UART.h(中断)

#ifndef __UART_H__
#define __UART_H__

void UsartConfiguration(void);
void UART_SendByte(unsigned char byte);

#endif

UART.c

#include 

/**
   * @brief  串口初始化,[email protected]
   * @param  无
   * @retval 无
   */

void UsartConfiguration(void)		//[email protected]
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	ES = 1;        //开启串口中断
    EA = 1; 		//开启总中断
}

/**
   * @brief  串口发送一个字节数据
   * @param  byte 是接收的数据
   * @retval 无
   */

void UART_SendByte(unsigned char byte)
{
	SBUF = byte;
	while (TI == 0);
	TI = 0;
}

Timer0.h(定时器0)

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0Init(void);

#endif

Timer0.c

#include 

/**
   * @brief  定时器0,1毫秒@11.0592MHz
   * @param  无
   * @retval 无
   */

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;		//定时器开关
	EA = 1;			//总开关
}



/*模板
	void time_control() interrupt 1
	{
		static unsigned int counst;//局部变量,静态变量,防止每次进入中断,都将counst置为0
		TL0 = 0x66;		//设置定时初值
		TH0 = 0xFC;		//设置定时初值
		counst++;
		if (counst == 1000)
		{
			counst = 0;
			
		}
	
	}
*/

Nixie.h(数码管)

#ifndef __NIXIE_H__
#define __NIXIE_H__

void Nixie(unsigned char Location,Number);

#endif

Nixie.c

#include 
#include "Delay.h"

//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

/**
  * @brief  数码管显示
  * @param  Location 要显示的位置,范围:1~8
  * @param  Number 要显示的数字,范围:段码表索引范围
  * @retval 无
  */
void Nixie(unsigned char Location,Number)
{
	switch(Location)		//位码输出
	{
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];	//段码输出
	Delay(1);				//显示一段时间
	P0=0x00;				//段码清0,消影
}

Delay.h(延时)

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif

Delay.c


/**
  * @brief  毫秒延时
  * @param  xms输入的毫秒
  * @retval 无
  */
void Delay(unsigned int xms)	//@11.0592MHz
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}




四、手机端设置

在开关设置:

简单易上手 51蓝牙 PWM调速 避障 循迹小车(最强小车)_第3张图片

五、总结

有待加强的地方:

1.本次循迹只使用了两个循迹模块,在精准度上还有待提升,间接限制了速度的提升

代码下载:

Txet: 记录代码 - Gitee.com

--------------------------------------------------------------------------------------------------------------------------

欢迎大家观看我的文章,希望对你有所帮助。

作者大一新生,一起加油努力丫~!

来个赞阿布~

你可能感兴趣的:(#,51单片机,#,51小车,嵌入式,单片机)