Переход с аналоговых кнопок на цифровые, помогите!

ty
Offline
Зарегистрирован: 15.06.2015

Клапауций 999 пишет:

ty пишет:

Я не понимаю как программа понимает, что input 3 это именно BUTTON_00 ?  Какая строчка из примера это описывает?

ты считываешь состояние пина 3 в локальную переменную nb00 

boolean nb00 = digitalRead(3);

если это состояние изменилось

if (nb00 != b00) {}

то, что-то делаешь

что бы это делать один раз, то обновляешь переменную состояния пина

b00 = nb00;

далее, что-то делаешь при нажатии или отпускании

 

Спасибо, уже понял. Но почему дребезг не будет обработан как многократное нажатие/отпускание?

Клапауций 999
Offline
Зарегистрирован: 06.06.2015

ty пишет:

Но все разво не понимаю, почему не будет обработам дребезг контактов как многократное нажатие отпускание?

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

ty
Offline
Зарегистрирован: 15.06.2015

Клапауций 999 пишет:

ty пишет:

Но все разво не понимаю, почему не будет обработам дребезг контактов как многократное нажатие отпускание?

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

Спасибо, буду пробовать, значит фактическ избавится от дребезга можно или delay (останавливая процессор) или конденсатором?

Мне собственно только нажати надо, но почему то пример описанный здесь на форуме как избавление от дребезга, с флагами, у меня не работатет :(

Клапауций 999
Offline
Зарегистрирован: 06.06.2015

ty пишет:

Спасибо, буду пробовать, значит фактическ избавится от дребезга можно или delay (останавливая процессор) или конденсатором?

можно аналогично примеру мигания светодиодом без делау - блокируешь обработку кнопки на промежуток времени.

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

например:

int tb00 = millis();

тогда условие выполнения события при нажатии у тебя будет выглядеть так

boolean nb00 = digitalRead(3); 

int ntb00 = millis();

if (nb00 != b00 && ntb00 - tb00 >= 10) {b00 = nb00; tb00 = ntb00;} // где 10 - это задержка обработки нажатия

*вроде не наврал в коде - попробуй, как оно будет.

 

ty
Offline
Зарегистрирован: 15.06.2015

Клапауций 999 пишет:

ty пишет:

Спасибо, буду пробовать, значит фактическ избавится от дребезга можно или delay (останавливая процессор) или конденсатором?

можно аналогично примеру мигания светодиодом без делау - блокируешь обработку кнопки на промежуток времени.

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

например:

int tb00 = millis();

тогда условие выполнения события при нажатии у тебя будет выглядеть так

boolean nb00 = digitalRead(3); 

int ntb00 = millis();

if (nb00 != b00 && ntb00 - tb00 >= 10) {b00 = nb00; tb00 = ntb00;} // где 10 - это задержка обработки нажатия

*вроде не наврал в коде - попробуй, как оно будет.

 

 

Спасибо! Уже голова не соображает, завтра на свежую голову все еще раз перечитаю осознаю и буду пробовать! Спасибо огромное за помощь в образовании! :)

ty
Offline
Зарегистрирован: 15.06.2015

Сделал немного по другому, все работает как надо. Вход в меню установки по ОТПУСКАНИЮ кнопки SET, однокраное нажатие кнопок UP/DOWN изменяет заданную темепературу на 0.5 градуса, удержание этих кнопок - циклическое увеличение/уменешение заданной температуры. Повторное нажание кнопки SET выход из меню установки (по отпусканию кнопки) и возврат в режим термостата.

Все кнопки работают и задумывалось! Спасибо комрадам не пожалевшим своего времени на наставление на путь истинный! Особенно SU-27-16 за совет включить воображение, это действительно очень помогло.

Следующий этап разобратся с алгоритмом поддержания темепературы :)

в итоге получился такой код:

// термостат, один датчик DS18B20
// V4.0
//  

#include <EEPROM.h>
#include <OneWire.h>
#include <OLED_I2C.h>

#define OUT1 13               // выход для реле 
OneWire  ds(15);              // 15 вход датчика 18b20
OLED  myOLED(SDA, SCL, 8);    //OLED display
extern uint8_t SmallFont[];   //OLED display 
extern uint8_t BigNumbers[];  //OLED display

 long previousMillis = 0;
 long interval = 200; 
 boolean flag=0;   

// variables will change:

float tempSV;

// ГРАФИЧАСКИЕ СИМВОЛЫ ДЛЯ ЭКРАНА

byte gradus[8] = {     
  0b00110,
  0b01001,
  0b01001,
  0b00110,
  0b00000,
  0b00000,
  0b00000,
  0b00000
                 };
byte on[8] = {        
  0b00000,
  0b00000,
  0b10001,
  0b01110,
  0b01110,
  0b10001,
  0b00000,
  0b00000
              };

