Прошу помочь со скетчем

gra_ver
Offline
Зарегистрирован: 23.01.2013

Скачал, залил скетч StopWatch - секундометр отлично работает, результат пишет в SERIAL_MONITOR

/* StopWatch
 * Paul Badger 2008
 * Demonstrates using millis(), pullup resistors,
 * making two things happen at once, printing fractions
 *
 * Physical setup: momentary switch connected to pin 4, other side connected to ground
 * LED with series resistor between pin 13 and ground
 */


#define ledPin  13                  // LED connected to digital pin 13
#define buttonPin 4                 // button on pin 4

int value = LOW;                    // previous value of the LED
int buttonState;                    // variable to store button state
int lastButtonState;                // variable to store last button state
int blinking;                       // condition for blinking - timer is timing
long interval = 100;                // blink interval - change to suit
long previousMillis = 0;            // variable to store last time LED was updated
long startTime ;                    // start time for stop watch
long elapsedTime ;                  // elapsed time for stop watch
int fractional;                     // variable used to store fractional part of time



void setup()
{
   Serial.begin(9600);

   pinMode(ledPin, OUTPUT);         // sets the digital pin as output

   pinMode(buttonPin, INPUT);       // not really necessary, pins default to INPUT anyway
   digitalWrite(buttonPin, HIGH);   // turn on pullup resistors. Wire button so that press shorts pin to ground.

}

void loop()
{
    // check for button press
   buttonState = digitalRead(buttonPin);                   // read the button state and store

   if (buttonState == LOW && lastButtonState == HIGH  &&  blinking == false){     // check for a high to low transition
      // if true then found a new button press while clock is not running - start the clock

      startTime = millis();                                   // store the start time
      blinking = true;                                     // turn on blinking while timing
      delay(5);                                               // short delay to debounce switch
      lastButtonState = buttonState;                          // store buttonState in lastButtonState, to compare next time

   }

   else if (buttonState == LOW && lastButtonState == HIGH && blinking == true){     // check for a high to low transition
      // if true then found a new button press while clock is running - stop the clock and report

        elapsedTime =   millis() - startTime;              // store elapsed time
        blinking = false;                                  // turn off blinking, all done timing
        lastButtonState = buttonState;                     // store buttonState in lastButtonState, to compare next time

       // routine to report elapsed time
        Serial.print( (int)(elapsedTime / 1000L));         // divide by 1000 to convert to seconds - then cast to an int to print

        Serial.print(".");                             // print decimal point

        // use modulo operator to get fractional part of time
       fractional = (int)(elapsedTime % 1000L);

       // pad in leading zeros - wouldn't it be nice if
       // Arduino language had a flag for this? :)
       if (fractional == 0)
          Serial.print("000");      // add three zero's
       else if (fractional < 10)    // if fractional < 10 the 0 is ignored giving a wrong time, so add the zeros
          Serial.print("00");       // add two zeros
       else if (fractional < 100)
          Serial.print("0");        // add one zero

       Serial.println(fractional);  // print fractional part of time

   }

   else{
      lastButtonState = buttonState;                         // store buttonState in lastButtonState, to compare next time
   }

   // blink routine - blink the LED while timing
   // check to see if it's time to blink the LED; that is, the difference
   // between the current time and last time we blinked the LED is larger than
   // the interval at which we want to blink the LED.

   if ( (millis() - previousMillis > interval) ) {

      if (blinking == true){
         previousMillis = millis();                         // remember the last time we blinked the LED

         // if the LED is off turn it on and vice-versa.
         if (value == LOW)
            value = HIGH;
         else
            value = LOW;
         digitalWrite(ledPin, value);
      }
      else{
         digitalWrite(ledPin, LOW);                         // turn off LED when not blinking
      }
   }

}

 

 

 

gra_ver
Offline
Зарегистрирован: 23.01.2013

