Кнопка остановки/запуска секундомера и сброс

я пытаюсь сделать секундомер с кнопкой стоп/старт и кнопкой сброса

Я сделал это

#include "RTClib.h"
//Настройка часов реального времени, DS3231
RTC_DS3231 rtc;

const byte SQWinput = 2;  // Должно быть внешнее прерывание

volatile uint32_t  MillisecondsAtStartOfSecond = 0;
 
 unsigned long secondss=0 ;
 unsigned long minutess=0 ;
 
 unsigned long  hourss =0;
 unsigned long ms;

boolean passed_second=true;
boolean start=true;


const byte ledPin = 13;

const byte startButton = 7;


const byte resetButton = 3;
// Создаем еще один объект Bounce


const char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// Вывод SQW, установленный в режим 1 Гц, имеет спадающий фронт в начале каждой секунды.
void SQWFallingISR()
{
  MillisecondsAtStartOfSecond = millis();
}

void setup ()
{
  Serial.begin(9600); // Установить серийный монитор на 115200
  delay(200);

  pinMode(7, INPUT);
  digitalWrite(7, HIGH);
  pinMode(3, INPUT);
  digitalWrite(3, HIGH);
 


  
  if (! rtc.begin())
  {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }

  if (rtc.lostPower())
  {
    Serial.println("RTC lost power, let's set the time!");
    // Когда необходимо установить время на новом устройстве или после сбоя питания,
    // следующая строка устанавливает RTC на дату & время составления этого скетча
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // Эта строка устанавливает RTC с явной датой & время, например, установить
    // 21 января 2014 года в 3 часа ночи вы бы позвонили:
    // rtc.adjust(DateTime(2022, 4, 03, 21, 14, 0));
  }

  // Настройте контакт SQW на DS3231 для вывода прямоугольного сигнала с частотой 1 Гц
  rtc.writeSqwPinMode(DS3231_SquareWave1Hz);

  // Получаем MillisecondsAtStartOfSecond по заднему фронту SQW.
  attachInterrupt(digitalPinToInterrupt(SQWinput), SQWFallingISR, FALLING);
}



void loop ()
{
  DateTime now = rtc.now();


    ms = millis();
 
  noInterrupts();
  // Сколько времени прошло с начала второго?
  
 
  ms -= MillisecondsAtStartOfSecond;
  interrupts();

  if(digitalRead(7) != HIGH)   //КНОПКА ПУСК
{    displayTime (now, ms);
     Serial.println("stopwatch  ");
  
  Serial.print(hourss);
  Serial.print(':');
  Serial.print(minutess);
  Serial.print(':');
  Serial.print(secondss);
  Serial.print(':');
  Serial.println(ms);
}

 if(digitalRead(3) != HIGH)   //КНОПКА СБРОСА
{
     Serial.println("stopwatch  ");
  
  Serial.print(0);
  Serial.print(':');
  Serial.print(0);
  Serial.print(':');
  Serial.print(0);
  Serial.print(':');
  Serial.println(0);
  ms=0;
}
 // displayTime (сейчас, мс);
  /*Serial.println("stopwatch  ");
  
  Serial.print(hourss);
  Serial.print(':');
  Serial.print(minutess);
  Serial.print(':');
  Serial.print(secondss);
  Serial.print(':');
  Serial.println(ms);
  Serial.println("*********************************");
  Serial.println("Clock & Date  ");*/
   

  }

void displayTime(DateTime &now, unsigned long ms)
{
  ms = ms % 1000;  // Игнорировать полные секунды
  
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" (");
  Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
  Serial.print(") ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  if (now.minute() < 10)
    Serial.print('0');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  if (now.second() < 10)
    Serial.print('0');
  Serial.print(now.second(), DEC);
 // Serial.println();
  Serial.print(':');
  if (ms < 100)
    Serial.print('0');
  if (ms < 10)
    Serial.print('0');
  Serial.print(ms, DEC);
  Serial.println();
  Serial.println("*********************************");

  if(ms>998) {
      secondss++;
     
  }
    if(secondss>59) {
     secondss=0;
      minutess++;
 
    }
    if(minutess>59) {
     minutess=0;
      hourss++;}

    }

но он не работает должным образом

время не увеличивается после того, как мс достигает 999

в чем причина?

, 👍-1

Обсуждение

Что вы подразумеваете под «_это не работает должным образом_»? Какое поведение вы видите? Чем оно отличается от ожидаемого вами поведения?, @Edgar Bonet

время не увеличивается после того, как мс достигает 999, @Amr Ahmed

объявите now в setup() ... DateTime now; .... затем используйте now = rtc.now(); в loop(), @jsotola


1 ответ


4

Этот код довольно запутанный, так как вы используете как millis(), так и RTC как источник времени.

Ваша проблема может исходить отсюда:

ms -= MillisecondsAtStartOfSecond;

Если внутренние часы вашего Arduino немного сбиваются, может случиться так, что секунда RTC составляет всего 999 миллисекунд от millis(). Если это произойдет, тогда ms никогда не достигнет 999, а вместо этого пойдет прямо с 998 до 0.

Или, может быть, здесь:

ms = ms % 1000;  // Игнорировать полные секунды
// ...
if (ms > 998) {
    secondss++;
}

Если ваш скетч занят (возможно, он обменивается данными с RTC), он может не запускать этот код точно в миллисекунду 999. И 999 - единственный значение ms, которое может увеличить secondss.

Для секундомера данные RTC на самом деле не нужны. Вы можете реализовать он полностью основан на millis(), и это упростило бы ситуацию:

bool stop_watch_running;
uint32_t stop_watch_last_update;
uint16_t stop_watch_ms;
uint8_t stop_watch_s;
uint8_t stop_watch_min;
uint8_t stop_watch_h;

void stop_watch_reset() {
    stop_watch_running = false;
    stop_watch_ms = 0;
    stop_watch_s = 0;
    stop_watch_min = 0;
    stop_watch_h = 0;
}

void stop_watch_start() {
    stop_watch_last_update = millis();
    stop_watch_running = true;
}

// Периодически вызывайте это.
void stop_watch_update() {
    if (!stop_watch_running)
        return;
    uint32_t now = millis();
    stop_watch_ms += now - stop_watch_last_update;
    stop_watch_last_update = now;
    while (stop_watch_ms >= 1000) {
        stop_watch_ms -= 1000;
        stop_watch_s++;
        if (stop_watch_s >= 60) {
            stop_watch_s = 0;
            stop_watch_min++;
            if (stop_watch_min >= 60) {
                stop_watch_min = 0;
                stop_watch_h++;
            }
        }
    }
}

void stop_watch_stop() {
    stop_watch_update();
    stop_watch_running = false;
}

Если вы немного разбираетесь в классах C++, вы можете превратить это в class и замените префикс stop_watch_ на StopWatch::.

,

привет Эдгар Большое спасибо за ваш код RTC используется для получения сигнала прямоугольной формы., @Amr Ahmed