1.项目需求
以下几个事件触发时,垃圾桶自动开盖,并伴随蜂鸣器短响一声,同时 LED 灯闪烁一下,2秒后自动关盖:
- 检测到有人靠近
- 检测到有震动
- 按下按键 KEY1
2.硬件
- STM32单片机最小系统
- 震动传感器模块
- 蜂鸣器模块(低电平触发)
- HC-SR04超声波传感器模块
- SG90舵机模块
- LED灯模块
硬件接线
STM32 | 震动传感器 | 蜂鸣器 | 超声波传感器 | 舵机 | LED灯 |
---|---|---|---|---|---|
PA4 | DO | ||||
PA6 | I/O | ||||
PB5 | I/O | ||||
PB6 | Trig | ||||
PB7 | Echo | ||||
PB8 | 负极 | ||||
3V3 | VCC | VCC | |||
5V | VCC | VCC | |||
GND | GND | GND | GND | GND |
- 项目框图
3.软件
- led、exti、beep、key、sg90、hcsr04驱动文件添加
- main.c程序
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "beep.h"
#include "exti.h"
#include "hcsr04.h"
#include "key.h"
#include "sg90.h"
#define OPEN 1//宏定义
#define CLOSE 0
uint8_t dustbin_status = CLOSE;//定义盖的状态
void open_dustbin(void)//开盖函数
{
if(dustbin_status == CLOSE)//判断盖的状态,防止手一直放在超声波导致蜂鸣器一直滴
{ //如果是盖关闭情况下才执行
sg90_angle_set(30);
beep_on();
led1_on();
delay_ms(100);
beep_off();
led1_off();
dustbin_status = OPEN;//此时盖的状态为打开
}
}
void close_dustbin(void)//关盖函数
{
sg90_angle_set(0);
beep_off();
led1_off();
dustbin_status = CLOSE;
}
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* 初始化LED灯 */
uart1_init(115200);
beep_init();
exti_init();
hcsr04_init();
key_init();
sg90_init();
printf("hello world!\r\n");
uint8_t key_num = 0;
while(1)
{
key_num = key_scan();//扫描按键
if(key_num == 1 || vibrate_flag_get() == TRUE || hcsr04_get_length() < 10)//条件或,满足一个即可
{
open_dustbin();
delay_ms(2000);
vibrate_flag_set(FALSE);
}
else
close_dustbin();
delay_ms(10);//防止超声波传感器一直获取距离,而导致崩
// sg90_angle_set(0);
// delay_ms(1000);
// sg90_angle_set(20);
// delay_ms(1000);
// sg90_angle_set(40);
// delay_ms(1000);
// sg90_angle_set(90);
// delay_ms(1000);
// sg90_angle_set(180);
// delay_ms(1000);
// key_num = key_scan(); /* 扫描按键获取按下按键的值 */
// if(key_num == 1) /* 检测到按键1按下 */
// led1_toggle(); /* 翻转LED1 */
//
// if(key_num == 2) /* 检测到按键2按下 */
// led2_toggle(); /* 翻转LED2 */
// printf("dis: %.2f\r\n", hcsr04_get_length());
// delay_ms(1000);
// if(vibrate_flag_get() == TRUE)
// {
// //那么就点亮LED1两秒,然后熄灭
// led1_on();
// delay_ms(2000);
// led1_off();
// vibrate_flag_set(FALSE);
// }
// beep_on();
// delay_ms(500);
// beep_off();
// delay_ms(500);
// led1_on();
// led2_off();
// delay_ms(500);
// led1_off();
// led2_on();
// delay_ms(500);
}
}
- exti.c程序
#include "exti.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
uint8_t vibrate_flag = FALSE; // 检测到震动标志位
void exti_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_4; // 震动传感器对应的引脚
gpio_initstruct.Mode = GPIO_MODE_IT_FALLING; // 下降沿触发
gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
HAL_GPIO_Init(GPIOA, &gpio_initstruct);
HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0); // 设置EXTI0中断线的优先级
HAL_NVIC_EnableIRQ(EXTI4_IRQn); // 使能中断
}
void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
//delay_ms(20);
if (GPIO_Pin == GPIO_PIN_4)
{
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET)
//led1_toggle();
vibrate_flag = TRUE;
}
}
uint8_t vibrate_flag_get(void)
{
uint8_t temp = vibrate_flag;
vibrate_flag = FALSE;
return temp;
}
void vibrate_flag_set(uint8_t value)
{
vibrate_flag = value;
}
- exti.h程序
#ifndef __EXTI_H__
#define __EXTI_H__
#include "stdint.h"
#define TRUE 1
#define FALSE 0
void exti_init(void);
uint8_t vibrate_flag_get(void);
void vibrate_flag_set(uint8_t value);
#endif
- led.c
#include "led.h"
#include "sys.h"
//初始化GPIO函数
void led_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_8 | GPIO_PIN_9; // 两个LED对应的引脚
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
//关闭LED
led1_off();
led2_off();
}
//点亮LED1的函数
void led1_on(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET); // 拉低LED1引脚,点亮LED1
}
//熄灭LED1的函数
void led1_off(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET); // 拉高LED1引脚,熄灭LED1
}
//翻转LED1状态的函数
void led1_toggle(void)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
}
//点亮LED2的函数
void led2_on(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET); // 拉低LED2引脚,点亮LED2
}
//熄灭LED2的函数
void led2_off(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET); // 拉高LED2引脚,熄灭LED2
}
//翻转LED2状态的函数
void led2_toggle(void)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9);
}
- led.h
#ifndef __LED_H__
#define __LED_H__
void led_init(void);
void led1_on(void);
void led1_off(void);
void led1_toggle(void);
void led2_on(void);
void led2_off(void);
void led2_toggle(void);
#endif
- beep.c
#include "beep.h"
#include "sys.h"
//初始化GPIO函数
void beep_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_5; // 蜂鸣器对应的引脚PB5
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
//关闭蜂鸣器
beep_off();
}
//打开蜂鸣器的函数
void beep_on(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); // 拉低蜂鸣器引脚,打开蜂鸣器
}
//关闭蜂鸣器的函数
void beep_off(void)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET); // 拉高蜂鸣器引脚,关闭蜂鸣器
}
- beep.h
#ifndef __BEEP_H__
#define __BEEP_H__
void beep_init(void);
void beep_on(void);
void beep_off(void);
#endif
- hcsr04.c
#include "hcsr04.h"
#include "delay.h"
TIM_HandleTypeDef tim2_handle = {0};
//定时器初始化函数
void tim2_init(void)
{
tim2_handle.Instance = TIM2;
tim2_handle.Init.Prescaler = 72 - 1;
tim2_handle.Init.Period = 65536 - 1;
tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2_handle);
}
//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
__HAL_RCC_TIM2_CLK_ENABLE();
}
}
void tim2_start(void)
{
HAL_TIM_Base_Start(&tim2_handle);
}
void tim2_stop(void)
{
HAL_TIM_Base_Stop(&tim2_handle);
}
uint16_t tim2_get_cnt(void)
{
return __HAL_TIM_GetCounter(&tim2_handle);
}
void tim2_set_cnt(uint16_t val)
{
__HAL_TIM_SetCounter(&tim2_handle, val);
}
void hcsr04_gpio_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
TRIG_GPIO_CLK_ENABLE();
ECHO_GPIO_CLK_ENABLE();
//初始化Trig引脚
gpio_initstruct.Pin = TRIG_PIN;
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_initstruct.Pull = GPIO_NOPULL;
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(TRIG_PORT, &gpio_initstruct);
gpio_initstruct.Pin = ECHO_PIN;
gpio_initstruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(ECHO_PORT, &gpio_initstruct);
}
void hcsr04_init(void)
{
tim2_init();
hcsr04_gpio_init();
}
float hcsr04_get_length(void)
{
uint16_t total_time = 0;
float distance = 0;
//1. Trig,给Trig端口至少10us的高电平
TRIG_HIGH();
delay_us(15);
TRIG_LOW();
//2. Echo引脚,由低电平跳转到高电平,表示开始发送波
//波发出去的那一下,开始启动定时器
while(ECHO_STATUS() == GPIO_PIN_RESET);
tim2_start();
tim2_set_cnt(0);
//3. Echo,由高电平跳转回低电平,表示波回来了
//波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
while(ECHO_STATUS() == GPIO_PIN_SET);
tim2_stop();
//4. 计算出中间经过多少时间
total_time = tim2_get_cnt();
//5. 距离 = 速度(343m/s) * 时间 / 2
distance = total_time * 0.01715;
return distance;
}
- hcsr04.h
#ifndef __HCSR04_H__
#define __HCSR04_H__
#include "sys.h"
#define TRIG_PORT GPIOB
#define TRIG_PIN GPIO_PIN_6
#define TRIG_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define TRIG_HIGH() HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET)
#define TRIG_LOW() HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET)
#define ECHO_PORT GPIOB
#define ECHO_PIN GPIO_PIN_7
#define ECHO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define ECHO_STATUS() HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN)
void hcsr04_init(void);
float hcsr04_get_length(void);
#endif
- key.c
#include "key.h"
#include "delay.h"
//初始化GPIO
void key_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; // 两个KEY对应的引脚
gpio_initstruct.Mode = GPIO_MODE_INPUT; // 输入
gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOA, &gpio_initstruct);
}
//按键扫描函数
uint8_t key_scan(void)
{
//检测按键是否按下
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
{
//消抖
delay_ms(10);
//再次判断按键是否按下
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
{
//如果确实是按下的状态,等待按键松开
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);
//返回按键值
return 1;
}
}
//检测按键是否按下
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
{
//消抖
delay_ms(10);
//再次判断按键是否按下
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
{
//如果确实是按下的状态,等待按键松开
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET);
//返回按键值
return 2;
}
}
//返回默认值
return 0;
}
- key.h
#ifndef __KEY_H__
#define __KEY_H__
#include "sys.h"
void key_init(void);
uint8_t key_scan(void);
#endif
- sg90.c
#include "sg90.h"
TIM_HandleTypeDef tim3_handle = {0};
// init函数
void tim3_init(void)
{
TIM_OC_InitTypeDef pwm_config = {0};
tim3_handle.Instance = TIM3;
tim3_handle.Init.Prescaler = 7200 - 1;
tim3_handle.Init.Period = 200 - 1;
tim3_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_PWM_Init(&tim3_handle);
pwm_config.OCMode = TIM_OCMODE_PWM1;
pwm_config.Pulse = 100;
pwm_config.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&tim3_handle, &pwm_config, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&tim3_handle, TIM_CHANNEL_1);
}
//msp函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
GPIO_InitTypeDef gpio_initstruct;
//打开时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOB时钟
__HAL_RCC_TIM3_CLK_ENABLE();
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_6; // 两个LED对应的引脚
gpio_initstruct.Mode = GPIO_MODE_AF_PP; // 推挽输出
gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOA, &gpio_initstruct);
}
}
//修改CCR值的函数
void tim3_compare_set(uint16_t val)
{
__HAL_TIM_SET_COMPARE(&tim3_handle, TIM_CHANNEL_1, val);
}
void sg90_init(void)
{
tim3_init();
}
void sg90_angle_set(uint16_t angle)
{
uint16_t CCRx = (1.0 / 9.0) * angle + 5.0;
tim3_compare_set(CCRx);
}
- sg90.h
#ifndef __SG90_H__
#define __SG90_H__
#include "sys.h"
void sg90_init(void);
void sg90_angle_set(uint16_t angle);
#endif
4.实物效果
ST-Link下载方式