【STM32F130RCT6】超声波测距模块思路和代码

目录

【硬件说明】

【理论说明】

【软件设计】

定时器初始化

超声波测距函数

定时器中断函数

主函数


【硬件说明】

        STM32F103内核开发板,超声波模块HC-SR04

 图1 HC-SR04超声波模块实物图

【理论说明】

过程中使用的超声波模块是HC-SR04模块。有四个引脚,分别是Echo、Trig、VCC、GND。Trig触发端:是为了触发超声波测距工作的引脚;Echo接收信号端:超声波返回到单片机一个高电平,而我们就是通过高电平持续的时间计算距离。

超声波原理:(1)采用 IO 触发测距,至少给 10us 的高电平信号;(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;(3)有信号返回,通过 IO 输出一高电平,高电平持续的时间就是超声波从发射到返回的时间。

测试距离 = ( 高电平时间 * 声速(340 M/S ) ) / 2

  图2 HC-SR04超声波时序图

【软件设计】

定时器初始化

本次使用TIM3、TIM5来负责超声波模块的数据采集。在程序进入while循环之前,需要对TIM3、TIM5进行初始化,由于两个定时器的配置都大同小异,所以只展示一个。

/**************************************************************************
函数功能:定时器5通道输入捕获初始化
入口参数:入口参数:arr:自动重装值  psc:时钟预分频数 
返回  值:无
**************************************************************************/
void TIM5_Cap_Init(u16 arr, u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);												            
    //使能TIM5时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |           
    RCC_APB2Periph_GPIOC, ENABLE); //使能GPIO时钟
   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA  输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; //2M
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; //2M
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; //2M
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	//初始化定时器5
	TIM_TimeBaseStructure.TIM_Period = arr;					//设定计数器自动重装值
	TIM_TimeBaseStructure.TIM_Prescaler = psc;				//预分频器
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;	//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);	//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

	//初始化TIM5输入捕获参数
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;			//选择输入端
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
	TIM_ICInitStructure.TIM_ICFilter = 0x00;			  //配置输入滤波器 不滤波
	TIM_ICInit(TIM5, &TIM_ICInitStructure);

	//初始化TIM5输入捕获参数
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;			//选择输入端
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
	TIM_ICInitStructure.TIM_ICFilter = 0x00;			  //配置输入滤波器 不滤波
	TIM_ICInit(TIM5, &TIM_ICInitStructure);

	//初始化TIM5输入捕获参数
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;			//选择输入端
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
	TIM_ICInitStructure.TIM_ICFilter = 0x00;			  //配置输入滤波器 不滤波
	TIM_ICInit(TIM5, &TIM_ICInitStructure);

	//初始化TIM5输入捕获参数
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;			//选择输入端
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
	TIM_ICInitStructure.TIM_ICFilter = 0x00;			  //配置输入滤波器 不滤波
	TIM_ICInit(TIM5, &TIM_ICInitStructure);

	//中断分组初始化
	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;												                   
     //TIM中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;									      
    //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;											   
    //从优先级2级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;												   
    //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);																           
    //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
	TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE); //允许更新中断 ,允许捕获中断
	TIM_Cmd(TIM5, ENABLE);		//使能定时器														
}

超声波测距函数

这里程序只展示定时器5通道一

