Снова светодиод и кнопка)

Тема в разделе "Arduino & Shields", создана пользователем Suro, 20 окт 2017.

  1. Suro

    Suro Нерд

    есть 2 кнопки и светодиод))

    при нажатии кнопка1 пусть светодиод загарается,если кнопка1 нажата более 10секунд без кнопка2 пусть светодиод выклюяиться.А если двое нажаты пусть загарается столько сколько нажаты,но если некоторое время выключить кнмопка2 через 10сек пусть выключиться.

    не могу дописывать скетч

    Код (C++):
    int switchPin1 = 9;
    int switchPin2 = 10;
    int ledPin = 11;
    int interval;
    void setup()
    {
      pinMode(switchPin1, INPUT);
      pinMode(switchPin2, INPUT);
      pinMode(ledPin, OUTPUT);
    }

    void loop(){
      if (digitalRead(switchPin1) == HIGH){
        interval = millis();
        digitalWrite(ledPin,HIGH);
        if (interval - millis()<10000)
        digitalWrite(ledPin,LOW);
       
    }
     
  2. DIYMan

    DIYMan Guest

    Алгоритм:

    1. Если кнопка 1 нажата - включить светодиод;
    2. Если кнопка 1 нажата 10 секунд, и при этом кнопка 2 не нажата - выключить светодиод;
    3. Если нажаты обе кнопки - включить светодиод, выключить его через 10 секунд после того, как кнопка 2 становится не нажатой.

    Всё верно? Навскидку как-то так, без проверки в железе:
    Код (C++):
    typedef enum
    {
        msIdle,
        msWaitFor10Seconds,
        msWaitForIdle,
       
    } MachineState;


    MachineState state;
    unsigned long timer;

    void setup()
    {
        state = msIdle;
    }


    void loop()
    {
       switch(state)
       {
           case msIdle: // исходный режим, ждёт нажатия на кнопки
           {
               bool b1pressed = button1.isPressed(); // нажата ли кнопка 1?
             
               if(b1pressed) // если да, то
               {
                   turnDiodeOn(); // включаем светодиод
                   timer = millis(); // запоминаем время включения
                   state = msWaitFor10Seconds; // переходим на ожидание отжатия кнопки 1
               }
           }
           break;
         
           case msWaitFor10Seconds: // ждём ожидания отжатия кнопки 1
           {
               bool b1pressed = button1.isPressed(); // нажата ли кнопка 1?
               bool b2pressed = button2.isPressed(); // нажата ли кнопка 2?
             
               if(b1pressed) // если кнопка 1 нажата - проверяем, не истекло ли 10 секунд
               {
                   if(millis() - timer > 10000) // если истекло, то
                   {
                    turnDiodeOff(); // выключаем светодиод
                    state = msWaitForIdle; // переключаемся на ожидание отжатия кнопки 1, чтобы сразу не сработать повторно
                   }
                 
                   if(b2pressed) // вместе с кнопкой 1 нажата кнопка 2
                   {
                       timer = millis(); // обновляем таймер
                   }
               }
               else // иначе (кнопка уже не нажата) - переключаемся в режим ожидания
               {
                  state = msIdle;
               }
                 
           }
           break;
         
           case msWaitForIdle:
           {
               if(!button1.isPressed())
                   state = msIdle;
           }
           break;
       }  
    }
     
  3. Suro

    Suro Нерд


    Алгоритм очень правильный но почему то не работает
     
  4. DIYMan

    DIYMan Guest

    Выясняйте, почему - не вопрос. За вас никто делать не будет. Я дал старт, никто законченного решения не обещал. Откуда я знаю, что у вас там творится - может, банально на макетке контакт плохой.

    Могу написать скетч, с демонстрационным видео - 500 рублей, не вопрос. И будет у вас всё работать ;) То, что я писал выше - я даже не компилировал, навскидку набросал, лишь как демонстрацию возможного подхода.
     
  5. Suro

    Suro Нерд

    в любом случае спосибо)
     
  6. fogary

    fogary Гик

    В коде DIYMan-а часть кода опущена, Вы его дописали или использовали "как есть"?
     
  7. akl

    akl Гуру

    алгоритм не до конца продуман, но думаю так можно набыдлить

    Код (C++):

    bool button1 = digitalRead(BUTTON1_PIN); //считываются состояния кнопок и лампочки
    bool button2 = digitalRead(BUTTON2_PIN);
    bool led = digitalRead(LED_PIN);
      bool button1_on; //флаг нажатия кнопки 1


       if(button1 && !button1_on) {  //если кнопка1 нажата, но флаг что она была нажата не стоит
         button1_on = 1; //ставим флаг что кнопка нажата
         delay(20);  //ждем 20мс чтоб дребезг ушел
         button1 = digitalRead(BUTTON1_PIN); //проверяем нажата ли кнопка все еще
         if(button1){  //если таки нажата
         timer = millis(); //засекаем текущее время, т.к. в изначальном условии есть флаг -
                               //оно засечется только в момент нажатия на кнопку
         if(!led){digitalWrite(LED_PIN,HIGH);} //если лампочка не горит, то зажигаем ее
         }}
       if(!button1 && button1_on) {button1_on=0;} // если кнопка отжата - снимаем флаг нажатия кнопки



       if(button2 && led){  //а тут тупо каждый цикл пока зажата кнопка 2 при горящем леде
         timer = millis();  //будет обновляться время в таймере
         }

       if(led && millis()-timer>10000){ // если лампочка горит и время не обновлялось более 10с
          digitalWrite(LED_PIN,LOW); //выключаем лампочку
          }
    не проверял, но вроде должно работать так:
    когда нажимается кнопка 1 - зажигается лед и если не была нажата вторая кнопка и не была повторно снова нажата первая (то есть ее либо непрерывно держат нажатой либо отпустили и больше не трогают) - тухнет через 10 секунд с момента нажатия
    если пока лед горит (то есть на кнопку 1 нажали меньше чем 10 секунд назад) нажали кнопку2, то лед погаснет через 10 секунд после того как кнопку 2 отпустят и не будут больше трогать.
    если просто тыкать кнопку 2 при негорящем леде, то ниче не будет.

    тащемта, я считаю, что отсутствие в ардуиноИДЕ дебаггера-симулятора - это преступление

    тупо копировать этот код не советую, т.к. даже если он теоретически работает - в нем опечатки есть (несколько только что исправил)
     
    Последнее редактирование: 20 окт 2017
  8. qwone

    qwone Гик

    Алгоритм идиотский. Вот представьте у вас общее освешение в комнате 1) если нажать на кнопку , то освещение включится. 2) если нажать на кнопку , спеть "Чунга-Чанга" и снять кепочку, то освещение выключиться 3) а вот если нажать на кнопочку а второй рукой нажать на шнобель, то освещение выклются через 10 секунд. И так вопрос , как выглядит из хозяин в глазах гостей если у него стоит такая система на освещении. Думаю перед тем как составлять алгоритм надо немного подумать , а не открывать тему на форуме.
     
  9. akl

    akl Гуру

    раз уж ТСа начали троллить
    рабочий вариант на ЧистомСи™
    Код (C++):
    #include <avr/io.h>
    #define F_CPU 8000000UL
    #include <avr/interrupt.h>
    #include <util/delay.h>

    #define setH(port,bit)  do{port |= (1 << bit);}while(0)
    #define setL(port,bit)  do{port &= ~(1 << bit);}while(0)
    #define readP(reg,bit)    (reg & (1 << bit))


    #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
    //millis
    #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
    #define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
    #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
    #define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
    #define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
    #define FRACT_MAX (1000 >> 3)
    volatile unsigned long timer0_overflow_count = 0;
    volatile unsigned long timer0_millis = 0;
    static unsigned char timer0_fract = 0;


    typedef struct pin_t
    {
        volatile uint8_t *port;
        uint8_t bit;
    }Pin;

    Pin Pin0 = {&PORTB, 1<<0};
    Pin Pin1 = {&PORTB, 1<<1};


    Pin* PinArray[] = {
    &Pin0,
    &Pin1
    };
    #define allpins 2
    #define Led 0


    #define Led_port PORTB
    #define Led_reg PINB
    #define Led_bit 0
    #define Butt1_port PORTB
    #define Butt1_reg PINB
    #define Butt1_bit 2
    #define Butt2_port PORTB
    #define Butt2_reg PINB
    #define Butt2_bit 3

    uint8_t button1;
    uint8_t button2;
    uint8_t button1_on;
    uint8_t button2_on;
    uint8_t led;
    unsigned long timer;


    void WritePin_on(uint8_t num)
    {
      Pin* pin = PinArray[num];
      *pin->port |= pin->bit;
    }

    void WritePin_off(uint8_t num)
    {
      Pin* pin = PinArray[num];
      *pin->port &= ~pin->bit;
    }

    void WritePin(uint8_t num, uint8_t val)
    {
      Pin* pin = PinArray[num];
      if (val==0){*pin->port &= ~pin->bit;}
      else {*pin->port |= pin->bit;}
    }



    ISR(TIMER0_OVF_vect){
        unsigned long m = timer0_millis;
        unsigned char f = timer0_fract;
        m += MILLIS_INC;
        f += FRACT_INC;
        if (f >= FRACT_MAX) {
            f -= FRACT_MAX;
            m += 1;}
        timer0_fract = f;
        timer0_millis = m;
        timer0_overflow_count++;}

    unsigned long millis(){
        unsigned long m;
        uint8_t oldSREG = SREG;
        SREG &= ~(0b10000000);
        m = timer0_millis;
        SREG = oldSREG;
        return m;}




    int main(void) {

    DDRB=0b00000001;
      SREG |= (1<<7);

      TCCR0 = 0b00000011;
      TIMSK |= (1<<0);



    while (1==1) {
       button1 = readP(Butt1_reg,Butt1_bit);
       button2 = readP(Butt2_reg,Butt2_bit);
       led = readP(Led_reg,Led_bit);
     
       if(button1 && !button1_on) {
         button1_on = 1;
         _delay_ms(20);
         button1 = readP(Butt1_reg,Butt1_bit);
         if(button1){
         timer = millis();
         if(!led){WritePin(Led,1);}
         }}
       if(!button1 && button1_on) {button1_on=0;}



       if(button2 && led){
         timer = millis();
         }

       if(led && (millis()-timer)>10000){
          WritePin(Led,0);
          }
     
       _delay_ms(10);
     
        }
         

    return 0;}
    только для атмега8

    просто я хотел проверить работает ли предложенный мной вариант, а в ардуино симулятора нету [​IMG]
     
    Последнее редактирование: 20 окт 2017
  10. akl

    akl Гуру

    алгоритм недодуманый, но насколько я понял - одна кнопка это типа разовое включение и активация второй, а вторая кнопка - перманентное продление. вполне может быть применен к чему-то хз к чему.
     
  11. qwone

    qwone Гик

    aki, вы просто представьте это. Вы должны держать кнопку 10 секунд , при этом держать или не дежать другую, что бы выключить свет. А вот если держать к примеру 9 минут , а на второй отбивать морзянку, то разумеется ничего не должно получится. Так что проблема не в анализе вариантов когда что-то должно сработать, а в отсечке вариантов когда это сработать не должно ни в каком случае. А таких вариантов ТС сделал дофига в своем недоалгоритме.
     
  12. akl

    akl Гуру

    думаю надо чтобы ТС написал какая в принципе общая сверхзадача должна выполняться его алгоритмом (если оная есть)
     
  13. Suro

    Suro Нерд

    Честно говоря использовалл "как есть"
     
  14. Suro

    Suro Нерд

    Есть у меня две кнопки и нужно после обнуления таймера выключить светодиод.


    0 0 - отжаты: светодиод выключен, 10 сек таймер обнулен

    1 0 - кнопка1 нажата: включить светодиод и запустить 10 сек таймер. Если кнопка1 нажата более 10сек,выключить светодиод и обнулить таймер.Если нажата кнопка1 менее 10сек (например таймер = 8сек) и нажимаем кнопка2 - обнулить таймер (включить таймер тогда когда отпустили кнопка2 (внизу в примере тоже самое) ).

    1 1 - кнопка1 и кнопка2 нажаты: пусть светодиод загарается столько сколько нажаты.Если в этом состоянии выключить кнопка2,включить 10сек таймер.

    0 1 - кнопка2 нажата: никаких действий.

    Извените но не знаю смог ли правильно создать алгоритм.
     
  15. Airbus

    Airbus Радиохулиган Модератор

    Чисто так для общего развития.
     
  16. Suro

    Suro Нерд

    Есть у меня две кнопки и нужно после обнуления таймера выключить светодиод.

    0 0 - отжаты: светодиод выключен, 10 сек таймер обнулен

    1 0 - кнопка1 нажата: включить светодиод и запустить 10 сек таймер.

    Если 1 0 состояние менее 10сек - светодиод горит и таймер запущен.
    Если 1 0 состояние более 10сек - светодиод отключается и таймер обнуляется.

    Если 1 0 состояние стало 1 1 до 10сек - светодиод оставается вкл и таймер обнуляется (горит столько сколько обе нажаты).
    Если 1 0 состояние стало 1 1 после 10сек - светодиод включается а таймер оставается обнуленным.

    1 1 - кнопка1 и кнопка2 нажаты: светодиод горит и таймер обнулен.

    Если 1 1 состояние стало 1 0 - таймер включается и после 10сек светодиод выключается.
    Если 1 1 состояние стало 0 1 - светодиод отключается и таймер обнуляется.

    0 1 - светодиод выключен, 10 сек таймер обнулен.

    Если 0 1 состояние стало 0 0 - светодиод выключен, 10 сек таймер обнулен(тоест ничего не делать).
    Если 0 1 состояние стало 1 1 - светодиод включается а таймер оставается обнуленным.

    По моему так выглядит алгоритм
     
  17. akl

    akl Гуру

    я правильно понял, что при нажатии кнопки1 неважно сколько времени ее держат в нажатом состоянии, и светодиод должен погаснуть через 10 секунд с момента надавливания на эту кнопку (если другую кнопку не трогали)? то есть при отпускании 1 кнопки ничего не происходит? тогда мой пример должен подходить вроде по всем параметрам

    ну и под общей сверхзадачей я имел в виду - что конкретно в реальном мире должно делать это устройство, кроме как зажигать абстрактный светодиод? что это будет? подсветка в сортире? охранная сигнализация? пульт управления чем-то?
     
  18. akl

    akl Гуру

    или все таки про отпускании 1 кнопки светодиод должен тут же погаснуть (даже если вторую держат)
    если так, то надо просто добавить отключение светодиода при отжатии кнопки

    Код (C++):
    bool button1 = digitalRead(BUTTON1_PIN); //считываются состояния кнопок и лампочки
    bool button2 = digitalRead(BUTTON2_PIN);
    bool led = digitalRead(LED_PIN);
      bool button1_on; //флаг нажатия кнопки 1


       if(button1 && !button1_on) {  //если кнопка1 нажата, но флаг что она была нажата не стоит
         button1_on = 1; //ставим флаг что кнопка нажата
         delay(20);  //ждем 20мс чтоб дребезг ушел
         button1 = digitalRead(BUTTON1_PIN); //проверяем нажата ли кнопка все еще
         if(button1){  //если таки нажата
         timer = millis(); //засекаем текущее время, т.к. в изначальном условии есть флаг -
                               //оно засечется только в момент нажатия на кнопку
         if(!led){digitalWrite(LED_PIN,HIGH);} //если лампочка не горит, то зажигаем ее
         }}
       if(!button1 && button1_on) {button1_on=0;
    digitalWrite(LED_PIN,LOW);} // если кнопка отжата - снимаем флаг нажатия кнопки
    //и отключаем лампочку



       if(button2 && led){  //а тут тупо каждый цикл пока зажата кнопка 2 при горящем леде
         timer = millis();  //будет обновляться время в таймере
         }

       if(led && millis()-timer>10000){ // если лампочка горит и время не обновлялось более 10с
          digitalWrite(LED_PIN,LOW); //выключаем лампочку
          }
    не очень понятно что будет если при удерживании 2ой кнопки туда-сюда нажимать и отпускать первую много раз, но тестировать лень, т.к. непонятен смысл зачем это все вообще
     
    Последнее редактирование: 21 окт 2017
  19. Suro

    Suro Нерд

    Да вы правильно поняли. А какой пример тот что только для атмега8?

    Это не отдельное что то,маленький нюанс с проекта)
     
  20. Suro

    Suro Нерд


    Если 1 0 состояние менее 10сек - светодиод горит и таймер запущен.
    Если 1 0 состояние более 10сек - светодиод отключается и таймер обнуляется.

    Если 1 0 состояние стало 1 1 до 10сек - светодиод оставается вкл и таймер обнуляется (горит столько сколько обе нажаты).
    Если 1 0 состояние стало 1 1 после 10сек - светодиод включается а таймер оставается обнуленным.

    т.е.
    если кнопка1 нажата без кнопка2 в течении 10сек - при отжатии выключается и таймер обнуляется.
    если кнопка1 и кнопка2 нажаты,светодиод горит, то при отжатии кнопка1 - выключить светодиод и таймер обнуляеть.