基于STM32的三路超声波自动跟随小车

三路超声波自动跟随小车

我个人一直都觉得自动跟随小车很酷,所以我的单片机课设就决定做这个了。其实现在网上有这个的代码不多,反正我怎么找也找不到,当时还没学完STM32的时候觉得好难实现,接近期末的时候终于搞出来了,虽然不是很理想,但还是不错滴,看一下效果。
在这里插入图片描述
这个是只有超声波传感器的,看上去有点简约,可以实现基本的自动跟随功能了

在这里插入图片描述
这个是接了火焰传感器、烟雾传感器、蜂鸣器、红外避障模块等等,看上去酷多了。

小车的系统结构图

在这里插入图片描述

代码部分

超声波初始化函数:

可能因为板子的端口有冲突,没有把三个超声波的引脚定义到同一组GPIO口上,但是这并不影响。

void CH_SR04_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructer;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer;

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

	/*TRIG触发信号*/
	GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructer.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_6;
	GPIO_Init(GPIOB, &GPIO_InitStructer);

	/*ECOH回响信号*/
	GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStructer.GPIO_Pin=GPIO_Pin_9 |GPIO_Pin_7;
	GPIO_Init(GPIOB, &GPIO_InitStructer);
	
	

	/*定时器TIM2初始化*/
	TIM_DeInit(TIM4);
	TIM_TimeBaseInitStructer.TIM_Period=999;//定时周期为1000
	TIM_TimeBaseInitStructer.TIM_Prescaler=71; //分频系数72
	TIM_TimeBaseInitStructer.TIM_ClockDivision=TIM_CKD_DIV1;//不分频
	TIM_TimeBaseInitStructer.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructer);

	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);//开启更新中断
	NVIC_Config();
	TIM_Cmd(TIM4,DISABLE);//关闭定时器使能

}

我把右边的超声波分开定义了,你也可以自己修改。

void right(void){    //右边超声波的引脚声明
	GPIO_InitTypeDef GPIO_InitStructer;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	/*TRIG触发信号*/
	GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructer.GPIO_Pin=GPIO_Pin_3;
	GPIO_Init(GPIOA, &GPIO_InitStructer);

	/*ECOH回响信号*/
	GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStructer.GPIO_Pin=GPIO_Pin_4;
	GPIO_Init(GPIOA, &GPIO_InitStructer);	

}

下面这部分就是超声波工作的过程了,也是核心代码。注释也解释得很清楚了,需要注意的是这里的超声波是测量了五次才返回一个值的,这样做的好处是起到一个滤波的作用,使得超声波的值更精确、稳定。但是他也有不好的地方,在小车前进过程可能会识别很慢或者转向失败,因为三个超声波是使用同一个定时器的,分时复用的,也就是同一时刻只能有一个超声波工作,所以如果处理器不够快的话可以把次数降低一点,我就是值检测一次的,效果也还行。左右超声波的函数也是一样的,把函数名改一下就好了。

//中间超声波的工作过程
float Senor_Using(void)
{
	float length=0,sum=0;
	u16 tim;
	uint i=0;
	/*测5次数据计算一次平均值*/
	while(i!=5)
	{
		PBout(8)=1; //拉高信号,作为触发信号
		delay_us(25); //高电平信号超过10us
		PBout(8)=0;
		/*等待回响信号*/
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==RESET);
		TIM_Cmd(TIM4,ENABLE);//回响信号到来,开启定时器计数

		i+=5; //每收到一次回响信号+1,收到5次就计算均值
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==SET);//回响信号消失
		TIM_Cmd(TIM4,DISABLE);//关闭定时器

		tim=TIM_GetCounter(TIM4);//获取计TIM4数寄存器中的计数值,一边计算回响信号时间

		length=(tim+overcount*1000)/58.0;//通过回响信号计算距离

		sum=length+sum;
		TIM4->CNT=0; //将TIM4计数寄存器的计数值清零
		overcount=0; //中断溢出次数清零
		delay_ms(10);
	}
	length=sum/5;
	return length;//距离作为函数返回值
}

这个是定时器的中断服务函数,避免因为距离过长,定时器中的值溢出。

void TIM4_IRQHandler(void) //中断,当回响信号很长是,计数值溢出后重复计数,用中断来保存溢出次数
{
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET)
	 {
		TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//清除中断标志
		overcount++;
	 }
}

PWM电机驱动代码:

#include "moter.h"
void CarGo(void)
{
	TIM_SetCompare1(TIM3 , 300);  //数值越大速度越慢
	TIM_SetCompare2(TIM3 , 900);
	TIM_SetCompare3(TIM3 , 300);  
	TIM_SetCompare4(TIM3 , 900);	
}