u16 TIM5CH1_CAPTURE_STA, TIM5CH1_CAPTURE_VAL, TIM5CH2_CAPTURE_STA, TIM5CH2_CAPTURE_VAL;
u16 TIM5CH3_CAPTURE_STA, TIM5CH3_CAPTURE_VAL, TIM5CH4_CAPTURE_STA, TIM5CH4_CAPTURE_VAL;
u16 TIM3CH1_CAPTURE_STA, TIM3CH1_CAPTURE_VAL, TIM3CH2_CAPTURE_STA, TIM3CH2_CAPTURE_VAL;
u16 TIM3CH3_CAPTURE_STA, TIM3CH3_CAPTURE_VAL, TIM3CH4_CAPTURE_STA, TIM3CH4_CAPTURE_VAL;
/**************************************************************************
函数功能:超声波接收回波函数
入口参数:无
返回  值:无
**************************************************************************/
void Read_Distane(void)
{
	TRIPA = 1;						//高电平触发
	delay_us(15);					//延时
	TRIPA = 0;						//低电平
	if (TIM5CH1_CAPTURE_STA & 0X80) //成功捕获到了一次高电平
	{
		Distance_A = TIM5CH1_CAPTURE_STA & 0X3F;
		Distance_A *= 65536;				  //溢出时间总和
		Distance_A += TIM5CH1_CAPTURE_VAL;	  //得到总的高电平时间
		Distance_A = Distance_A * 170 / 1000; //转化成mm为单位,依据声音在空气中传播速度340m/s
		TIM5CH1_CAPTURE_STA = 0;			  //开启下一次捕获
	}

	TRIPB = 1;						//高电平触发
	delay_us(15);					//延时
	TRIPB = 0;						//低电平
	if (TIM5CH2_CAPTURE_STA & 0X80) //成功捕获到了一次高电平
	{
		Distance_B = TIM5CH2_CAPTURE_STA & 0X3F;
		Distance_B *= 65536;				  //溢出时间总和
		Distance_B += TIM5CH2_CAPTURE_VAL;	  //得到总的高电平时间
		Distance_B = Distance_B * 170 / 1000; //转化成mm为单位,依据声音在空气中传播速度340m/s
		TIM5CH2_CAPTURE_STA = 0;			  //开启下一次捕获
	}

	TRIPC = 1;						//高电平触发
	delay_us(15);					//延时
	TRIPC = 0;						//低电平
	if (TIM5CH3_CAPTURE_STA & 0X80) //成功捕获到了一次高电平
	{
		Distance_C = TIM5CH3_CAPTURE_STA & 0X3F;
		Distance_C *= 65536;				  //溢出时间总和
		Distance_C += TIM5CH3_CAPTURE_VAL;	  //得到总的高电平时间
		Distance_C = Distance_C * 170 / 1000; //转化成mm为单位,依据声音在空气中传播速度340m/s
		TIM5CH3_CAPTURE_STA = 0;			  //开启下一次捕获
	}

	TRIPD = 1;						//高电平触发
	delay_us(15);					//延时
	TRIPD = 0;						//低电平
	if (TIM5CH4_CAPTURE_STA & 0X80) //成功捕获到了一次高电平
	{
		Distance_D = TIM5CH4_CAPTURE_STA & 0X3F;
		Distance_D *= 65536;				  //溢出时间总和
		Distance_D += TIM5CH4_CAPTURE_VAL;	  //得到总的高电平时间
		Distance_D = Distance_D * 170 / 1000; //转化成mm为单位,依据声音在空气中传播速度340m/s
		TIM5CH4_CAPTURE_STA = 0;			  //开启下一次捕获
	}
}

定时器中断函数