// ОБРАБОТКА ОШИБОК

void erorr()
 {                                                  // останавливает работу программы и показываем ошибку
  digitalWrite(OUT1, LOW);                          // выключаем реле
  
      while(1)                                     // крутим бесконечный цикл
      {                                               
       digitalWrite(13, !digitalRead(13));
       delay(100);
      }  
 }

// ОПИСАНИ КНОПОК

byte key()

 { 
       unsigned long currentMillis = millis();   

//"SETUP" Button connected to 7   
         
      if(digitalRead(7)==LOW&&flag==0)                          //если кнопка нажата и перемення flag равна 0 , то ... 
          { 
          if (millis() -previousMillis >500);
               {     
               previousMillis = millis();
               flag=1;                                          //это нужно для того что бы с каждым нажатием кнопки происходило только ОДНО действие  
               } 
          }   
      
     if (digitalRead(7)==HIGH&&flag==1)                         //если кнопка НЕ нажата и переменная flag равна - 1 ,то ... 
          {   
          flag=0;                                               //обнуляем переменную flag 
          return 1;                                             // возвращаем код кнопки ОДИН раз при ОРПУСКАНИИ кнопки
          }  
                     
 //"DOWN" Button connected to 4   

     if(digitalRead(4)==LOW)                                   // если кнопка нажата
             {
             if(currentMillis - previousMillis > interval)     // проверяем интервал, если интревал больше заданного
               {
               previousMillis = currentMillis;                 // меняем previousMillis на текущий
               return 2;                                       // возвращаем код кнопки 
               }                                               // если УДЕРЖИВАЕМ кнопку нажатой код кнопки будет возвращатся ПЕРИОДИЧЕСКИ через интервал
             }
     
 //"UP" Button connected to 2   
            
     if(digitalRead(2)==LOW)                                    // если кнопка нажата
             {
             if(currentMillis - previousMillis > interval)      // проверяем интервал, если интревал больше заданного
                 {
                 previousMillis = currentMillis;                // меняем previousMillis на текущий
                 return 3;                                      // возвращаем код кнопки 
                 }                                              // если УДЕРЖИВАЕМ кнопку нажатой код кнопки будет возвращатся ПЕРИОДИЧЕСКИ через интервал
             }
      
     else return 0;       
  }

// ВЫВОД НА ЭКРАН В РЕЖИМЕ УСТАНОВКИ ТЕМПЕРАТУРЫ И ЗАДАНИЯ ТЕМПАРАТУРЫ (SV)

void setMenu()

 {    
     digitalWrite(OUT1, LOW);                 // выключаем реле
     boolean out=0;                           // внутрення переменная для выхода из цикла
      while ( out != 1 )                       // крутим цикл пока boolean out не равна 1
   {                    
     
     byte KEY = key();                      // читаем состояние кнопок
   
 //вывод информации на экран в режиме установки темепературы (SV)
   
    myOLED.clrScr();                       // OLED display
    myOLED.setFont(SmallFont);             // OLED display                
    myOLED.print("SV", 10, 20);            // OLED display
    myOLED.setFont(BigNumbers);            // OLED display
    myOLED.printNumF(tempSV, 2, 30, 20);   // OLED display
    myOLED.drawCircle(110, 23, 2);         // hor, ver ,size
    myOLED.setFont(SmallFont);             // OLED display
    myOLED.print("C", 114, 22);            // OLED display
    myOLED.update();                       // OLED display
   

// обработка кнопок 

  switch ( KEY )
 
     {
     case 2 :                                 // если кнопка DOWN нажата 
        {
        tempSV-= 0.5;                        // изменяем значение
        if (tempSV < 20) tempSV = 95;        // проверяем пределы
        break;
       }   
  
    case 3 :                                 // если кнопка UP нажата 
    
       {
       tempSV+= 0.5;                         // изменяем значение
       if (tempSV > 95) tempSV = 20;         // проверяем пределы
       break;
       } 

    case 1 :                                 // если кнопка SETUP нажата 

      {
      EEPROM.put(0, tempSV);                 // сохраняем SV в eeprom   
      myOLED.clrScr();                       // очищаем OLED display
      out=1;                                 // инициируем выход из цикла
      break;
      }      
    }
  }
 }

// ОПРОС ДАТЧИКА

float getTemp()                            // возвращает температуру с датчика
  
  {          
  byte data[12];                           // и останавливает программу на секунду
  byte addr[8];  
  
  if (!ds.search(addr))                    //если адрес датчика не получен сообщаем об ошибке
  
    { 
 
    myOLED.begin();                                   //OLED display
    myOLED.setFont(SmallFont);                        //OLED display
    myOLED.print("NO SENSOR", 37, 30);                //OLED display
    myOLED.update();                                  //OLED display
    
    erorr(); 
     
    }
  
    ds.reset_search(); 
      if (OneWire::crc8(addr, 7) != addr[7]) 
      
    {
      
     myOLED.begin();                                 //OLED display
     myOLED.setFont(SmallFont);                      //OLED display
     myOLED.print("SENSOR CRC ERROR", 30, 30);       //OLED display
     myOLED.update();                                //OLED display
     
 erorr(); 
    
    }
  
     ds.reset();            
     ds.select(addr);        
     ds.write(0x44);      
     delay(500);   
     ds.reset();
     ds.select(addr);    
     ds.write(0xBE);          

  for (int i = 0; i < 9; i++) data[i] = ds.read(); 
  int raw = (data[1] << 8) | data[0];                              // Переводим температуру   
  if (data[7] == 0x10) raw = (raw & 0xFFF0) + 12 - data[6];  
  return raw / 16.0;
 }

void setup() 

 {

    pinMode(13, OUTPUT);      // конфигурация выхода
    pinMode(OUT1, OUTPUT);    // описание выхода
  
// Serial.begin(9600); 
    
// Buttons setup
    
    pinMode(7, INPUT);         //  устанавливает режим работы - вход для 7го вход/выхода (кнопка "SETUP")
    digitalWrite(7, HIGH);   

    pinMode(4, INPUT);         //  устанавливает режим работы - вход для 4го вход/выхода (кнопка "DOWN")
    digitalWrite(4, HIGH);   

    pinMode(2, INPUT);         //  устанавливает режим работы - вход для 2го вход/выхода (кнопка "UP")
    digitalWrite(2, HIGH);   

    myOLED.begin();           // инициализация экрана
  
    
  
    tempSV = EEPROM.get(0 , tempSV);     // читаем настройки из еепром
 }

void loop() 

 {  
  
  if (key() == 1) setMenu();                                // если нажата кнопка SETUP, переходим в меню задания температуры
  
  float temperature = getTemp();                             // читаем температуру
 
  if (temperature < tempSV) digitalWrite(OUT1, HIGH);        // сверяем температуру 
  
  else digitalWrite(OUT1, LOW);                              // и управляем выходами
  

// ВЫВОД ИНФОРМАЦИИ НА ЭКРАН В РАБОЧЕМ РЕЖИМЕ 
      
   myOLED.setFont(SmallFont);
   myOLED.print("PV", 10, 05);
   myOLED.print("SV", 10, 39); 
   myOLED.print("C", 115, 05); 
   myOLED.print("C", 115, 39); 
    
     if (digitalRead(OUT1)) myOLED.print("*", 13, 16);            // вывод на экран состояние выхода
     else myOLED.print(" ", 13, 16);
  
   myOLED.setFont(BigNumbers);                                    //вэбор экранного шрифта
   myOLED.printNumF(temperature, 2, 30, 03);                      // вывод на экран текущей температуры PV
   myOLED.printNumF(tempSV, 2, 30, 37);                          // вывод на экран заданной темепературы SV
   myOLED.drawCircle(111, 06, 2);                                // hor, ver ,size  значек градуса
   myOLED.drawCircle(111, 40, 2);                                // hor, ver ,size  значек градуса
   
   myOLED.update();                                              // вывод буфера экрана

 }




 

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

ty пишет:

Попробовал то что нашел здесь на форуме

void(* resetFunc) (void) = 0; // Reset MC function

resetFunc(); //вызов

Это очень жестоко. Оаботает, конечно, куда нафиг денется, но ... почитайте всё же 10 главу даташита. как я Вам советовал. Там поймёте и почему так не стоит и как сделать более аккуратно.

ty
Offline
Зарегистрирован: 15.06.2015

ЕвгенийП пишет:

ty пишет:

Попробовал то что нашел здесь на форуме

void(* resetFunc) (void) = 0; // Reset MC function

resetFunc(); //вызов

Это очень жестоко. Оаботает, конечно, куда нафиг денется, но ... почитайте всё же 10 главу даташита. как я Вам советовал. Там поймёте и почему так не стоит и как сделать более аккуратно.

Уже убрал это, ресет вообще не нужен, сделал переходы между циклами установки темепературой и термостата. Выше итоговый код. Но даташит все равно конечно почитаю :)

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

#57    016 long interval = 200; 

зачем long ?
200 влезает в byte....   0...255

ty
Offline
Зарегистрирован: 15.06.2015

SU-27-16 пишет:

#57    016 long interval = 200; 

зачем long ?
200 влезает в byte....   0...255

Я экспериметировал с длинными интревалами, сейчас уже лонг не надо, поправлю.