Хотелось бы сделать из этого секундомера реле времени с возможным ручным стопом той же кнопкой. Уровень - чайник, так что - как понимаю - нужно добавить константу "long myDelay = моя уставка" в Setup и как то воткнуть if((millis() > (startTime + myDelay)).

Голову сломал. Help me please!!!

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

Общие направление мысли - верное.

Но ведь проще "написать с нуля", особенно если не нужны все красивости подравненого вывода в Serial и проч.

Если нужно просто "реле с кнопкой".

Но тут нужно будет уточнить постановку задачи.

Нужен ли вообще выводв Serial?

Когда оно запускается, при старте контроллера или по кнопке? Что оно делает по прошествии времени включает какой-то пин или выключает? Или "меняет ему состояние"? Возможны ли повторные запуски?

Вот самый простеший вариант: включаем светик. Выключаем его или если прошло 5 секунд от включения контроллера или по нажатию кнопку (что-бы опять его включить - перегружаем кнопкой Reset).

#define LED 13
#define BUTTON 2

#define ON_PERIOD 5000 // будем светить светиком 5-ть. секунд
unsigned long onTime; // тут храним время когда включили светик
void setup(){
  pinMode(LED,OUTPUT);
  digitalWrite(BUTTON,HIGH); // включаем подтяжку для кнопки
  

  // 
  digitalWrite(LED,OUTPUT); // включили светик
  onTime=millis(); // запомнили время включения
  
  
}

void loop(){
  if(millis()-onTime>ON_PERIOD){ // пора выключать
    digitalWrite(LED,LOW);
  }
  
  if(!digitalRead(BUTTON)){ // или нажата кнопка
      digitalWrite(LED,LOW); // тоже выключаем
  }
}

На самом деле onTime тут и не нужна. Она всегда будет 0 (так как setup() выполнится быстрее чем 1 мсек). Просто показал ее как принцип "засекать момент включения", может в будущем захотите "зажигать по кнопке", тогда в нее нестесвенно уже что-то не нулевое будет попадать.

P.S. На будущие постарайтесь называть свои темы более информативно. Вообщем-то все темы на этом сайте в итоге сводятся к "нужно помощь со скетчем" и "нужно помощь с железом". Но не называть же их все одинаково? 

gra_ver
Offline
Зарегистрирован: 23.01.2013

Спасибо за ответ, leshak! Добавило уверенности. StopWatch мне интересен и выводом времени - хочу подобраться к выводу на LCD. Поэтому продолжил долбить его. Вот что получилось: (добавленное выделено)

/* StopWatch
 * Paul Badger 2008
 * Demonstrates using millis(), pullup resistors,
 * Делать две вещи одновременно, printing fractions
 *
 * Физическая установка: мгновенный переключатель, подключенный к
 выводу 4, другая сторона подключен к земле

 * Светодиод с резистором между выводом 13 и землей
 */


#define ledPin  13                  // LED подключен к цифровому выводу 13
#define buttonPin 8                 // кнопка на контакт 4

int value = LOW;                    // предыдущее значение LED
int buttonState;                    // переменная для хранения состояния кнопки
int lastButtonState;                // переменная для хранения последнего состояния кнопки
int blinking;                       // условие мигает - таймер времени
long interval = 50;                // интервал мигания  - изменить в соответствии 
long previousMillis = 0;            // переменная для хранения последнего времени обновления светодиода
long startTime ;                    // время старта секундомер 
long elapsedTime ;                  // истекшее время секундомера
int fractional;                     // переменная используется для хранения дробной части времени 

long myDelay = 15000 ;                 // переменная определяющая уставку времени



void setup()
{
   Serial.begin(9600);

   pinMode(ledPin, OUTPUT);         // sets the digital pin as output

   pinMode(buttonPin, INPUT);       // не обязательно, контакты по умолчанию как входы 
   digitalWrite(buttonPin, HIGH);   // включить подтягивающий резистор. Wire button so that press shorts pin to ground.

}

void loop()
{
    // Проверка на нажатие кнопки 
   buttonState = digitalRead(buttonPin);                   // считывание состояния кнопки и сохранение

   if (buttonState == LOW && lastButtonState == HIGH  &&  blinking == false){     // check for a high to low transition
      // if true then found a new button press while clock is not running - start the clock
      //Если так, то нашел новую кнопку во время пресс часы не запущен - запустить часы 
      
      startTime = millis();                                   // store the start time
      blinking = true;                                     // turn on blinking while timing
      delay(5);                                               // короткая задержка на дребезг переключателя 
      lastButtonState = buttonState;                          // store buttonState in lastButtonState, для сравнения в следующий раз

   }

   else if ((buttonState == LOW && lastButtonState == HIGH && blinking == true) || (millis() == (startTime + myDelay))) {     // check for a high to low transition
      // if true then found a new button press while clock is running - stop the clock and report
      //Если так, то нашел новую нажать кнопку в то время как часы работает - остановить часы и отчет 

        elapsedTime =   millis() - startTime;              // store elapsed time - прошедшее время 
        blinking = false;                                  // turn off blinking, all done timing
        lastButtonState = buttonState;                     // store buttonState in lastButtonState, to compare next time_сохранить buttonState в lastButtonState, для сравнения в следующий раз

       // routine to report elapsed time
        Serial.print( (int)(elapsedTime / 1000L));         // делим на 1000, чтобы преобразовать в секунды - затем преобразуем в целое число для печати 

        Serial.print(".");                             // print decimal point_Вывод десятичной точки 

        // use modulo operator to get fractional part of time_Использовать модуль оператор, чтобы получить дробную часть времени 
       fractional = (int)(elapsedTime % 1000L);

       // pad in leading zeros - wouldn't it be nice if
       // Arduino language had a flag for this? :)
       if (fractional == 0)
          Serial.print("000");      // add three zero's_Добавьте три ноля
       else if (fractional < 10)    // if fractional < 10 the 0 is ignored giving a wrong time, so add the zeros
          Serial.print("00");       // add two zeros
       else if (fractional < 100)
          Serial.print("0");        // add one zero

       Serial.println(fractional);  // print fractional part of time_дробная часть времени

   }

   else{
      lastButtonState = buttonState;                         // store buttonState in lastButtonState, to compare next time
   }

   // blink routine - blink the LED while timing_мигает светодиод при отсчете времени
   // check to see if it's time to blink the LED; that is, the difference
   // between the current time and last time we blinked the LED is larger than
   // the interval at which we want to blink the LED.

   if ( (millis() - previousMillis > interval) ) {

      if (blinking == true){
         previousMillis = millis();                         // remember the last time we blinked the LED

         // if the LED is off turn it on and vice-versa.Если светодиод не горит, включите его и наоборот.
         if (value == LOW)
            value = HIGH;
         else
            value = LOW;
         digitalWrite(ledPin, value);
      }
      else{
         digitalWrite(ledPin, LOW);                         // turn off LED when not blinking_Выключите СВЕТОДИОД при не мигании
      }
   }

}

З.Ы.

Все работает - определяем уставку времени "long myDelay =хххх", по первому нажатию тактовой кнопки включаем нагрузку-(у меня пока это люминисцентная лампа на 220 v  включенная через твердотельное реле). По истечению времени уставки или при повторном нажатии кнопки нагрузка отключается и время во включенном состоянии (сек/мсек) видим в Serial Monitor.

З.З.Ы.

Иногда глючит кнопка - надо править Debounce?

 

leshak
Offline
Зарегистрирован: 29.09.2011
(millis() == (startTime + myDelay)

Плойхо.

Во первых, через 49-девять дней будет переполнение и "все поломается".

Во вторых грабли вылезут раньше. Что будет если мы прийдем к этой срочке не точно в нужную миллисекунду? Чуть где-то "задуплились" и все. Привет. часы не остановсятся. Поезд ушел. Так что лучше, преобразовать это условие в 

(millis()-startTime >= myDelay)

(хе. хе. вспоминается школа и уравнения/неравества? ;)

А еще "вывод на печать" я бы порекомендовал вам  вынести в отдельную функцию. Не замусоривать ей основную "бизнес логику".

Сделайте функцию, скажем printTime(unsgined long tm) и упихайте в нее строки с 066 по 082.

Когда доберетесь до экрана, то просто напишете еще printTimeLCD(unsgined long tm). И основная логику у вас уже не будет затрагиватся.

А еще почитайте про типы. Нужно ими пользоватся более аккуратно. Не нужно int, там где хватит byte. Нужно различать long и unsigned long. То есть "пока это не критично" и "и так сойдет", но подобной небрежностью вы себе большие головняки на будущие закладываете.

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

А еще  lastButtonState = buttonState;   можно просто в конце loop делать, а не раскидывать по if/else (а потом выискавать "где мы забыли сделать сохранение"). Зачем нам его писать в трех местах если можно в одном?

gra_ver
Offline
Зарегистрирован: 23.01.2013

leshak, я за вами не успеваю! Еще раз спасибо! Будем думать. И "работать, работать, и еще раз работать"!

leshak
Offline
Зарегистрирован: 29.09.2011

:)

А еще вот это

   // if the LED is off turn it on and vice-versa.Если светодиод не горит, включите его и наоборот.
         if (value == LOW)
            value = HIGH;
         else
            value = LOW;

можно спокойно заменить (будет в точности тот же самый резульат) на

value=!value;

 

leshak
Offline
Зарегистрирован: 29.09.2011

А если почесать репу, то и весь

if ( (millis() - previousMillis > interval) ) {

      if (blinking == true){
         previousMillis = millis();                         // remember the last time we blinked the LED

         // if the LED is off turn it on and vice-versa.Если светодиод не горит, включите его и наоборот.
         if (value == LOW)
            value = HIGH;
         else
            value = LOW;
         digitalWrite(ledPin, value);
      }
      else{
         digitalWrite(ledPin, LOW);                         // turn off LED when not blinking_Выключите СВЕТОДИОД при не мигании
      }
   }

 

На

      if ( (millis() - previousMillis > interval) ) {
             previousMillis = millis();                         // remember the last time we blinked the LED
             value=!value;
             digitalWrite(ledPin, blinking && value);
     }

 

gra_ver
Offline
Зарегистрирован: 23.01.2013

"Во первых, через 49-девять дней будет переполнение и "все поломается"."-

- Я не рассматриваю варианты с курятниками - перепелятниками -мне до них как до луны пешком. Для меня достаточно чтобы девайс работал в течение суток. И правильно я понимаю, что на следующий день если я включу свой таймер по схеме:

1) Включаем питание ардуино

