#include "sensor_app.h" static void DHT22_SetPinOut(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = TEMP_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(TEMP_GPIO_Port, &GPIO_InitStruct); } static void DHT22_SetPinIn(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = TEMP_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(TEMP_GPIO_Port, &GPIO_InitStruct); } static void delay_us(uint16_t us) { uint32_t start = __HAL_TIM_GET_COUNTER(&htim3); while ((uint16_t)(__HAL_TIM_GET_COUNTER(&htim3) - start) < us); } static uint8_t DHT22_Read(float *temp, float *humid) { uint8_t data[5] = {0}; uint32_t start_tick; // 1. Gửi tín hiệu đánh thức cảm biến (Kéo LOW > 18ms) DHT22_SetPinOut(); HAL_GPIO_WritePin(TEMP_GPIO_Port, TEMP_Pin, GPIO_PIN_RESET); vTaskDelay(pdMS_TO_TICKS(18)); // Khóa ngắt FreeRTOS ngay lúc này để bảo vệ tuyệt đối độ trễ 20us phía sau taskENTER_CRITICAL(); HAL_GPIO_WritePin(TEMP_GPIO_Port, TEMP_Pin, GPIO_PIN_SET); delay_us(20); // 2. Chuyển sang chế độ nhận (Input) DHT22_SetPinIn(); // Đợi phản hồi LOW từ DHT22 (~80us) start_tick = __HAL_TIM_GET_COUNTER(&htim3); while (HAL_GPIO_ReadPin(TEMP_GPIO_Port, TEMP_Pin) == GPIO_PIN_SET) { if ((uint16_t)(__HAL_TIM_GET_COUNTER(&htim3) - start_tick) > 100) { taskEXIT_CRITICAL(); return 0; } } // Đợi phản hồi HIGH từ DHT22 (~80us) start_tick = __HAL_TIM_GET_COUNTER(&htim3); while (HAL_GPIO_ReadPin(TEMP_GPIO_Port, TEMP_Pin) == GPIO_PIN_RESET) { if ((uint16_t)(__HAL_TIM_GET_COUNTER(&htim3) - start_tick) > 100) { taskEXIT_CRITICAL(); return 0; } } // Đợi chân kéo LOW trở lại để chuẩn bị truyền bit đầu tiên start_tick = __HAL_TIM_GET_COUNTER(&htim3); while (HAL_GPIO_ReadPin(TEMP_GPIO_Port, TEMP_Pin) == GPIO_PIN_SET) { if ((uint16_t)(__HAL_TIM_GET_COUNTER(&htim3) - start_tick) > 100) { taskEXIT_CRITICAL(); return 0; } } // 3. Đọc 40 bit dữ liệu for (int i = 0; i < 40; i++) { // Đợi chân nảy lên HIGH start_tick = __HAL_TIM_GET_COUNTER(&htim3); while (HAL_GPIO_ReadPin(TEMP_GPIO_Port, TEMP_Pin) == GPIO_PIN_RESET) { if ((uint16_t)(__HAL_TIM_GET_COUNTER(&htim3) - start_tick) > 100) { taskEXIT_CRITICAL(); return 0; } } // Đo độ rộng xung mức HIGH start_tick = __HAL_TIM_GET_COUNTER(&htim3); while (HAL_GPIO_ReadPin(TEMP_GPIO_Port, TEMP_Pin) == GPIO_PIN_SET) { if ((uint16_t)(__HAL_TIM_GET_COUNTER(&htim3) - start_tick) > 150) { taskEXIT_CRITICAL(); return 0; } } uint32_t t = (uint16_t)(__HAL_TIM_GET_COUNTER(&htim3) - start_tick); // Nửa chu kỳ > 40us được tính là bit 1 if (t > 40) { data[i / 8] |= (1 << (7 - (i % 8))); } } // Mở lại ngắt hệ điều hành sau khi đã đọc xong taskEXIT_CRITICAL(); // Kiểm tra checksum và loại bỏ gói dữ liệu rác toàn số 0 if ((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) return 0; if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) return 0; // Chuyển đổi dữ liệu thô sang nhiệt độ/độ ẩm thực tế uint16_t h = (data[0] << 8) | data[1]; uint16_t t_val = (data[2] << 8) | data[3]; *humid = (float)h / 10.0f; *temp = (float)(t_val & 0x7FFF) / 10.0f; if (t_val & 0x8000) *temp = -(*temp); return 1; } void SensorTask_Main(void) { float temp, humid; uint32_t msg; HAL_TIM_Base_Start(&htim3); for (;;) { if (DHT22_Read(&temp, &humid)) { msg = PACK_MSG(CMD_UPDATE_HUMID, 0, (uint16_t)(humid * 10.0f)); xQueueSend((QueueHandle_t)TelemetryQueueHandle, &msg, 0); msg = PACK_MSG(CMD_UPDATE_TEMP, 0, (uint16_t)(temp * 10.0f)); xQueueSend((QueueHandle_t)TelemetryQueueHandle, &msg, 0); } HAL_ADC_Start(&hadc1); if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) { uint16_t mq2_val = HAL_ADC_GetValue(&hadc1); msg = PACK_MSG(CMD_MQ2_ANALOG, 0, mq2_val); xQueueSend((QueueHandle_t)TelemetryQueueHandle, &msg, 0); } HAL_ADC_Stop(&hadc1); vTaskDelay(pdMS_TO_TICKS(2000)); } } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_0) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; if (AlertEvent != NULL) { xEventGroupSetBitsFromISR(AlertEvent, SMOKE_ALERT_BIT, &xHigherPriorityTaskWoken); } portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } }