目录
项目需求
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
项目框图![](https://i-blog.csdnimg.cn/blog_migrate/bea9b6e1ce0f8fa32c4b90781ec344a5.png)
硬件清单
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 */