2) Через 30 сек включаем силу - то все должно быть OK?

 

leshak
Offline
Зарегистрирован: 29.09.2011

gra_ver пишет:

"Во первых, через 49-девять дней будет переполнение и "все поломается"."-

- Я не рассматриваю варианты с курятниками - перепелятниками -мне до них как до луны пешком. Для меня достаточно чтобы девайс работал в течение суток. И правильно я понимаю, что на следующий день если я включу свой таймер по схеме:

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

gra_ver пишет:

2) Через 30 сек включаем силу - то все должно быть OK?

Ну проверте. Скетч же у вас. Это я вас должен спрашивать все ли работает, а не вы меня. Я просто указал вам "тонкие места", которые "я бы делал по другому". А что дальше делать с этими советами - ваше дело.

leshak
Offline
Зарегистрирован: 29.09.2011

Вообщем не проверял, но я бы все это писал примерно так:

#define ledPin  13                  // LED подключен к цифровому выводу 13
#define buttonPin 8                 // кнопка на контакт D8

#define BLINK_INTERVAL 50                // интервал мигания  - изменить в соответствии 


bool lastButtonState;                // переменная для хранения последнего состояния кнопки
bool blinking;                       // условие мигает - таймер времени

unsigned long startTime ;                    // время старта секундомер 

