基于STM32的SR04超声波模块(基本库和HAL库)

关于HC-SR04超声波模块的一些事情

这里写目录标题

    • 关于HC-SR04超声波模块的一些事情
    • STM32(基本库)代码实现
    • STM32(Hal库)超声波模块的实现

基于STM32的SR04超声波模块(基本库和HAL库)_第1张图片

关于模块的一些内容可以在淘宝的购买界面能找到,因为模块比较简单,主要用到的内容是IO口输出方波,外部中断和定时器计时
基于STM32的SR04超声波模块(基本库和HAL库)_第2张图片
我买的超声波就4个引脚VCC Tring Echo GND。

主要的原理是Tring端输出一个10us的高电平,Echo接收返回的信号,其中发射与接收中间会空出一段时间,这段时间就是我们求距离得关键。
在这里插入图片描述

STM32(基本库)代码实现

首先是IO口的初始化,我这里选择了板子的PB0(Tring)和PB1(Echo)。

void SR04_Cfg(void)
{
	GPIO_InitTypeDef  GPIO_InitSture;
	EXTI_InitTypeDef  EXTI_InitSture;
	//如果外部中断的话则一定使能AFIO复用功能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB,ENABLE);
	
	
	//配置IO端口
	GPIO_InitSture.GPIO_Mode=GPIO_Mode_Out_PP;   //推挽输出模式
	GPIO_InitSture.GPIO_Pin=GPIO_Pin_0;                //将PE4于Trig相连
	GPIO_InitSture.GPIO_Speed=GPIO_Speed_50MHz;  
	GPIO_Init(GPIOB,&GPIO_InitSture);
	
	GPIO_InitSture.GPIO_Mode=GPIO_Mode_IPD;      //拉输入模式
	GPIO_InitSture.GPIO_Pin=GPIO_Pin_1;                //将PE6于Echo相连
	GPIO_InitSture.GPIO_Speed=GPIO_Speed_50MHz;  
	GPIO_Init(GPIOB,&GPIO_InitSture);
	
	//中断和6端口映射一起
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
	
	//外部中断配置
	EXTI_InitSture.EXTI_Line=EXTI_Line1;
	EXTI_InitSture.EXTI_LineCmd=ENABLE;
	EXTI_InitSture.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitSture.EXTI_Trigger=EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitSture);
	
	NVIC_Config(EXTI1_IRQn,1,1);
}

其中NVIC优先级的配置为:

void NVIC_Config(uint16_t IRQChannel, uint16_t MainPriority, uint16_t SubPriority)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	//设置中断来源
	NVIC_InitStructure.NVIC_IRQChannel = IRQChannel;      
	//设置主优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = MainPriority;
	//设置抢占式优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = SubPriority;    
	//使能中断
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

	NVIC_Init(&NVIC_InitStructure);
}

IO口的初始化完成后,来看看是怎么用Tring端发送10us的高电平的:

GPIO_SetBits(GPIOB,GPIO_Pin_0);
		SysTick_Delay_Us(20);
	 GPIO_ResetBits(GPIOB,GPIO_Pin_0);
		my_delay_ms(60);

这段代码放在了主函数,虽然说是10us的高电平,但是实现时经常性卡住,数值不更新,将高电平的时间延长到20us就好了,然后建议整个的周期不要低于60us。

最后也是最重要的一块是Echo的外部中断了:

void EXTI1_IRQHandler(void)
{

	if(EXTI_GetITStatus(EXTI_Line1) != RESET )
	{
		EXTI_ClearITPendingBit(EXTI_Line1);
	
		TIM_SetCounter(TIM3,0);
		TIM_Cmd(TIM3,ENABLE);
		
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1));  //等待低电平
		
		TIM_Cmd(TIM3,DISABLE);
		Distance=TIM_GetCounter(TIM3)*340/200.0;
	
	}
}

采用外部中断的形式判断是否接受到高电平,当接受到低电平时,开启定时器3进行计时,得到低电平时的时间。

void TIM3_CounterMode(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitSture;   
	/* 配置时基结构体 */
	
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3
	
	//初始化定时器	
	TIM_TimeBaseInitSture.TIM_Period=9999;
	TIM_TimeBaseInitSture.TIM_Prescaler=7199;
	TIM_TimeBaseInitSture.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitSture.TIM_ClockDivision=0;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitSture);
	
	//允许更新中断,触发方式中断
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	TIM_ITConfig(TIM3,TIM_IT_Trigger,ENABLE);
	
	NVIC_Config(TIM3_IRQn, 0, 1);
	/*配置中断优先级*/
//	TIM_Cmd(TIM3, ENABLE);
	//使能定时器
}

到这里就已经完成了模块的使用了,可以在调试界面看数值的变换,或者用串口显示,LCD都行。

但要注意,超声波的晶振被挡住或后面被死死黏住时,超声波模块会将程序给卡住。

STM32(Hal库)超声波模块的实现

Hal库是近期学的,CubeMX经常配错东西 ,所以大家看个大概就行,不过和基本库的代码一样,都是能实现的。首先代码的思路是和基本库一样的,这里就简单的过一下。

  GPIO_InitStruct.Pin = Tring_Pin|LEDR_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : Echo_Pin */
  GPIO_InitStruct.Pin = Echo_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(Echo_GPIO_Port, &GPIO_InitStruct);
	
	HAL_NVIC_EnableIRQ(EXTI1_IRQn);
  HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 2);
/* 超声波发送一定频率的高电平 */
void SR04Tring_Go(void)
{
	HAL_GPIO_WritePin(GPIOB, Tring_Pin, GPIO_PIN_SET);
	HAL_Delay(40);
	HAL_GPIO_WritePin(GPIOB, Tring_Pin, GPIO_PIN_RESET);
	HAL_Delay(50);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == GPIO_PIN_1)
	{
		htim6.Instance->CNT = 0;
		HAL_TIM_Base_Start_IT(&htim6);
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1));
		HAL_TIM_Base_Stop_IT(&htim6);
		Distance = htim6.Instance->CNT*340/200.0;
	}
}
void MX_TIM6_Init(void)
{
	

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

//  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 9999;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 7199;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	HAL_TIM_Base_Init(&htim6);
	
	HAL_NVIC_SetPriority(TIM6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(TIM6_IRQn);
	
//  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
//  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
	
	
  /* USER CODE BEGIN TIM6_Init 2 */

  /* USER CODE END TIM6_Init 2 */

}

因为是几块钱的小模块,所以在远的距离时会产生较大的误差,但用来做避障还是足够的。

Hal库就很方便,可以看着我的代码自己重新配一个模板,稍微改下,很快就能实现功能,

你可能感兴趣的:(stm32,嵌入式,单片机)