基于STM32的感应开关盖垃圾桶

该项目利用SG90舵机控制垃圾桶开闭,结合超声波传感器进行距离检测,当物体靠近至5cm内时自动开启,并在2秒后关闭。同时,系统集成了震动传感器和按键,当发生震动或按下按键时也能触发开盖功能。通过微秒级延时函数和定时器配置实现了精确的控制逻辑。
摘要由CSDN通过智能技术生成

目录

项目需求

项目框图​编辑

硬件清单

sg90舵机介绍

超声波传感器介绍及实战

超声波传感器介绍

 编程实战

需求:

接线:

定时器配置:

 编写微秒级函数:

距离检测开盖

功能整合

加入蜂鸣器、按键开盖、震动开盖


项目需求

检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

项目框图

硬件清单

SG90舵机,超声波模块,震动传感器,蜂鸣器

a. sg90舵机介绍及实战

sg90舵机介绍

 PWM波的频率不能太高,大约50HZ,即周期=1/频率=1/50=0.02s,20ms左右。

确定周期/频率

 如果周期为20ms,即 Tout = 20000us

且要角度精确到度,即一度对应一单位ARR

舵机0~180度,对应占空比 0.5ms~2.5ms/20ms

换算可得 ARR+1 = 1800 ,角度0~180度 对应 ARR 范围 44 ~ 224

则 PSC=799,ARR=1799

 通过一个函数来将输入的角度 0~180 转化为对应占空比。

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//根据输入的角度获取对应pwm占空比参数
uint8_t Angle(uint8_t pwm_pulse)
{
	return pwm_pulse + 44;
}

/* USER CODE END 0 */

... ... ... ... ...

  /* USER CODE BEGIN 2 */
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
	//设置初始角度为 90
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, Angle(90));
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		//超过180之后回到0度
		if(angle > 180)	angle = 0;
		
		/* USER CODE BEGIN 3 */
		//每1s改变一次角度
		HAL_Delay(1000);
		//修改比较值,修改占空比
		__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, Angle(angle)); 
		//每秒转45度
		angle += 45;
		
  }
  /* USER CODE END 3 */

超声波传感器介绍及实战

超声波传感器介绍

怎么让它发送波

Trig ,给Trig端口至少10us的高电平

怎么知道它开始发了

Echo信号,由低电平跳转到高电平,表示开始发送波

怎么知道接收了返回波

Echo,由高电平跳转回低电平,表示波回来了

怎么算时间

Echo引脚维持高电平的时间!

波发出去的那一下,开始启动定时器

波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间

怎么算距离

距离 = 速度 (340m/s)* 时间/2

 编程实战

需求:

使用超声波测距,当手离传感器距离小于5cm时,LED1点亮,否则保持不亮状态。

接线:

Trig --- PB6

Echo --- PB7

LED1 --- PB8

定时器配置:

使用 TIM2 ,只用作计数功能,不用作定时。

将 PSC 配置为71,则计数 1 次代表 1us 。

 编写微秒级函数:

传入要延时多少微秒,开始延时,延时到指定时长,停止延时

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//使用TIM2来做us级延时函数
void TIM2_Delay_us(uint16_t n_us)
{
	/* 使能定时器2计数 */
	__HAL_TIM_ENABLE(&htim2);
	__HAL_TIM_SetCounter(&htim2, 0);
	while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us)-1) );
	/* 关闭定时器2计数 */
	__HAL_TIM_DISABLE(&htim2);
}

/* USER CODE END 0 */

//1. Trig ,给Trig端口至少10us的高电平
//2. echo由低电平跳转到高电平,表示开始发送波
//波发出去的那一下,开始启动定时器
//3. 由高电平跳转回低电平,表示波回来了
//波回来的那一下,我们开始停止定时器
//4. 计算出中间经过多少时间
//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
//每500毫秒测试一次距离

  /* USER CODE BEGIN 1 */
	int cnt=0;
	float distance=0;
	
  /* USER CODE END 1 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
		//1. Trig ,给Trig端口至少10us的高电平
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//拉高
		TIM2_Delay_us(20);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);//拉低
		
		//2. echo由低电平跳转到高电平,表示开始发送波
		//波发出去的那一下,开始启动定时器
		while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
		HAL_TIM_Base_Start(&htim2);
		__HAL_TIM_SetCounter(&htim2, 0);
		
		//3. 由高电平跳转回低电平,表示波回来了
		//波回来的那一下,我们开始停止定时器
		while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_SET);
		HAL_TIM_Base_Stop(&htim2);
		
		//4. 计算出中间经过多少时间
		time_us = __HAL_TIM_GetCounter(&htim2);
		
		//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
		distance = time_us * 340/2 * 0.000001 * 100; //单位:cm
		
		//距离小于10,点灯
		if(distance < 5)
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
		else
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
		
		//每500毫秒测试一次距离
		HAL_Delay(500);
		
  }
  /* USER CODE END 3 */

