Домашняя метеостанция

Тема в разделе "Флудилка", создана пользователем Cris, 11 авг 2014.

  1. Cris

    Cris Нуб

    Вот решил сделать метеостанцию с передачей по воздуху значений температуры и влажности. Но на текущий момент застрял на выведении на дисплей (при нажатии кнопки) показаний температуры и влажности. Дело в том что мне нужно задержаться на 5 секунд когда на дисплее показана влажность, а функция delay() не работает в прерываниях. Думал использовать таймеры, но даже не понял могут ли они такое делать. Нужна ваша помощь. Если что то я полный нуб и изучаю программирование две недели, буду признателен на подробное объяснение .

    Код (Text):
    // Подключаем библиотеки:
    #include <LiquidCrystal.h>
    #include "DHT.h"
    #include <WolfCrystal.h>


    volatile int state = LOW;


    //Определяем  датчик влажности и температуры
    #define DHTPIN 11
    #define DHTTYPE DHT11



    // Включаем дачик в 16 мгц режим ардуино
    DHT dht(DHTPIN, DHTTYPE);


    // обозначаем пины на которые подключён дисплей
    LiquidCrystal lcd(1, 3, 4, 5, 6, 7);

    // В конструкторе передаём указатель на ранее созданный
    // экземпляр LiquidCrystal:
    WolfCrystal WC(&lcd);



    // Описываем наши собственные символы в виде массивов битовых масок.
    enum { SYMBOL_HEIGHT = 8 };
    byte simG[SYMBOL_HEIGHT] =
    {
      B00100,
      B10101,
      B01110,
      B00100,
      B01110,
      B10101,
      B00100,
      B00000,
    };


    void setup() {
      pinMode(A0, OUTPUT); // устанавливаем 9 ногу как выход

      lcd.createChar(7, simG);
    //Влючаем пищалку на 0.2 сек
      digitalWrite(A0, HIGH);
      delay(200);
      analogWrite(A0, LOW);


      dht.begin();
      // обозначаем строки и рядки дисплея:
      lcd.begin(16, 2);
    // Используем прерывание на кнопку
      attachInterrupt(0, vlag, RISING);

    }


    void loop() {


      // Ожидаем пару секунд перед измерениями.
      delay(2000);

      // читаем температуру с дачика в цельсиях
      float t = dht.readTemperature();

    // Выводим надписи и температуру
      lcd.setCursor(0,0);
      lcd.print(WC.GS("  ТЕМПЕРАТУРА:") );
      lcd.setCursor(5,1);
      lcd.print(t);
      lcd.print(" C    ");
    }


    void vlag()
    {
      //выводим надписи и влажность
      lcd.clear();
      float h = dht.readHumidity();
      lcd.setCursor(3,0);
      lcd.print(WC.GS("ВЛА "));
      lcd.setCursor(6,0);
      lcd.write(7);
      lcd.print(WC.GS("НОСТЬ:    "));
      lcd.setCursor(5,1);
      lcd.print(h);
      lcd.print(" %");
     
       

        }
     
     
  2. acos

    acos Официальный гик Администратор

    Я бы посоветовал вам пока не использовать прерывания, тем более что в данном случае это и не нужно.
    Заведите пару переменных типа unsigned long и отправляйте туда текущее время. Типа такого должно получится
    Код (C):
    ......//где-то перед Setup
    unsigned long temperatureDelay =0;
    unsigned long buttonCheck =0;

    //тут должен был быть Setup и т.д и т.п

    void loop() {


      // Ожидаем пару секунд перед измерениями.
    //  delay(2000);
      if (millis()-temperatureDelay>=2000)
      {
      // читаем температуру с дачика в цельсиях
          float t = dht.readTemperature();

    // Выводим надписи и температуру
          lcd.setCursor(0,0);
          lcd.print(WC.GS("  ТЕМПЕРАТУРА:") );
          lcd.setCursor(5,1);
          lcd.print(t);
          lcd.print(" C    ");
       
         temperatureDelay=millis();
      }
      if (millis()-buttonCheck>=100)
      {
         buttonCheck = millis();
          if (!digitalRead(2))
         {
      //выводим надписи и влажность
              lcd.clear();
              float h = dht.readHumidity();
              lcd.setCursor(3,0);
              lcd.print(WC.GS("ВЛА "));
              lcd.setCursor(6,0);
              lcd.write(7);
              lcd.print(WC.GS("НОСТЬ:    "));
              lcd.setCursor(5,1);
              lcd.print(h);
              lcd.print(" %");
           
              delay(5000);
          }
      }
    }
     
     
    Последнее редактирование: 11 авг 2014
    Cris нравится это.
  3. Cris

    Cris Нуб

    Кстати в коде вы сделали опечатку и небольшую неточность. unsigned long нужно выводить перед функцией Setup, так как она потом будет недоступна нигде кроме Setup. С вашим вариантом нет долгих задержек и код работает быстрее.
    Подскажите пожалуйста как сделать так что бы при нажтии кнопки показывалась влажность, при следующем - температура и т.д. Планирую туда ещё и датчик атмосферного давления прилепить и что бы была всего 1 кнопка. То есть при каждом нажатии отображалась новая величина.
     
  4. acos

    acos Официальный гик Администратор

    Упс, да. Спасибо поправил. Это был не готовый код а размышления на тему, но вы и так всё верно поняли).
    Возможно такое решение вам подойдёт http://wiki.amperka.ru/конспект-arduino:кнопочный-переключатель
    Ну и вообще, посмотрите разные штучки тут http://wiki.amperka.ru/мини-проекты-arduino-breadboard:оглавление
    Можно ещё сделать меню, об этом тут http://forum.amperka.ru/threads/Библиотека-для-создания-Меню-на-дисплеях.1815/

    Да и вообще - посмотрите по форуму, много для себя найти сможете того, что можно было бы применить
     
  5. Cris

    Cris Нуб

    У меня появилась идея но есть небольшие уточнения.
    Создать два своих цикла void в которых буду инициализировать вывод температуры и влажности
    В основном цикле написать условие в котором при нажатии кнопки будет идти переход с одного цикла на другой.

    Нормальная идея? Если да, скажите как синтаксически использовать названия циклов в условии.
    Например:
    Код (Text):
    if (knopka == HiGH)
    {переходим к циклу влажности}
     
  6. acos

    acos Официальный гик Администратор

    void это не цикл, это функция которая ничего не возвращает. Аналог процедур в паскале, например. Когда мы пишем код функции, то перед её названием ставится тип того значения, которое она возвращает.
    Например
    Код (C):

    //функция вернёт площадь круга
    float circleArea(float radius)
    {
        return 3.14*radius*radius;
    }
     
    Вам же можно было бы завести переменную, в которой можно хранить текущее состояние, и потом проверять это состояние и выполнять соответствующую процедуру. Для случая двух состояний это будет предложенное вами решение

    Код (C):

    //где-то выше
    #define HUMID 0
    #define TEMP     1
    int state;
    //.....
    state = HUMID;
    //.....
    if (state == HUMID)
        showHumidity();
    else
        showTemperature();
    //.....
    //где-то далеко внизу
    void showHumidity()
    {
    }
    void showTemperature()
    {
    }
     
    Если состояний больше - например вам захочется выводить ещё и скорость ветра, то лучше воспользоваться конструкцией switch.
    Короче говоря рекомендую вам прочитать эту статью http://wiki.amperka.ru/программирование:конечный-автомат

    Ещё очень полезно было бы вообще прочитать для начала вот это http://wiki.amperka.ru/программирование:оглавление
    Для начала хватит, а дальше появятся другие вопросы)
     
    Cris нравится это.
  7. Cris

    Cris Нуб

    По мере расширения функционала, появились проблемы. У меня есть дисплей на который выводятся показания с различных датчиков. Так вот мне нужно сделать два действия на одну кнопку, то есть при нажатии без задержки производится одно действие, а про нажатии с задержкой другое. Подскажите пожалуйста как это реализовать, а то неделю уже мучаюсь.
     
  8. geher

    geher Гуру

    Для начала следует определиться со временем длинного и короткого нажатия и действием, если длительность нажатия оказалась между этими величинами: ничего, действие по короткому нажатию, какое-то третье действие.
    Есть два варианта.
    1. Сделать одно действие при самом нажатии. Дождаться отпускания, периодически проверяя состояние кнопки. Если к моменту истечения времени длинного нажатия кнопка все еще нажата, выполнить второе действие, после чего вывесить флаг, что действие произошло, и сбросить его при отпускании кнопки.
    Это годится, если первое действие не влияет существенно на поведение прибора, например, включение подсветки.
    Примерно так:
    Код (Text):
    #define LONG_PRESS_TIME 3000
    unsignrd long int buttonPressTime;
    int buttonState=0; // 0 - ждем нажатия, 1- ждем отпускания и времени длинного нажатия, 2 - ждем отпускания
    void loop()
    {
      int buttonPressed;
      ... // определение состояния кнопки тем или иным способом (прямое чтение с пина, прерывание)
      if (buttonPressed) {
        switch(state) {
          case 0:
              buttonState=1;
              buttonPressTime=millis();
              // действия по короткому нажатию
              ...
              break;
          case 1:
              if (millis()-buttonPressTime>=LONG_PRESS_TIME) {
                 buttonState=2;
                 // действия по длинному нажатию
                 ...
              }
              break;
        }
      } else {
        buttonState=0;
      }
    }
    2. Засечь факт нажатия кнопки. Дождаться отпускания. Если время нажатия меньше короткого - выполнить одно действие. Ждать до истечения длинного действия или отпускания. Если время длинного нажатия произошло до отпускания, то выполнить второе действме.
    Примерно так:
    Код (Text):
    #define LONG_PRESS_TIME 3000
    #define SHORT_PRESS_TIME 100
    unsignrd long int buttonPressTime;
    int buttonState=0; // 0 - ждем нажатия, 1- ждем отпускания и времени длинного нажатия, 2 - ждем отпускания
    void loop()
    {
      int buttonPressed;
      ... // определение состояния кнопки тем или иным способом (прямое чтение с пина, прерывание)
      if (buttonPressed) {
        switch(state) {
          case 0:
              buttonState=1;
              buttonPressTime=millis();
              break;
          case 1:
              if (millis()-buttonPressTime>=LONG_PRESS_TIME) {
                 buttonState=2;
                 // действия по длинному нажатию
                 ...
              }
              break;
        }
      } else {
        buttonState=0;
        if (millis()-buttonPressTime<SHORT_PRESS_TIME) {
           // действия по короткому нажатию
           ...
        } else {
           if (buttonState==1) {
              // действия по нажатию длительностью между коротким и длинным
              ...    
           }
        }
      }
    }
     
    Последнее редактирование: 21 сен 2014
    Cris нравится это.