基于stm32f103vc的智能小车——超声波避障部分

智能小车的超声波避障实现过程

在硬件综合训练这门课程中,我们以小组的形式完成了基于stm32f103vc的智能小车的制作,实现的主要功能有:遥控、避障、语音控制、人脸识别以及舵机控制摄像头旋转。其中我主要负责的是stm32板的开发,以下是超声波避障的实现过程。

  1. 超声波模块的介绍
    我们所用的是HC-SR04超声波测距模块,它可以测量 3cm – 4m 的距离,精确度可以达到 3mm。
    基于stm32f103vc的智能小车——超声波避障部分_第1张图片
  2. 超声波模块的工作原理
    (1)采用IO口TRIG触发测距,给至少10us的高电平信号;
    (2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
    (3)有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速/2;
    (4)本模块使用方法简单,一个控制口发一个10US以上的高电平,就可以在接收口等待高电平输出。一有输出就可以开定时器计时,当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离。如此不断的周期测,即可以达到你移动测量的值。
  3. 超声波模块电路图
    基于stm32f103vc的智能小车——超声波避障部分_第2张图片
  4. 超声波模块时序图
    基于stm32f103vc的智能小车——超声波避障部分_第3张图片
  5. 超声波模块实现代码
    时钟与GPIO初始化:
void iniTim()
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
 	TIM_TimeBaseInitStructer.TIM_Period=9999;// 定时周期 .1s 100ms overflow
 	TIM_TimeBaseInitStructer.TIM_Prescaler=71;  // 72 000 000 1mhz 1us
 	TIM_TimeBaseInitStructer.TIM_ClockDivision=0; 
 	TIM_TimeBaseInitStructer.TIM_CounterMode=TIM_CounterMode_Up;
 	TIM_TimeBaseInitStructer.TIM_RepetitionCounter = 0;
 	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructer);

	TIM_Cmd(TIM2,ENABLE);
 	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
 
 	NVIC_InitTypeDef NVIC_InitStructure;
 	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
 	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
 	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
 	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	 NVIC_Init(&NVIC_InitStructure);
 
 	TIM_Cmd(TIM2,DISABLE);// 关闭定时器使能

	GPIO_InitTypeDef GPIO_InitStructure;
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
	 /*TRIG 信号 */
 	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
 	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
 	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	 /*ECOH 信号 */
	 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
 	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
 
 	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
 	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
 	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
 	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
 	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
 
 	GPIO_ResetBits(GPIOB,GPIO_Pin_9);//关闭距离过远led
}

测距函数:

double get_length(void)
{
 	GPIO_SetBits(GPIOB,GPIO_Pin_8);
 	 Delay_us(11);
  	GPIO_ResetBits(GPIOB,GPIO_Pin_8);
 	 while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6) == RESET);
   	TIM2->CNT = 0;//清零计时器
  	TIM_Cmd(TIM2,ENABLE);// 回响信号到来,开启定时器计数
  	while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==SET);
  	TIM_Cmd(TIM2,DISABLE);// 关闭定时器
  
 	if(!toofar) //没有完成一次计数周期,即距离不是很远 
  	{
   		t=TIM_GetCounter(TIM2);// 获取 TIM2 寄存器中的计数值
   		time = (double)t/(double)1000000; //往返时间,单位s 
   		length =  340*time/2; //单程长度,单位m 
   		TIM2->CNT=0; // 将 TIM2 计数寄存器的计数值清零
  	}
  	else
 	{
   		toofar = 0; 
   		length =99; //足够远,不用考虑 
   		TIM2->CNT=0; // 将 TIM2 计数寄存器的计数值清零
  	}
 	return length;
}

设置中断:

void TIM2_IRQHandler(void) // 中断,当距离足够远时,设置toofar = 1,不必再计算 
{
 	if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
   	{
   		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);// 清除中断标志
   		toofar = 1;
   		GPIO_ResetBits(GPIOB,GPIO_Pin_9);
   	}
}

主函数:

int main(void) 
{
 	SysTick_Init();
 	iniTim();
 	while(1) 
 	{
 		double len = 0;
  		len = get_length();
  		if ( len < 0.5 ) //如果距离够近
  		{
  			GPIO_SetBits(GPIOB,GPIO_Pin_7);//点亮距离过近led
   			GPIO_ResetBits(GPIOB,GPIO_Pin_9);//复位距离过远led
  		}
  		else 
   		{
   			if(toofar)//距离长到tim溢出,> 17m
   			{
    				GPIO_SetBits(GPIOB,GPIO_Pin_9);//点亮距离过远led
    				GPIO_ResetBits(GPIOB,GPIO_Pin_7);//复位距离过近led
   			}
   			else
   			{
     				GPIO_ResetBits(GPIOB,GPIO_Pin_7);//复位距离过近led
    				GPIO_ResetBits(GPIOB,GPIO_Pin_7);//复位距离过近led
    			}
  		}  
 	}
}

注:我添加了两个led灯来判断超声波测距功能的实现,其中
PB7引脚上连接的是距离过近led,如果近距离内出现障碍,它会亮起;
PB9引脚上连接的是距离过远led,如果在很远的距离范围里都没有障碍,它会亮起。

你可能感兴趣的:(硬件综合训练)