用HC-SR501检测人接近1s以上,控制L9110风扇模块启动同时启动DHT11检测环境温度,根据温度自动调整风扇转速,人离开后关闭风扇,STM32F103ZET6生成代码
时间: 2023-06-20 20:03:28 浏览: 136
以下是基于STM32CubeMX和HAL库生成的代码,可以实现根据DHT11检测的温度自动调整风扇转速,并且在人离开后关闭风扇。
首先,需要在STM32CubeMX中配置以下外设和引脚:
- 时钟:使用外部晶振,主频为72MHz
- GPIO:PA0作为HC-SR501的信号输入,PB0和PB1分别作为L9110风扇模块的IN1和IN2输入,PC13作为人接近检测的LED指示灯输出
- TIM:使用TIM1作为PWM输出,配置PB13作为TIM1_CH1输出
- USART:使用USART1与DHT11通信,配置PA9作为USART1_TX输出,PA10作为USART1_RX输入
然后在STM32CubeMX中生成代码,并在main.c中添加以下代码(注释中有详细解释):
```c
#include "main.h"
#include "dht11.h"
// 定义HC-SR501的输入引脚
#define PIR_Pin GPIO_PIN_0
#define PIR_GPIO_Port GPIOA
// 定义L9110风扇模块的输入引脚和PWM输出引脚
#define IN1_Pin GPIO_PIN_0
#define IN1_GPIO_Port GPIOB
#define IN2_Pin GPIO_PIN_1
#define IN2_GPIO_Port GPIOB
#define PWM_Pin GPIO_PIN_13
#define PWM_GPIO_Port GPIOB
// 定义DHT11的输入输出引脚
#define DHT11_Pin GPIO_PIN_9
#define DHT11_GPIO_Port GPIOA
// 定义PWM输出的最大值和最小值
#define PWM_MAX_VALUE 10000
#define PWM_MIN_VALUE 0
// 定义DHT11读取数据的间隔时间
#define DHT11_READ_INTERVAL 2000
// 定义人接近检测的LED指示灯的闪烁时间
#define PIR_LED_BLINK_INTERVAL 200
// 定义变量保存当前温度和湿度
static uint8_t temperature = 0;
static uint8_t humidity = 0;
// 定义变量保存当前PWM输出值
static uint16_t pwm_value = PWM_MIN_VALUE;
// 定义变量保存上一次检测到人的时间
static uint32_t last_pir_time = 0;
// 定义变量保存上一次读取DHT11数据的时间
static uint32_t last_dht11_read_time = 0;
// 定义变量保存当前是否检测到人
static uint8_t is_pir_detected = 0;
// 定义变量保存当前LED指示灯是否亮着
static uint8_t is_pir_led_on = 0;
// 定义变量保存当前是否正在读取DHT11数据
static uint8_t is_dht11_reading = 0;
// 定义函数:初始化HC-SR501
void PIR_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PIR_Pin */
GPIO_InitStruct.Pin = PIR_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(PIR_GPIO_Port, &GPIO_InitStruct);
}
// 定义函数:初始化L9110风扇模块
void L9110_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pins : IN1_Pin IN2_Pin */
GPIO_InitStruct.Pin = IN1_Pin|IN2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PWM_Pin */
GPIO_InitStruct.Pin = PWM_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(PWM_GPIO_Port, &GPIO_InitStruct);
}
// 定义函数:初始化定时器1作为PWM输出
void TIM1_PWM_Init(void)
{
TIM_HandleTypeDef htim1 = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* TIM1 clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* Configure TIM1: PWM */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = PWM_MAX_VALUE;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&htim1);
/* Configure TIM1 OC */
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = PWM_MIN_VALUE;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
/* Start TIM1 PWM */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
// 定义函数:初始化DHT11
void DHT11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : DHT11_Pin */
GPIO_InitStruct.Pin = DHT11_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
/* Set DHT11 pin to high */
HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET);
}
// 定义函数:检测HC-SR501是否检测到人
void PIR_Detect(void)
{
if (HAL_GPIO_ReadPin(PIR_GPIO_Port, PIR_Pin) == GPIO_PIN_SET) {
// 人接近
last_pir_time = HAL_GetTick();
if (!is_pir_detected) {
// 之前没有检测到人,打开风扇和LED指示灯
is_pir_detected = 1;
is_pir_led_on = 1;
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, GPIO_PIN_RESET);
}
} else {
// 人离开
if (HAL_GetTick() - last_pir_time > 1000) {
// 已经离开超过1秒,关闭风扇和LED指示灯
is_pir_detected = 0;
is_pir_led_on = 0;
HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, GPIO_PIN_RESET);
} else {
// 仍然在检测到人的时间内,保持风扇和LED指示灯状态不变
}
}
}
// 定义函数:读取DHT11数据
void DHT11_Read(void)
{
if (!is_dht11_reading && HAL_GetTick() - last_dht11_read_time > DHT11_READ_INTERVAL) {
// 当前没有在读取DHT11数据,并且间隔时间已经超过预设时间
is_dht11_reading = 1;
uint8_t data[5] = {0};
if (DHT11_ReadData(data) == DHT11_OK) {
// 读取数据成功,计算温度和湿度
humidity = data[0];
temperature = data[2];
}
is_dht11_reading = 0;
last_dht11_read_time = HAL_GetTick();
}
}
// 定义函数:根据温度调整PWM输出值
void PWM_Adjust(void)
{
if (is_pir_detected) {
// 人接近,根据温度调整PWM输出值
if (temperature >= 30) {
pwm_value = PWM_MAX_VALUE;
} else if (temperature >= 25) {
pwm_value = PWM_MAX_VALUE * 3 / 4;
} else if (temperature >= 20) {
pwm_value = PWM_MAX_VALUE * 1 / 2;
} else {
pwm_value = PWM_MAX_VALUE * 1 / 4;
}
} else {
// 人离开,PWM输出值为最小值
pwm_value = PWM_MIN_VALUE;
}
// 更新PWM输出值
TIM_HandleTypeDef htim1 = {0};
htim1.Instance = TIM1;
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = pwm_value;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
// 定义函数:控制LED指示灯闪烁
void PIR_LED_Blink(void)
{
static uint32_t last_blink_time = 0;
if (is_pir_led_on && HAL_GetTick() - last_blink_time > PIR_LED_BLINK_INTERVAL) {
// LED指示灯亮着,并且闪烁时间已经超过预设时间
is_pir_led_on = 0;
HAL_GPIO_WritePin(PC13_GPIO_Port, PC13_Pin, GPIO_PIN_RESET);
} else if (!is_pir_led_on && HAL_GetTick() - last_blink_time > PIR_LED_BLINK_INTERVAL) {
// LED指示灯没亮,并且闪烁时间已经超过预设时间
is_pir_led_on = 1;
HAL_GPIO_WritePin(PC13_GPIO_Port, PC13_Pin, GPIO_PIN_SET);
} else {
// LED指示灯状态不变
}
}
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
PIR_Init();
L9110_Init();
TIM1_PWM_Init();
DHT11_Init();
/* Infinite loop */
while (1)
{
PIR_Detect();
DHT11_Read();
PWM_Adjust();
PIR_LED_Blink();
HAL_Delay(10);
}
}
```
需要注意的是,以上代码中使用了DHT11库来读取DHT11的温度和湿度数据。DHT11库的代码可以自行搜索下载,也可以参考以下代码:
```c
#include "dht11.h"
#define DHT11_DATA_HIGH_TIME 30
#define DHT11_DATA_LOW_TIME 80
#define DHT11_ACK_HIGH_TIME 80
#define DHT11_ACK_LOW_TIME 80
static void DHT11_Delay(uint32_t ms)
{
HAL_Delay(ms);
}
static void DHT11_SetPinOutput(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
static void DHT11_SetPinInput(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
static uint8_t DHT11_ReadByte(void)
{
uint8_t data = 0;
for (uint8_t i = 0; i < 8; i++) {
while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_RESET);
DHT11_Delay(DHT11_DATA_HIGH_TIME);
if (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_SET) {
data |= 1 << (7 - i);
}
while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_SET);
}
return data;
}
static uint8_t DHT11_ReadData(uint8_t data[5])
{
// 发送起始信号
DHT11_SetPinOutput(DHT11_GPIO_Port, DHT11_Pin);
HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET);
DHT11_Delay(18);
HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET);
DHT11_Delay(1);
DHT11_SetPinInput(DHT11_GPIO_Port, DHT11_Pin);
// 等待DHT11响应
uint32_t timeout = DHT11_ACK_HIGH_TIME;
while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_RESET && timeout--);
if (timeout == 0) {
return DHT11_TIMEOUT_ERROR;
}
timeout = DHT11_ACK_LOW_TIME;
while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) == GPIO_PIN_SET && timeout--);
if (timeout == 0) {
return DHT11_TIMEOUT_ERROR;
}
// 读取数据
for (uint8_t i = 0; i < 5; i++) {
data[i] = DHT11_ReadByte();
}
// 计算校验和
if (data[0] + data[1] + data[2] + data[3] != data[4]) {
return DHT11_CHECKSUM_ERROR;
}
return DHT11_OK;
}
```
阅读全文