距离检测开盖

PB9输出PWM给舵机

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//使用TIM2来做us级延时函数
void TIM2_Delay_us(uint16_t n_us)
{
	/* 使能定时器2计数 */
	__HAL_TIM_ENABLE(&htim2);
	__HAL_TIM_SetCounter(&htim2, 0);
	while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us)-1) );
	/* 关闭定时器2计数 */
	__HAL_TIM_DISABLE(&htim2);
}

//测距获取信息
float get_distance()
{
	//1. Trig ,给Trig端口至少10us的高电平
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//拉高
	TIM2_Delay_us(20);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);//拉低
	
	//2. echo由低电平跳转到高电平,表示开始发送波
	//波发出去的那一下,开始启动定时器
	while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
	HAL_TIM_Base_Start(&htim2);
	__HAL_TIM_SetCounter(&htim2, 0);
	
	//3. 由高电平跳转回低电平,表示波回来了
	//波回来的那一下,我们开始停止定时器
	while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_SET);
	HAL_TIM_Base_Stop(&htim2);
	
	//4. 计算出中间经过多少时间	
	//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
	return __HAL_TIM_GetCounter(&htim2) * 340/2 * 0.000001 * 100; //单位:cm
}

//根据输入的角度获取对应pwm占空比参数
uint8_t sg90(uint8_t pwm_pulse)
{
	return pwm_pulse + 44;
}

/* USER CODE END 0 */
//============================================================
/* USER CODE BEGIN 2 */
	//开始输出pwm信号
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
	//设置初始角度为 0
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, sg90(0));

  /* USER CODE END 2 */
//============================================================
/* USER CODE END WHILE */
		/* USER CODE BEGIN 3 */
		if(get_distance() < 5)
		{
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, sg90(180));
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
			HAL_Delay(2000);
		}
		else
		{
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, sg90(0));
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
			
			//避免频繁重载定时器(功耗和灵敏度的抉择)
			HAL_Delay(10);
		}
    
  }
	
  /* USER CODE END 3 */

功能整合

加入蜂鸣器、按键开盖、震动开盖

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t vib_mark = 0;
/* USER CODE END PV */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

//根据输入的角度获取对应pwm占空比参数
uint8_t sg90(uint8_t pwm_pulse)
{
	return pwm_pulse + 44;
}

//开盖,亮指示灯,蜂鸣器响
void OPEN_dustbin()
{
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_RESET);
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, sg90(180));
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
	HAL_Delay(500);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,GPIO_PIN_SET);
	HAL_Delay(1500);
}

//关盖,灭指示灯,每100ms检测一次
void CLOSE_dustbin()
{
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, sg90(0));
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
	
	//避免频繁重载定时器(功耗和灵敏度的抉择)
	HAL_Delay(100);
}

//按键、震动传感器中断
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	switch(GPIO_Pin)
	{
		case GPIO_PIN_0://按钮开盖
			OPEN_dustbin();
		break;
		
		case GPIO_PIN_1://开关震动功能
			vib_mark = !vib_mark;
			CLOSE_dustbin();
		break;
		
		case GPIO_PIN_4://震动开盖
			if(vib_mark)
				OPEN_dustbin();
		break;
	}
}

//使用TIM2来做us级延时函数
void TIM2_Delay_us(uint16_t n_us)
{
	/* 使能定时器2计数 */
	__HAL_TIM_ENABLE(&htim2);
	__HAL_TIM_SetCounter(&htim2, 0);
	while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us)-1) );
	/* 关闭定时器2计数 */
	__HAL_TIM_DISABLE(&htim2);
}

//测距获取信息
float get_distance()
{
	//1. Trig ,给Trig端口至少10us的高电平
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);//拉高
	TIM2_Delay_us(20);
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);//拉低
	
	//2. echo由低电平跳转到高电平,表示开始发送波
	//波发出去的那一下,开始启动定时器
	while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_RESET);
	HAL_TIM_Base_Start(&htim2);
	__HAL_TIM_SetCounter(&htim2, 0);
	
	//3. 由高电平跳转回低电平,表示波回来了
	//波回来的那一下,我们开始停止定时器
	while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==GPIO_PIN_SET);
	HAL_TIM_Base_Stop(&htim2);
	
	//4. 计算出中间经过多少时间	
	//5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
	return __HAL_TIM_GetCounter(&htim2) * 340/2 * 0.000001 * 100; //单位:cm
}

/* USER CODE END 0 */
//===================================================================
 /* USER CODE BEGIN SysInit */
	HAL_NVIC_SetPriority(SysTick_IRQn,0,0);//提高滴答定时器优先级
	
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
	//开始输出pwm信号
	HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
	//设置初始角度为 0
	__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, sg90(0));

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		//距离检测开关盖
		if(get_distance() < 5)
		{
			OPEN_dustbin();
		}
		else
		{
			CLOSE_dustbin();
		}
    
  }
	
  /* USER CODE END 3 */

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值