long myDelay = 15000 ;                 // переменная определяющая уставку времени



void setup()
{
   Serial.begin(9600);

   pinMode(ledPin, OUTPUT);         // sets the digital pin as output

   pinMode(buttonPin, INPUT);       // не обязательно, контакты по умолчанию как входы 
   digitalWrite(buttonPin, HIGH);   // включить подтягивающий резистор. Wire button so that press shorts pin to ground.

}

void loop()
{
    // Проверка на нажатие кнопки 
   bool buttonState = digitalRead(buttonPin);                   // считывание состояния кнопки и сохранение

   if (lastButtonState && !buttonState){     // check for a high to low transition
      if(!blinking)startTimer();       //Если так, то нашел новую кнопку во время пресс часы не запущен - запустить часы 
      else stopAndPrintTime();  // часы уже идут. останавливаем и выводим на экран
   } // остановка/старт по кнопке

   if (blinking && (millis() - startTime >= myDelay)) stopAndPrintTime();       // остановка по времени

    blinkLed();// мигаем диодом если blinking==true;
    
   lastButtonState = buttonState;                         // store buttonState in lastButtonState, to compare next time

}

void blinkLed(){
  static bool value=LOW; // предыдущее значение LED
  static unsigned long previousMillis = 0;            // переменная для хранения последнего времени обновления светодиода
  
   if ( (millis() - previousMillis > BLINK_INTERVAL) ) {
        previousMillis = millis();                         // remember the last time we blinked the LED
        value=!value;
        digitalWrite(ledPin, blinking && value);
  }
  
}