/**************************************************************************
函数功能:超声波回波脉宽读取中断
入口参数:无
返回  值:无
**************************************************************************/
void TIM5_IRQHandler(void)
{
	u16 tsr;
	tsr = TIM5->SR;
	/通道一///
	if ((TIM5CH1_CAPTURE_STA & 0X80) == 0) //还未成功捕获
	{
		if (tsr & 0X01) //溢出
		{
			if (TIM5CH1_CAPTURE_STA & 0X40) //已经捕获到高电平了
			{
				if ((TIM5CH1_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了
				{
					TIM5CH1_CAPTURE_STA |= 0X80; //标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL = 0XFFFF;
				}
				else
					TIM5CH1_CAPTURE_STA++;
			}
		}
		if (tsr & 0x02) //捕获1发生捕获事件
		{
			if (TIM5CH1_CAPTURE_STA & 0X40) //捕获到一个下降沿
			{
				TIM5CH1_CAPTURE_STA |= 0X80;	  //标记成功捕获到一次高电平脉宽
				TIM5CH1_CAPTURE_VAL = TIM5->CCR1; //获取当前的捕获值.
				TIM5->CCER &= ~(1 << 1);		  //CC1P=0 设置为上升沿捕获
			}
			else //还未开始,第一次捕获上升沿
			{
				TIM5CH1_CAPTURE_STA = 0; //清空
				TIM5CH1_CAPTURE_VAL = 0;
				TIM5CH1_CAPTURE_STA |= 0X40; //标记捕获到了上升沿
				TIM5->CNT = 0;				 //计数器清空
				TIM5->CCER |= 1 << 1;		 //CC1P=1 设置为下降沿捕获
			}
		}
	}
	/通道二///
	if ((TIM5CH2_CAPTURE_STA & 0X80) == 0) //还未成功捕获
	{
		if (tsr & 0X01) //溢出
		{
			if (TIM5CH2_CAPTURE_STA & 0X40) //已经捕获到高电平了
			{
				if ((TIM5CH2_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了
				{
					TIM5CH2_CAPTURE_STA |= 0X80; //标记成功捕获了一次
					TIM5CH2_CAPTURE_VAL = 0XFFFF;
				}
				else
					TIM5CH2_CAPTURE_STA++;
			}
		}
		if (tsr & 0x04) //捕获2发生捕获事件
		{
			if (TIM5CH2_CAPTURE_STA & 0X40) //捕获到一个下降沿
			{
				TIM5CH2_CAPTURE_STA |= 0X80;	  //标记成功捕获到一次高电平脉宽
				TIM5CH2_CAPTURE_VAL = TIM5->CCR2; //获取当前的捕获值.
				TIM5->CCER &= ~(1 << 5);		  //CC1P=0 设置为上升沿捕获
			}
			else //还未开始,第一次捕获上升沿
			{
				TIM5CH2_CAPTURE_STA = 0; //清空
				TIM5CH2_CAPTURE_VAL = 0;
				TIM5CH2_CAPTURE_STA |= 0X40; //标记捕获到了上升沿
				TIM5->CNT = 0;				 //计数器清空
				TIM5->CCER |= 1 << 5;		 //CC1P=1 设置为下降沿捕获
			}
		}
	}
	/通道三///
	if ((TIM5CH3_CAPTURE_STA & 0X80) == 0) //还未成功捕获
	{
		if (tsr & 0X01) //溢出
		{
			if (TIM5CH3_CAPTURE_STA & 0X40) //已经捕获到高电平了
			{
				if ((TIM5CH3_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了
				{
					TIM5CH3_CAPTURE_STA |= 0X80; //标记成功捕获了一次
					TIM5CH3_CAPTURE_VAL = 0XFFFF;
				}
				else
					TIM5CH3_CAPTURE_STA++;
			}
		}
		if (tsr & 0x08) //捕获3发生捕获事件
		{
			if (TIM5CH3_CAPTURE_STA & 0X40) //捕获到一个下降沿
			{
				TIM5CH3_CAPTURE_STA |= 0X80;	  //标记成功捕获到一次高电平脉宽
				TIM5CH3_CAPTURE_VAL = TIM5->CCR3; //获取当前的捕获值.
				TIM5->CCER &= ~(1 << 9);		  //CC1P=0 设置为上升沿捕获
			}
			else //还未开始,第一次捕获上升沿
			{
				TIM5CH3_CAPTURE_STA = 0; //清空
				TIM5CH3_CAPTURE_VAL = 0;
				TIM5CH3_CAPTURE_STA |= 0X40; //标记捕获到了上升沿
				TIM5->CNT = 0;				 //计数器清空
				TIM5->CCER |= 1 << 9;		 //CC1P=1 设置为下降沿捕获
			}
		}
	}
	/通道四///
	if ((TIM5CH4_CAPTURE_STA & 0X80) == 0) //还未成功捕获
	{
		if (tsr & 0X01) //溢出
		{
			if (TIM5CH4_CAPTURE_STA & 0X40) //已经捕获到高电平了
			{
				if ((TIM5CH4_CAPTURE_STA & 0X3F) == 0X3F) //高电平太长了
				{
					TIM5CH4_CAPTURE_STA |= 0X80; //标记成功捕获了一次
					TIM5CH4_CAPTURE_VAL = 0XFFFF;
				}
				else
					TIM5CH4_CAPTURE_STA++;
			}
		}
		if (tsr & 0x10) //捕获4发生捕获事件
		{
			if (TIM5CH4_CAPTURE_STA & 0X40) //捕获到一个下降沿
			{
				TIM5CH4_CAPTURE_STA |= 0X80;	  //标记成功捕获到一次高电平脉宽
				TIM5CH4_CAPTURE_VAL = TIM5->CCR4; //获取当前的捕获值.
				TIM5->CCER &= ~(1 << 13);		  //CC1P=0 设置为上升沿捕获
			}
			else //还未开始,第一次捕获上升沿
			{
				TIM5CH4_CAPTURE_STA = 0; //清空
				TIM5CH4_CAPTURE_VAL = 0;
				TIM5CH4_CAPTURE_STA |= 0X40; //标记捕获到了上升沿
				TIM5->CNT = 0;				 //计数器清空
				TIM5->CCER |= 1 << 13;		 //CC1P=1 设置为下降沿捕获
			}
		}
	}
	TIM5->SR = 0; //清除中断标志位
}

主函数

int main(void)
{
	delay_init();					//延时函数初始化
	MY_NVIC_PriorityGroupConfig(2); //设置中断分组
	JTAG_Set(SWD_ENABLE);			//打开SWD接口 可以利用主板的SWD接口调试

	QuDong_Init();					  //初始化驱动器驱动端口
	uart_init(115200);				  //串口1初始化
	CAN_Config();					  //初始化can,在中断接收CAN数据包*/
	MiniBalance_PWM_Init(3599, 0);	  //PWM频率最高 20K
	TIM2_Cap_Init(0XFFFF, 72 - 1);	  //定时器2 输入捕获 开启通道 TIM2_CH3 TIM2_CH4
	TIM6_Int_Init(100 - 1, 7200 - 1); //定时器6初始化 10ms中断
	TIM5_Cap_Init(0XFFFF, 72 - 1);	  //超声波始化 默认注释 超声波接线 参考timer.h文件
	TIM3_Cap_Init(0XFFFF, 72 - 1);	  //超声波始化 默认注释 超声波接线 参考timer.h文件

	printf("开始!\r\n");

	v_mc = (int)get_mc(0.2); //输入速度值 转化位对应的脉冲频率
	L = 6.0;

	/*** 硬件适配 ***/
	TIM_SetCompare1(TIM4, 0);
	TIM_SetCompare2(TIM4, 0);
	delay_ms(250);

	while (1)
	{
		TIM_SetCompare1(TIM4, sv_L);
		TIM_SetCompare2(TIM4, sv_R * 1.013);

		if (TIM2_CH3Structure.Capture_FinishFlag == 1)
		{
			printf("Frequency_L = %d Hz    ", TIM2_CH3Structure.value);
			printf("V_L = %f M/s\r\n", get_v(TIM2_CH3Structure.value));
			TIM2_CH3Structure.Capture_FinishFlag = 0;
		}
		if (TIM2_CH4Structure.Capture_FinishFlag == 1)
		{
			printf("Frequency_R = %d Hz    ", TIM2_CH4Structure.value);
			printf("V_R = %f M/s\r\n", get_v(TIM2_CH4Structure.value));
			TIM2_CH4Structure.Capture_FinishFlag = 0;
		}
		else
		{
			printf("Wave is not exist or Cature is incomplete.\n");
		}

		A = Distance_A; //y
		C = Distance_C; //*y
		D = Distance_D; //y
		c = Distance_c; //*y
		B = Distance_B; //*y
		a = Distance_a; //*n
		b = Distance_b; //y
		d = Distance_d; //y
		printf("距离前方:%d    ", b);
		printf("距离后方:%d    ", C);
		printf("距离左方:%d    ", B);
		printf("距离右方:%d\r\n", c);
		delay_ms(1000);
	}
}

void TIM6_IRQHandler(void) // TIM6 10ms中断
{

	if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) // 检查指定的TIM6中断发生与否
	{
		//超声波测距&避障
		Read_Distane();
		Read_Distane2();
		if (b < 600)
		{
			GPIO_ResetBits(GPIOC, GPIO_Pin_1 | GPIO_Pin_0); //置低刹车
		}
		else
		{
			GPIO_SetBits(GPIOC, GPIO_Pin_1 | GPIO_Pin_0);
			if (TIM2_CH3Structure.value <= v_mc)
			{
				sv_L = (int)(float)(Velocity_PI(TIM2_CH3Structure.value, v_mc) / -20000.0 * 3600.0);
			}
			if (TIM2_CH4Structure.value <= v_mc)
			{
				sv_R = (int)(float)(Velocity_PI(TIM2_CH4Structure.value, v_mc) / -20000.0 * 3600.0);
			}
		}
	}

	TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除TIM6的中断待处理位
}

到此,超声波模块的基本思路和程序已经罗列出来。

在下菜鸟,大家的鼓励是我继续创作的动力,如果觉得写的不错,欢迎关注,点赞,收藏,转发,谢谢!

  • 10
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会用魔法的叮当猫

蟹蟹٩('ω')و!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值