|
@@ -0,0 +1,284 @@
|
|
|
+#include "common_config.h"
|
|
|
+#include "stm32f4xx.h"
|
|
|
+#include "gpio.h"
|
|
|
+#include "AM2301.h"
|
|
|
+#ifdef PRINTF_STDLIB
|
|
|
+#include <stdio.h>
|
|
|
+#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) {
|
|
|
+ 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 {
|
|
|
+ printf("TEMP ERR\r\n\r\n");
|
|
|
+ return PARITY_ERR;
|
|
|
+ }
|
|
|
+ printf("TEMP = %.1f\r\n\r\n", data->temp);
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+}
|