void startTimer(){
    //  Serial.print(millis());Serial.println(": Timer Started!!!"); // для отладки
    
     startTime = millis();                                   // store the start time
     blinking = true;                                     // turn on blinking while timing
}

void stopTimer(){
   //  Serial.print(millis());Serial.println(": Timer Stopped!!!"); // для отладки
   
    blinking = false;    
}

void stopAndPrintTime(){
  stopTimer();
  unsigned long elapsedTime =   millis() - startTime;              // store elapsed time - прошедшее время 
  printTime(elapsedTime); // выводим который час
  //printTimeLCD(elapsedTime); //  когда-нибудь и на экран выведем
}

void printTime(unsigned long mTime){
    // routine to report elapsed time
        Serial.print( (int)(mTime / 1000L));         // делим на 1000, чтобы преобразовать в секунды - затем преобразуем в целое число для печати 

        Serial.print(".");                             // print decimal point_Вывод десятичной точки 

        // use modulo operator to get fractional part of time_Использовать модуль оператор, чтобы получить дробную часть времени 
       int fractional = (int)(mTime % 1000L); // переменная используется для хранения дробной части времени 

       // pad in leading zeros - wouldn't it be nice if
       // Arduino language had a flag for this? :)
       if (fractional == 0)
          Serial.print("000");      // add three zero's_Добавьте три ноля
       else if (fractional < 10)    // if fractional < 10 the 0 is ignored giving a wrong time, so add the zeros
          Serial.print("00");       // add two zeros
       else if (fractional < 100)
          Serial.print("0");        // add one zero

       Serial.println(fractional);  // print fractional part of time_дробная часть времени
}

 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Мне кажется, что printTime(unsigned long mTime) занимается какими-то нечеловеческими преобразованиями. Есть же

   // reformat float number to string
   char current_value[10];
   dtostrf(CurrentValue, 7, 2, current_value );

 

leshak
Offline
Зарегистрирован: 29.09.2011

Andrey_Y_Ostanovsky пишет:

Мне кажется, что printTime(unsigned long mTime) занимается какими-то нечеловеческими преобразованиями. Есть же

   // reformat float number to string
   char current_value[10];
   dtostrf(CurrentValue, 7, 2, current_value );

 

Вы правы. Только только сейчас рассказывать еще про "откуда взялась dtostrf?", что это за  current_value[10]  . К тому же на чем же всякие for/if/switch изучать как не на таких задачах типа "подравнять строку"?

К тому же, ну вот в дальшенйшем подрубит, скажем, сегментный индикатор. Как он потом dtostrf с ним заиспользует? А там где "сами разбирали ручками" (тут важнее "понять") - уже есть шанс адаптировать под индикатор.

P.S. Но я не хочу сказать что "вы зря про это сказали". Пусть и ваш вариант будет. Кто захочет - погуглит что это за dtostrf, не сейчас так потом пригодится знание