#include "common_config.h" #include "stm32f4xx.h" #include "gpio.h" #include "AM2301.h" #ifdef PRINTF_STDLIB #include #endif #ifdef PRINTF_CUSTOM #include "tinystdio.h" #endif #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #define AM2301_ERRORS_LIMIT 5 /* Force remove debug output */ #undef DBG #define DBG if(0) static void one_wire_delay_us(uint16_t time); static void am2301_pin_as_output(at2301_sensor *sensor); static void am2301_pin_as_input(at2301_sensor *sensor); AM2301_t am2301_reset(at2301_sensor *sensor); at2301_data_t sAM2301Sensorsdata[MAX_T_SENSORS]; at2301_sensor sAM2301Sensors[MAX_T_SENSORS]; TIM_TypeDef *timer = TIM2; static bool dht_present = false; static bool dht_finish = false; static bool new_hum_request = false; static uint8_t rawData[50]; static void am2301_pin_as_output(at2301_sensor *sensor) { gpio_pindef_t *pin = &gpio_pins[sensor->ow_pin]; gpio_hw_config_pin(pin->port, pin->pin, (GPIO_MODE_OUT_CFG | GPIO_SPEED_HIGH_CFG)); gpio_set(sensor->ow_pin, GPIO_SET); } static void am2301_pin_as_input(at2301_sensor *sensor) { gpio_pindef_t *pin = &gpio_pins[sensor->ow_pin]; gpio_hw_config_pin(pin->port, pin->pin, (GPIO_MODE_IN_CFG | GPIO_PU_CFG)); } AM2301_t am2301_reset(at2301_sensor *sensor) { uint8_t flag_err = 0; new_hum_request = true; /* Запрос данных у датчика */ //Перевод пина "на выход" am2301_pin_as_output(sensor); //Опускание линии данных на 500 мкс gpio_set(sensor->ow_pin, 0); one_wire_delay_us(500); //Подъём линии, перевод порта "на вход" gpio_set(sensor->ow_pin, 1); am2301_pin_as_input(sensor); for(uint8_t i = 0; i < 120; i++); NVIC_EnableIRQ(sensor->irq); flag_err = 0; while(!dht_present) { vTaskDelay(1); flag_err ++; if(flag_err > 5) { break; } } if (flag_err > 5) { DBG printf("CONNECT ERR\r\n\r\n"); return CONNECTION_ERR; } return CONNECTION_OK; } AM2301_t am2301_get_data(at2301_sensor *sensor, at2301_data_t *data) { uint8_t flag_err = 0; dht_present = false; dht_finish = false; if (am2301_reset(sensor) != CONNECTION_OK) { dht_present = false; dht_finish = false; NVIC_DisableIRQ(sensor->irq); return CONNECTION_ERR; } flag_err = 0; while(!dht_finish) { vTaskDelay(1); if(flag_err > 5) { break; } flag_err ++; } if (flag_err > 5) { dht_present = false; dht_finish = false; NVIC_DisableIRQ(sensor->irq); return READ_ERR; } dht_present = false; dht_finish = false; NVIC_DisableIRQ(sensor->irq); uint8_t data_sensor[5] = {0, 0, 0, 0, 0}; for(uint8_t a = 0; a < 5; a++) { for(uint8_t b = 0; b < 8; b ++) { if(rawData[a*8 + b] > 100) data_sensor[a] |= (1<<(7 - b)); } } memset(rawData, 0, sizeof(rawData)); /* Проверка целостности данных */ if((uint8_t)(data_sensor[0] + data_sensor[1] + data_sensor[2] + data_sensor[3]) == data_sensor[4]) { //Если контрольная сумма совпадает, то конвертация и возврат полученных значений data->hum = (float)(((uint16_t)data_sensor[0]<<8) | data_sensor[1])*0.1f; //Проверка на отрицательность температуры if(!(rawData[2] & (1<<7))) { data->temp = (float)(((uint16_t)data_sensor[2]<<8) | data_sensor[3])*0.1f; } else { rawData[2] &= ~(1<<7); data->temp = (float)(((uint16_t)data_sensor[2]<<8) | data_sensor[3])*-0.1f; } } else { DBG printf("TEMP ERR\r\n\r\n"); return PARITY_ERR; } DBG printf("TEMP = %.1f\r\n\r\n", data->temp); DBG printf("HUM = %.1f\r\n\r\n", data->hum); return DATA_OK; } void am2301_init_port(void) { // Setup clock if (timer == TIM2) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); else if (timer == TIM3) RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); else while(1){} // not implemented TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_InitStructure.TIM_Prescaler = 84 - 1; // For 84 MHz APB1 timer clock TIM_InitStructure.TIM_Period = 0xFFFF; TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_InitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(timer, &TIM_InitStructure); //TIM_ITConfig(timer, TIM_IT_Update, ENABLE); TIM_Cmd(timer, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // Selects the GPIOA pin 0 used as external interrupt source SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); // Selects the GPIOC pin 12 used as external interrupt source SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource12); // External interrupt settings EXTI_InitTypeDef EXTI_InitStruct; EXTI_InitStruct.EXTI_Line = EXTI_Line0 | EXTI_Line12; EXTI_InitStruct.EXTI_LineCmd = ENABLE; EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStruct); // Nested vectored interrupt settings NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn | EXTI15_10_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = DISABLE; // EXTI0_IRQn has Most important interrupt NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00; NVIC_Init(&NVIC_InitStruct); } void am2301_init_sensors(void) { uint8_t i; for (i = 0; i < MAX_T_SENSORS; i++) { sAM2301Sensorsdata[i].hum = 0.0; sAM2301Sensorsdata[i].temp = 0.0; sAM2301Sensorsdata[i].ErrorCycle = 0; sAM2301Sensorsdata[i].SensorState = 1; // По умолчанию устанавливаем признак неисправности } sAM2301Sensors[0].ow_pin = WDATA1; sAM2301Sensors[0].irq = EXTI0_IRQn; sAM2301Sensors[1].ow_pin = WDATA2; sAM2301Sensors[1].irq = EXTI15_10_IRQn; } /** * @brief Задача чтения температуры 1-wire */ void vTaskDHT(void *pvParameters) { (void)pvParameters; am2301_init_port(); am2301_init_sensors(); vTaskDelay(1000); for (;;) { for(uint8_t i = 0; i < MAX_T_SENSORS; i++) { if (am2301_get_data(&sAM2301Sensors[i], &sAM2301Sensorsdata[i]) != DATA_OK) { sAM2301Sensorsdata[i].ErrorCycle ++; } else { sAM2301Sensorsdata[i].ErrorCycle = 0; sAM2301Sensorsdata[i].SensorState = 0; } if (sAM2301Sensorsdata[i].ErrorCycle == AM2301_ERRORS_LIMIT) { sAM2301Sensorsdata[i].SensorState = 1; sAM2301Sensorsdata[i].ErrorCycle = 0; } } vTaskDelay(2000); } } void DHT_Task_Init(void) { xTaskCreate(vTaskDHT, "vTaskDHT", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL); } void TIM2_IRQHandler(void) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // gpio_invert_output(LED_GREEN); } void one_wire_delay_us(uint16_t time) { timer->CNT = 0; time -= 1; while (timer->CNT <= time) { ; } } void EXTI_IRQHandler(void) { static bool start_meas = false; static uint8_t cnt_bit = 0; // Checks whether the interrupt from EXTI0 or not if (EXTI_GetITStatus(EXTI_Line0) || EXTI_GetITStatus(EXTI_Line12)) { if(!dht_present) { cnt_bit = 0; if(new_hum_request) { start_meas = false; new_hum_request = false; } if (!start_meas) { timer->CNT = 0; start_meas = true; } else { if (timer->CNT >= 120){ dht_present = true; start_meas = false; timer->CNT = 0; } } } else { rawData[cnt_bit++] = timer->CNT; if (cnt_bit == 40){ dht_finish = true; } timer->CNT = 0; } // Clears the EXTI line pending bit EXTI_ClearITPendingBit(EXTI_Line0); EXTI_ClearITPendingBit(EXTI_Line12); } }