欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

新手入门单片机实战超详细以及遇到一些坑-避障小车2【更新中】

程序员文章站 2022-05-22 09:06:03
...

咳咳,先提两句

上一篇介绍自己做单片机简单介绍了购买工具和元器件以及测试电机。(其实我也知道太low了,啥也不是,别骂了别骂了我知道我菜),然后经过那天之后对方案进行了一些调整,基本实现了避障和遥控,有必要说明一下方便大家避开我掉进去的一些坑。

方案调整

1.电机
开始着手做之前也是考虑了很多方案。包括电机驱动部分,在请教我认识的一些带佬时候,都是建议用一个电机驱动模块节省资源还能基本达到要求,我理解为只需要前驱或者后驱就行。(博主采用的是后驱,前面两个*直接处于空闲状态没有接线)实际也能跑,只是车后端扛了一个充电宝,车身晃动严重,虽然后来车前端塞一个钳子后效果好点,但是物理消抖的方法属实拉跨。
给大家提供一种改良后的方案,同时对电机状态控制运动状态原理做出了解释,效果也好多了。
新手入门单片机实战超详细以及遇到一些坑-避障小车2【更新中】
新手入门单片机实战超详细以及遇到一些坑-避障小车2【更新中】
2.传感器
博主买元件时候也是图便宜就顺便买了两个避障传感器(基于红外的),一个一两块还简单,那还要啥自行车。果断入手,结果就是白给了。因为红外受环境因素影响较大,光线一强容易触发,而且碰到透明物体容易变傻。后来改用超声波传感器,现在主流的智能小车方案避障模块通常都采用超声波。

超声波模块原理:
新手入门单片机实战超详细以及遇到一些坑-避障小车2【更新中】

3.PWM调速
直接控制输入确定电机正反转启停也能达到效果,但是也存在调试不方便全速输出功耗过大等问题。
原理就是开关管在一个周期内的导通时间为t,周期为T, 则电机两端的平均电压 U=Vcc*(t/T)=aVcc。 其中,a=t/T(占空比),Vcc 是电源电压, 电机的转速与电机两端的电压成正比例, 而电机两端的电压与控制波形的占空比成正比, 因此电机的速度与占空比成比例,占空比越大,电机转的越快。
有想进一步改进的可以加瓷片电容或者光耦隔离稳定电机减小干扰。
PWM调速博主是通过两路输出的使能端通过定时器控制取0置1实现的(ENA、ENB一开始用跳线帽拉高),属于比较简单的方案,也有不借助控制使能实现的,放在下面供大家参考。

http://www.51hei.com/bbs/dpj-161820-1.html

效果演示

新手入门单片机实战超详细以及遇到一些坑-避障小车2【更新中】
吐槽一下视频转GIF再压缩成小于5M的图片过程过于艰辛

避障小车代码

#include <reg52.h>
#include <intrins.h>
#include <stdio.h>

#define uint unsigned int
#define uchar unsigned char

sbit  left_s = P0^0;   //左侧红外传感器
sbit  right_s = P0^1;  //右侧红外传感器
sbit IN1 = P1^0;     
sbit IN2 = P1^1;
sbit ENA = P1^2;
sbit IN3 = P1^3;
sbit IN4 = P1^4;
sbit ENB = P1^5;
sbit Trig =P3^1;   //超声波模块输入信号
sbit Echo =P3^2;   //超声波模块传回信号

uchar speed_l=50;  
uchar speed_r=50;  //初始占空比
uchar t;
uint dis;

void Delayms(uint z);
void Delayus(uint time);
void Timer0Init();
void Timer1Init(void);
void StartInit();
int Count();
void straight();
void back();
void run();
void stop();
void turn_left();
void turn_right();

/*******************************************************/
//毫秒级延时函数
void Delayms(uint z)
{
	uint x,y;
	for(x = z; x > 0; x--)
		for(y = 120; y > 0 ; y--);
}

/*******************************************************/
//微秒级延时函数
void Delayus(uint time)
{
	while(time--);
}

/*******************************************************/
//定时器0初始化
void Timer0Init(void)		//100微秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x70;		//设置定时初值
	TH0 = 0xDD;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA  = 1;
	ET0 = 1;
}

/*******************************************************/
//定时器1初始化,用于超声波传感器计算距离
void Timer1Init(void)		
{
		TMOD &= 0x0F;		//设置定时器模式
		TMOD |= 0x10;		//设置定时器模式
		TL1 = 0x00;		//设置定时初值
		TH1 = 0x00;		//设置定时初值
		TF1 = 0;		//清除TF1标志
//	TR1 = 1;		//定时器1开始计时
}


/*******************************************************/
//超声波传感器启动
void StartInit()
{
	  Trig = 1;
	  Delayus(50);    //发出超声波
	  Trig = 0;
}

/*******************************************************/
//超声波传感器计算
int Count()
{
	  uint time,distance;
		time=TH1*256+TL1;  //计算接收返回超声波时间
	  TH1=0;
	  TL1=0;
	  distance=(time*1.7)/100;    //计算距离 
	  return distance;	       
}

/*******************************************************/
//超声波传感器得到距离
void Measure_dis()
{
	 StartInit();     //初始化
   while(!Echo);		//当RX为零时等待
   TR1=1;			    //开启计数
   while(Echo);		 //当RX为1计数并等待
   TR1=0;				//关闭计数
   dis=Count();
}

/*******************************************************/
//控制函数
void straight()
{
	  IN1 = 1;
	  IN2 = 0;
	  IN3 = 1;
	  IN4 = 0;   //由电机连接情况测试此时向前
}

void back()
{
	  IN1 = 0;
	  IN2 = 1;
	  IN3 = 0;
	  IN4 = 1;   //由电机连接情况测试此时向后
}

void run()
{
	  speed_l = 50;
	  speed_r = 50;
}

void stop()
{
	   ET0 = 0;      //关闭定时器,停止产生PWM
	   ENA = 0;       
	   ENB = 0;       //启停后重新启动需要重新配置定时器
}

void turn_left()
{
	  speed_l = 40;
	  speed_r = 0;
}

void turn_right()
{
	  speed_l = 0;
	  speed_r = 40;
}

void main()
{
	  Timer1Init();	
		Timer0Init();
	  straight();
	  while(1)
		{
			 Measure_dis();
			if(dis>40)
			{
				  straight();
					run();
			}
			else if(dis<40&&dis>20)
			{ 
				  straight();
				  run();
				  Delayms(10);
				  turn_right();
				  Delayms(500);
			}
			else
			{
					stop();
				  back();
				  ET0 = 1;
				  run();
				  Delayms(500);
				  straight();
					turn_right();
				  Delayms(500);
			}
		}
}

/* 通过控制左右的使能实现PWM调速  */
void Timer0_isr() interrupt 1 
{
		TL0 = 0x70;		//设置定时初值
		TH0 = 0xDD;		//设置定时初值
    if(t < speed_l )
		{
			 ENA = 1;
		}
		else
		{
			 ENA = 0;
		}
		if(t < speed_r)
		{
			 ENB = 1;
		}
		else
		{
			 ENB = 0;
		}
		t++;
		if(t >= 100)
		{
			 t = 0;
		}		
}
	

> 参考文章:

https://blog.csdn.net/Horizonhui/article/details/78319953?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-12.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-12.nonecase
https://zhuanlan.zhihu.com/p/27734663
https://blog.csdn.net/Darren_Wonn/article/details/86555741?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-7.nonecase

相关标签: 单片机