void CarStop(void)
{
    TIM_SetCompare1(TIM3 , 900);
    TIM_SetCompare2(TIM3 , 900);
	TIM_SetCompare3(TIM3 , 900);	
	TIM_SetCompare4(TIM3 , 900);
}

void CarBack(void)
{
    TIM_SetCompare1(TIM3 , 900);
    TIM_SetCompare2(TIM3 , 400);
	TIM_SetCompare3(TIM3 , 900);	
	TIM_SetCompare4(TIM3 , 400);
}

void CarLeft(void)
{
    TIM_SetCompare1(TIM3 , 900);
	TIM_SetCompare2(TIM3 , 200);
	TIM_SetCompare3(TIM3 , 200);
	TIM_SetCompare4(TIM3 , 900);
}

void CarBigLeft(void)
{
    TIM_SetCompare1(TIM3 , 900);
	TIM_SetCompare2(TIM3 , 100);
	TIM_SetCompare3(TIM3 , 100);
	TIM_SetCompare4(TIM3 , 900);
}

void CarRight(void)
{
    TIM_SetCompare1(TIM3 , 200);
	TIM_SetCompare2(TIM3 , 900);
	TIM_SetCompare3(TIM3 , 900);
	TIM_SetCompare4(TIM3 , 200);
	
}

void CarBigRight(void)
{
    TIM_SetCompare1(TIM3 , 100);
	TIM_SetCompare2(TIM3 , 900);
	TIM_SetCompare3(TIM3 , 900);
	TIM_SetCompare4(TIM3 , 100);
	
}


void TIM3_PWM_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure; 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
	
	
	TIM_TimeBaseStructure.TIM_Period = 899;
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseInit(TIM3 , &TIM_TimeBaseStructure);
	
	//端口复用
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 	
	GPIO_Init(GPIOA, &GPIO_InitStructure);   
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 	
	GPIO_Init(GPIOB, &GPIO_InitStructure);   
	
	//PWM通道1
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_Pulse = 900;
	TIM_OC1Init(TIM3 , &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM3 , TIM_OCPreload_Enable);
	
	//PWM通道2
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_Pulse = 900;
	TIM_OC2Init(TIM3 , &TIM_OCInitStructure);
	TIM_OC2PreloadConfig(TIM3 , TIM_OCPreload_Enable);
	
	//PWM通道3
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_Pulse = 900;
	TIM_OC3Init(TIM3 , &TIM_OCInitStructure);
	TIM_OC3PreloadConfig(TIM3 , TIM_OCPreload_Enable);
	
	//PWM通道4
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_Pulse = 900;
	TIM_OC4Init(TIM3 , &TIM_OCInitStructure);
	TIM_OC4PreloadConfig(TIM3 , TIM_OCPreload_Enable);
	
	TIM_Cmd(TIM3 , ENABLE);
}

主函数

while(1)
	{	
		length_res[0]=Senor_Using();
		delay_ms(100);
		if(length_res[0]>100.00)
		{
			CarGo();
		}
		if(length_res[0]<=40.00)
		{
			CarBack();//先后退一段距离
			delay_ms(200);
			CarBack();//先后退一段距离
			delay_ms(200);		

			length_res[0] =Senor_Using();//再次测量前方距离
			delay_ms(50);
			length_res[1]=Senor_Using_left();
			delay_ms(10);
			if(length_res[1]<=110.00&&length_res[0]>150.00)
			{			
					CarLeft();
					delay_ms(10);
								
			}
		
			length_res[2]=Senor_right();
			if(length_res[2]<=110.00&&length_res[0]>150.00)
			{
				CarRight();
				delay_ms(10);
							
			}			
		}
			
		length_res[1]=Senor_Using_left();
		delay_ms(10);
		if(length_res[1]<=110.00&&length_res[0]>150.00)
		{			
				CarLeft();
				delay_ms(50);
				CarLeft();
				delay_ms(50);
				if(length_res[1]<=30){
					CarRight();
					delay_ms(50);
				}
		}
		
		
		length_res[2]=Senor_right();
		if(length_res[2]<=110.00&&length_res[0]>150.00)
		{
			CarRight();
			delay_ms(50);
			CarRight();
			delay_ms(50);
				
			if(length_res[2]<=30){
					CarLeft();
					delay_ms(50);
				}
		}	
	}	

完成的工程代码已上传,有积分的土豪可以直接下载,链接:工程代码点这里

  • 15
    点赞
  • 238
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值