И кнопка, и цифровой выход на одном пине

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем Salk, 25 янв 2015.

  1. Salk

    Salk Гик

    Тогда действительно странно. Да, подключено все верно, DIP корпус, в макетку воткнул, пару проводов и несколько резисторов, несколько раз все перепроверил.
    Дело в том, что эти "3.75 В" Arduino читаются как лог. "1" (HIGH), но если мерить мультиметром на самой 5 ноге (VPIN), там напряжение около 100 мВ, если отключить VPIN от arduino, 3.75 В и будут. Но это ведь не так страшно, т.к. VPIN все равно меньше VREF, не должно же мешать работе компаратора? Как только с arduino приходит HIGH уровень, на VPIN появляются +5 В, как и положено, но на выходе компаратора все равно ничего нет. Я даже и без Arduino подключал компаратор, на VPIN +5 V; VREF +2.5 V и ничего. Как ещё можно проверить работоспособность компаратора, может с ним, что не так?
    Попробую подать напряжение побольше или компаратор заменить, может номиналы резисторов взять меньше в районе 10-50 кОм ?
     
  2. Unixon

    Unixon Оракул Модератор

    Кажется, я забыл один момент. У компаратора LM339 выход - это открытый коллектор, его нужно подтягивать к +5V, например, через тот же 10к-50к резистор.
     
    Salk нравится это.
  3. Salk

    Salk Гик

    Фуф, спасибо Unixon :) Действительно Вы правы, подтягивающий резистор был необходим.
    Все заработало, только пришлось немного номиналы резисторов подправить, когда на VREF было ~4.6 В, а на VPIN +5 В, то компаратор никак не реагировал, видимо для него разница в ~0.4 В не существенная. Пришлось вместо R4 100 кОм, поставить 10 кОм, напряжение упало до +2.5 В и вот тогда компаратор заработал. Подтягивающий резистор на выход поставил 1 кОм, но его можно менять в больших пределах. На VPIN в режиме "INPUT" по прежнему около 0 В, в итоге на практике получилось:
    "0" = VCC(5V) > VREF(2.5V) > VPIN(100 mV) > GND; "1" = GND < VREF(2.5V) < VPIN(5V) <= VCC(5V)

    Теперь остался скетч привести в нормальный вид. Чуть позже займусь им вплотную.
     
    Последнее редактирование: 4 фев 2015
  4. Salk

    Salk Гик

    Всё хорошо, да вот только скетч не могу написать :oops: Никак не возьму в толк, как мне кнопку без фиксации реализовать в скетче. Т.к. если использовать кнопку с фиксацией, то не получится управлять с пульта. Нужно подавать "HIGH" на VPIN после того, как отпустили кнопку.
    По идее нужно реализовать счетчик, который бы "отлавливал" два нажатия на кнопку без фиксации ("0"=>"1"=>"0"), после того, как мы её нажмем и отпустим, т.е. одно кратковременное нажатие - включили реле, второе - выключили реле. По разному пытался, больше запутался только.
    Подскажите, пожалуйста, верный путь :)
     
  5. X-Dron

    X-Dron Гик

    Попробуй так
    Код (Text):
    boolean Relay, Old_Key;

    void setup() {
      pinMode(13, OUTPUT);
      pinMode(10, INPUT);
      Old_Key:=  digitalRead(10); //Считанное с пина состояние клавиши, здесь без фильтрации;
    }

    void loop() {
        if (Key && !Old_Key) Relay = ! Relay;
        digitalWrite(13, Relay);
        Old_Key:=Key;
    }
    Key это фильтрованное от дребезга состояние кнопки. Методов фильтрации много. Есть библиотеки, есть пример "Debounce" в Файл -> Примеры -> 0.2 Digital -> Debounce.
    Ловим фронт изменения сигнала и меняем состояние Relay на противоположное.
     
  6. Unixon

    Unixon Оракул Модератор

    Не, 0.4V это довольно много. Сравните "input bias current" и ток через делитель. Как они соотносятся?
     
  7. altex

    altex Гик

    Да он просто не rail-to-rail, поэтому 4.5В от 5В на входах может не отличаться при питании 5В.
     
  8. Unixon

    Unixon Оракул Модератор

    Фу, забыл совсем. Тогда TS862, TLV2302 например.
     
  9. Salk

    Salk Гик

    X-Dron
    Нет, не подойдет. Вы не поняли, задумка повесить на один пин Arduino и кнопку и, к примеру, реле. На основе постоянного изменения состояния пина INPUT/OUTPUT. Проблема у меня, состояла в том, что я не мог "доказать" arduino, что второе нажатие кнопки это не одно и тоже, что и первое. :)

    Да были кое-какие "танцы" с номиналами резисторов, но в итоге я все же добился своего, как мне кажется. И LM339 неплох :)

    На VREF вместо постоянных резисторов посадил переменный на 20 кОм, а на VPIN подал +3.75 В, и искал то напряжение, при котором на выходе компаратора будет "0". Нашел им оказалось 3.9 В не меньше, но и не больше 4.2 В. Резисторы R4 и R3 подобрал такие - R4 - 33k, R3 = 10k, напряжение на VREF около 3.9 В.
    VPIN оставил без изменений: R2 - 150k, R1 - 50k (3.75V). Тем самым получилось:
    "0" = GND < VPIN (3.75 V) < VREF (3.9 V) < VCC (5 V);
    "1" = VCC (5 V) >= VPIN (5 V) > VREF (3.9 V) > GND.

    А теперь скетч. У меня таки получилось реализовать свою задумку :) Чтобы различить второе нажатие от первого, сделал одно короткое нажатие, второе более длительное. Не знал, что ещё придумать.
    Код (Text):
    #include <IRremote.h>

    int RECV_PIN = 11; // пин подключения IR приёмника
    int RELAY_PIN = 3; // пин подключения реле, обязательно к ШИМ

    IRrecv irrecv(RECV_PIN);
    decode_results results;

    bool LampState = false;
    int STATE; // текущее состояние пина
    int BUTTON; // счетчик нажатия кнопки
    int f; // первое нажатие
    int p; // второе нажатие

    void setup()
    {
      pinMode(RELAY_PIN, INPUT); // Реле и кнопка одновременно
      pinMode(RECV_PIN, INPUT); // ИК-приемник
      irrecv.enableIRIn(); // Включаем ресивер
      Serial.begin(9600);
    }

    void loop()
    {
      // необходимо использовать кнопку без фиксации !!!
      pinMode(RELAY_PIN, INPUT); // постоянно проверяем состояние пина
      STATE = digitalRead(RELAY_PIN); // проверяем состояние пина каждый раз и запоминаем

      if (BUTTON > 10 && BUTTON < 50) // Учим МК различать нажатия по времени их нажатия
      {
        f = 1; // первое нажатие
        p = 0;
        BUTTON = 55;
      }

      if (BUTTON > 75)
      {
        p = 1; // второе нажатие
        f = 0;
        BUTTON = 0;
      }

      if (STATE == HIGH) // кнопка не нажата (ничего не делаем)
      {
        Serial.print("<< NOT PRESS >>");
        Serial.print("          ");
        Serial.print(BUTTON);
        Serial.print("      ");
        Serial.print("f = ");
        Serial.print(f);
        Serial.print("      ");
        Serial.print("p = ");
        Serial.print(p);
        Serial.print("      ");
        Serial.print("HIGH");
        Serial.print("      ");
        Serial.println(results.value);
      }
      else // Иначе кнопку нажали, т.е. "поймали" LOW
      {
        BUTTON = BUTTON + 1; // накручиваем счетчик
        Serial.print("<< PRESS >>");
        Serial.print("          ");
        Serial.print(BUTTON);
        Serial.print("      ");
        Serial.print("f = ");
        Serial.print(f);
        Serial.print("      ");
        Serial.print("p = ");
        Serial.print(p);
        Serial.print("      ");
        Serial.print("LOW");
        Serial.print("      ");
        Serial.println(results.value);
      }

      if (f == 1) // Если нажали один раз, то включаем реле, а так же можем выключить с пульта
      {
        pinMode(RELAY_PIN, OUTPUT);
        digitalWrite(RELAY_PIN, HIGH);

        if (irrecv.decode(&results))
        {
          if (results.value == 524543)
          {
            f = 0;
            p = 1;
          }
          irrecv.resume();
        }
      }

      if (p == 1) // Если нажали второй раз, то выключаем реле, а так же можем включить обратно
      {
        pinMode(RELAY_PIN, OUTPUT);
        digitalWrite(RELAY_PIN, LOW);

        if (irrecv.decode(&results))
        {
          if (results.value == 524543)
          {
            p = 0;
            f = 1;
          }
        }
        irrecv.resume(); // Получаем следующее значение
      }

    if (p == 0 && f == 0) // начальное состояние
      {
        if (irrecv.decode(&results))
        {
          if (results.value == 524543) // можем вкл/выкл с пульта
          {
            LampState = !LampState;
            if (LampState)
            {
              p = 0;
              f = 1;
            }
            else
            {
              p = 1;
              f = 0;
            }
          }
          irrecv.resume(); // Получаем следующее значение
        }
      }
      delay(100);
      /* скорость проверки состояния пина (к выходу компаратора, на тест, подключил светодиод).
      С такой скоростью он заметно мерцает, но реле будет управляться транзистором, на базу которого
      можно поставить сглаживающий конденсатор (100-470 мкФ), что позволит реле сохранять всегда
      устойчивое состояние */
    }
    Счетчик нажатий сделал на "псевдо счетчике", т.е. когда кнопка зажата (LOW) у нас набегает счетчик (каждый раз прибавляя по 1), но мы знаем, если будем удерживать около 1 сек, то у нас включится реле, если дольше, то выключится. Можно в дальнейшем будет реализовать на LCD дисплее подсказку, когда реле будет готово выключится и можно отжать кнопку.
    Так же в скетче реализовано управление, того же реле, с ИК-пульта. Никаких сбоев в работе нет. Если включили реле с кнопки, то можем его выключить с пульта, и наоборот.

    Для теста, на выход компаратора поставил светодиод, единственное, что при delay(100), светодиод заметно мерцает, но это понятно, у нас на VPIN раз в 100 мс постоянно либо HIGH, либо LOW. Но я думаю это можно будет подправить сглаживающим конденсатором, либо увеличить время обновления. Конечно скетч "груб" и его нужно ещё шлифовать, но в основном все работает :)
    Если есть другой способ, как различать два нажатия между собой, я буду только рад.

    К сожалению не на что сделать фото своего "безобразия" на макетке.
    Вот что творилось в Serial при различных сценариях:
     

    Вложения:

    • 54dgfs.jpg
      54dgfs.jpg
      Размер файла:
      205 КБ
      Просмотров:
      574
    • 49154.jpg
      49154.jpg
      Размер файла:
      183,5 КБ
      Просмотров:
      585
    • 2121234.jpg
      2121234.jpg
      Размер файла:
      187,9 КБ
      Просмотров:
      595
    • safas2.jpg
      safas2.jpg
      Размер файла:
      195,2 КБ
      Просмотров:
      603
    Последнее редактирование: 5 фев 2015
  10. Salk

    Salk Гик

    Эксперименты продолжаются. Отладил немного скетч, отвязался от delay();
    Код (Text):
    #include <IRremote.h>

    int RECV_PIN = 11; // пин подключения IR приёмника
    int RELAY_PIN = 3; // пин подключения реле и кнопки, обязательно к ШИМ

    IRrecv irrecv(RECV_PIN);
    decode_results results;

    bool LampState = false;

    #define RELAY_UPDATE_TIME  150 // частота опроса пина
    unsigned long RelayLastUpdateTime = 0;

    int STATE; // текущее состояние пина
    int BUTTON; // счетчик нажатия кнопки
    int f; // первое нажатие
    int p; // второе нажатие

    void setup()
    {
      pinMode(RELAY_PIN, INPUT); // Реле и кнопка одновременно
      pinMode(RECV_PIN, INPUT); // ИК-приемник
      irrecv.enableIRIn(); // Включаем ресивер
      Serial.begin(9600);
    }

    void loop()
    {
      // необходимо использовать кнопку без фиксации !!!
      pinMode(RELAY_PIN, INPUT); // постоянно проверяем состояние пина
      STATE = digitalRead(RELAY_PIN);
      if (BUTTON == 1) // Одно нажатие - вкл. реле, второе - выключили
      {
        LampState = !LampState;
        if (LampState)
        {
          f = 1; // включаем реле с кнопки
          p = 0;
          BUTTON = 0;
        }
        else // или выключаем, если нажали на кнопку
        {
          f = 0;
          p = 1;
          BUTTON = 0;
        }
      }
      if (millis() - RelayLastUpdateTime > RELAY_UPDATE_TIME)
      {
        /* скорость проверки состояния пина */
        RelayLastUpdateTime = millis();
        if (STATE == HIGH) // кнопка не нажата (ничего не делаем)
        {
          Serial.print("<< NOT PRESS >>");
          Serial.print("          ");
          Serial.print(BUTTON);
          Serial.print("      ");
          Serial.print("f = ");
          Serial.print(f);
          Serial.print("      ");
          Serial.print("p = ");
          Serial.print(p);
          Serial.print("      ");
          Serial.print("HIGH");
          Serial.print("      ");
          Serial.println(results.value);
        }
        else // Иначе кнопку нажали, т.е. "поймали" LOW
        {
          BUTTON = 1; // если поймали момент нажатия кнопки (LOW)
          Serial.print("<< PRESS >>");
          Serial.print("          ");
          Serial.print(BUTTON);
          Serial.print("      ");
          Serial.print("f = ");
          Serial.print(f);
          Serial.print("      ");
          Serial.print("p = ");
          Serial.print(p);
          Serial.print("      ");
          Serial.print("LOW");
          Serial.print("      ");
          Serial.println(results.value);
        }
      }
      if (f == 1) // Если нажали один раз, то включаем реле, а так же можем выключить с пульта
      {
        pinMode(RELAY_PIN, OUTPUT);
        digitalWrite(RELAY_PIN, HIGH);
        if (irrecv.decode(&results))
        {
          if (results.value == 524543)
          {
            f = 0;
            p = 1;
          }
          irrecv.resume();
        }
      }
      if (p == 1) // Если нажали второй раз, то выключаем реле, а так же можем включить обратно
      {
        pinMode(RELAY_PIN, OUTPUT);
        digitalWrite(RELAY_PIN, LOW);
        if (irrecv.decode(&results))
        {
          if (results.value == 524543)
          {
            p = 0;
            f = 1;
          }
          irrecv.resume(); // Получаем следующее значение
        }
      }
      if (p == 0 && f == 0) // начальное состояние. Вкл/выкл реле с пульта
      {
        if (irrecv.decode(&results))
        {
          if (results.value == 524543)
          {
            p = 0;
            f = 1; // включить реле
          }
          irrecv.resume(); // Получаем следующее значение
        }
      }
    }
    Все работает - и с пульта управляет, и с кнопки включается/выключается.
    Но вот добиться постоянного уровня сигнала с выхода компаратора, а не импульсного, как это сейчас: _|-|_|-|_ , частота которого зависит от частоты опроса пина Arduino, пока не выходит, а это постоянное переключение реле. С выхода LM339 удается получить только 1.2 В, маловато для полного открытия транзистора BC550, коммутирующий реле. Конденсатор не спасает, при подключении оного напряжения и вовсе сильно падает, менее 0.5 В, подключенный светодиод не горит.
    Может, если компаратор запитать, к примеру, от +15 В, возможно ли на выходе получить больше 8 В ? После на выход поставить линейный стабилизатор напряжение (L7805) на 5 В ? Или что ещё можно предпринять для сглаживания импульсов ?
     
  11. Unixon

    Unixon Оракул Модератор

    Если вы постоянно дергаете ногу на вход-выход, делайте это быстро.
    В начале loop сразу
    Код (Text):

    pinMode(RELAY_PIN, INPUT);
    input_state = digitalRead(RELAY_PIN);
    pinMode(RELAY_PIN, OUTPUT);
    digitalRead(RELAY_PIN, output_state);
     
    а потом весь остальной код. Вместо непосредственного переключения выхода, меняйте только output_state, а на следующий круг оно уже само выставится на ногу. Так у вас провалы на опрос кнопки будут очень короткие, их легко сгладить емкостью. Сейчас это не получается из-за большой скважности, потому, что у вас опрос кнопки замедляется кучей других процессов.

    Если это без осреднения, то подтяжку поменьше поставьте. Хотя сдается мне, что это следствие предыдущей проблемы