Ещё одни часы без RTS

c0smo
Offline
Зарегистрирован: 19.02.2016

Всем привет, я начинающий, в программировании чють больше нуля, решил я сделать себе наручные часы с 7ми сигментым индикатором, наковырял скеч с часиками, залил, показывают всё время 0012(точки как разделить часы-минуты пока не использую) упёрся в какое то глобльное незнание(( тыкните в место где что-то не так?


#include "SevSeg.h"


SevSeg myDisplay;

unsigned long timer;
int deciSecond = 0;

void setup()
{

  int displayType = COMMON_CATHODE; //

   int digit1 = 8; //Pin 1
   int digit2 = 5; //Pin 10
   int digit3 = 11; //Pin 4
   int digit4 = 13; //Pin 6


   int segA = 7; //Pin 12
   int segB = 6; //Pin 11
   int segC = 10; //Pin 3
   int segD = 3; //Pin 8
   int segE = 9; //Pin 2
   int segF = 4; //Pin 9
   int segG = 2; //Pin 7
   int segDP= 12; //Pin 5

  int numberOfDigits = 4; 

  myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP);

  myDisplay.SetBrightness(100);

  timer = millis();
}
 

void loop() {
  int n = 0;
  int hours = 00;
  int minutes = 00;
  int elapsedMinutes = 0;
  int seconds = 0;

  char timeString[10];
  sprintf(timeString, "%02d%02d", n);
  myDisplay.DisplayString(timeString, 0);
 
  unsigned long time = millis() - (elapsedMinutes * 60000);
  seconds = ((time / 1000) % 60);
  if (seconds > 60) {
    seconds = 0;
    minutes++;
    elapsedMinutes++;
    if (minutes >= 60) {
      minutes = 0;
      hours++;
      if (hours > 23) {
        hours = 0;
      }
    }
  }
  n = (hours * 100) + minutes;
}

 

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

Ну в странной логике вычисления часов минут секунд разбираться не охота, а вот для начала вынести переменные 

40   int n = 0;
41   int hours = 00;
42   int minutes = 00;
43   int elapsedMinutes = 0;
44   int seconds = 0;
 

следует в глобальную секцию до loop() или сделать их static

После этого если и будет показывать хрень - то будем разбираться уже в странной логике.

Araris
Offline
Зарегистрирован: 09.11.2012

Может кому пригодится, вот проверенное решение для данной задачи. Замечу, что у меня этот кусок кода задействован в скетчах периферийных устройств, которые периодически синхронизируются со временем основного устройства, которое имеет модуль RTC, который периодически синхронизируется с NTP-сервером, (в доме, который построил Джек ))) ). Также замечу, что часы без RTC - плохая идея, точность их не порадует. Впрочем, код :

// Имеем ряд глобальных переменных
byte CurTimeHour = 0;
byte CurTimeMin   = 0;
byte CurTimeSec  = 0;
unsigned long setClockpreviousMillis; 
//
unsigned long Every1SecondTimer = 0;


void loop()
{
// с периодичностью в секунду вызывается некая функция, которая, в том числе, контролирует переменные времени.
if ( (millis() - Every1SecondTimer) > 1000 ) { RunEverySecond();  Every1SecondTimer = millis(); }
}

void RunEverySecond()
{
unsigned long setClockcurrentMillis = millis(); 
unsigned long setClockelapsedMillis += setClockcurrentMillis - setClockpreviousMillis;
while ( setClockelapsedMillis > 999 )
 {
 CurTimeSec++;
 if ( CurTimeSec > 59 )  { CurTimeMin++;  CurTimeSec = 0; }
 if ( CurTimeMin > 59 )  { CurTimeHour++; CurTimeMin = 0; }
 if ( CurTimeHour > 23 ) { CurTimeHour = 0; }
 setClockelapsedMillis -= 1000;
 }
setClockpreviousMillis = setClockcurrentMillis - setClockelapsedMillis;  
}

 

c0smo
Offline
Зарегистрирован: 19.02.2016

Огоромное спасибо за код.

Я осознаю, что часы без RTС не точны, я хочу сделать наручные часы, о обойтись минимальной схемой... и паралельно попытатся разобратся в прогарммировании. 

 

Araris
Offline
Зарегистрирован: 09.11.2012

Так пусть же все Ваши попытки будут успешными (звучит как тост))).

P.S. Всё-таки RTC - Real Time Clock.

c0smo
Offline
Зарегистрирован: 19.02.2016

Здравствуйте Sr.FatCat, спасибо за совет, вынес переменные за  loop(),  но реакция прежняя статичная картинка 0012. Есле не трудно то подскадите код с паривльной логикой хотябы для отсчёта секунд, а я попробую разобратся с минутми и часами...

c0smo
Offline
Зарегистрирован: 19.02.2016

Araris пишет:

Так пусть же все Ваши попытки будут успешными (звучит как тост))).

P.S. Всё-таки RTC - Real Time Clock.

Спасибо, исправил.

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Вот такой вариант на 16 битном таймере будет работать ещё более точно:

volatile uint8_t minut=0;
volatile uint8_t chas=0;
volatile uint8_t sec=0;

void setup(){
Serial.begin(9600);
TCCR1A=(1<<WGM11); //режим14 FAST PWM 
TCCR1B=(1<<CS12)|(1<<WGM13)|(1<<WGM12); //делить частоту CPU на 256
ICR1=62499;  // (16000000MHz /div256) -1 = 1 раз в секунду
TIMSK1=(1<<TOIE1); //разрешить прерывание
}

ISR (TIMER1_OVF_vect) { 
sec++ ; //инкремент переменной каждую секунду
if (sec>59){sec=0; minut++; }
if (minut>59){minut=0; chas++; }
if (chas>23){chas=0;}
}

void loop(){
Serial.print(chas);
Serial.write(':');
Serial.print(minut);
Serial.write(':');
Serial.print(sec);
Serial.println();
}

 

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

dimax пишет:

...

Красивый у вас код, прям как из даташита к МК :)

Но по-моему, это несколько противоречит тому, что хочет ТС. Он хочет осмысленно написать простую программу.

Пока у него с осмысленностью простейших операций не очень. А тут одно деление на 256 чего стоит :)

2c0smo

выложите новый скетч с вынесенными переменными и с комментариями к строкам.
начиная со строки

timer = millis();

которые вы не используете ниже :)

и вставьте в 49 строку Serial.println(timeString); -посмотрите в мониторе тоже "0012"?

c0smo
Offline
Зарегистрирован: 19.02.2016

Sr.FatCat 


#include "SevSeg.h"


SevSeg myDisplay; //Cоздаём объект

//Глобальные переменные
unsigned long timer;
int deciSecond = 0;

void setup()
{

  int displayType = COMMON_CATHODE; // Тип дисплея катод
   
   //декларируем  пины подключения индикатора
   int digit1 = 8; //Pin 1
   int digit2 = 5; //Pin 10
   int digit3 = 11; //Pin 4
   int digit4 = 13; //Pin 6


   int segA = 7; //Pin 12
   int segB = 6; //Pin 11
   int segC = 10; //Pin 3
   int segD = 3; //Pin 8
   int segE = 9; //Pin 2
   int segF = 4; //Pin 9
   int segG = 2; //Pin 7
   int segDP= 12; //Pin 5

   int numberOfDigits = 4; //Количество сегментов индикатора 4

  //что то для работы индикатора
  myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP);
  
  myDisplay.SetBrightness(100);//100% яркость

  timer = millis(); //Возвращает количество миллисекунд с момента начала выполнения текущей программы
 
  
}
  //Переменные для часов тоже из примера
  int n = 0; 
  int hours = 00;
  int minutes = 00;
  int elapsedMinutes = 0;
  int seconds = 0;
  
 
void loop() {

 
  char timeString[100]; //Используется для sprintf
  sprintf(timeString, "%02d%02d", seconds); //Запись значеия в строку с 2-мя лидирующими нулями 
  
  myDisplay.DisplayString(timeString, 0); //Вывод значения на индиактор?

  Serial.println(timeString);
 
 //здесь странная логика вычисления временя из примера
  unsigned long time = millis() - (elapsedMinutes * 60000);
  seconds = ((time / 1000) % 60);
  if (seconds > 60) {
    seconds = 0;
    minutes++;
    elapsedMinutes++;
    if (minutes >= 60) {
      minutes = 0;
      hours++;
      if (hours > 23) {
        hours = 0;
      }
    }
  }
  n = (hours * 100) + minutes;
}

после добавления строки Serial.println(timeString); , что то стало вычистятся(не корректно конечно) но это уже прорыв!) см.видео ( https://yadi.sk/i/AqEbOD6PpApnz )

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

c0smo, в 54 
должно быть sprintf(timeString, "%02i%02i", hours, minutes);

и все-таки не ясна конечная цель. Если вы хотите хоть как-то поизучать с/с++ то стоит как-то внимательнее, что ли примеры
посмотреть, книжки проглядеть от начала, хотя бы до середины.

А каждую строчку исправлять он-лайн как-то не очень эффективно. Я написал, что timer не используете, но вы так и не используете.

Да и дальше такой бред....

 

c0smo
Offline
Зарегистрирован: 19.02.2016

Спасибо, Sr.FatCat ,.... осознал что я ничо не понимаю )

Продолжил ковырять скеч и теперь всё работает. Хотя видно что примерно пару раз за 10 секунд, эти секунды перескакивают быстрее чем положенно, и думаю что время будет сильно улетать вперед. Думаю над коррекцией, вроде как можно сделать  относительно частоты кварца, но сначала я прикручу к скечу кнопки настройки. А пока вот рабочий вариант.

 

#include "SevSeg.h"

SevSeg myDisplay; 

void setup()
{
   int displayType = COMMON_CATHODE; 
  
   int digit1 = 8; //Pin 1
   int digit2 = 5; //Pin 10
   int digit3 = 11; //Pin 4
   int digit4 = 13; //Pin 6

   int segA = 7; //Pin 12
   int segB = 6; //Pin 11
   int segC = 10; //Pin 3
   int segD = 3; //Pin 8
   int segE = 9; //Pin 2
   int segF = 4; //Pin 9
   int segG = 2; //Pin 7
   int segDP= 12; //Pin 5
   
   int numberOfDigits = 4;
   
  myDisplay.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP);
  myDisplay.SetBrightness(100);
}

  unsigned long lastTick = 0; 
  unsigned int seconds = 1; 
  unsigned int minutes = 0; 
  unsigned int hours = 0; 
 
void loop() { 
  char timeString[10]; 
  sprintf(timeString, "%02d%02d", minutes, seconds); 
  myDisplay.DisplayString(timeString, 0);

    if (millis() - lastTick >= 1000) { 
         seconds++; 
     if (seconds==60) 
        {minutes++; 
         seconds=0; 
         } 
        if(minutes==60) 
        { hours++; 
          minutes=0; 
        } 
        lastTick = millis(); 
      } 
} 

 

Sr.FatCat
Offline
Зарегистрирован: 19.02.2016

маленькая подсказка: инициализировать время в setupможно через время компиляции скетча: системная константа __TIME__

Типа

  char compileTime[] = __TIME__; 
  char time_str_buf[3] = "\0\0";
  strncpy(time_str_buf, compileTime, 2);
  hours = atoi(time_str_buf);
  strncpy(time_str_buf, compileTime+3, 2);
  minutes = atoi(time_str_buf);
  strncpy(time_str_buf, compileTime+6, 2);
  seconds = atoi(time_str_buf);

 

 

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

RTC успешно реализуется на атмега8 - ставим тактирование от внутреннего осциллятора и подключаем часовой кварц.

здесь теория, даже с усыплением камня http://microcontrollerov.net/microcontrolleri/mega/AVR134-Chasy-Realnogo-Vremeni-na-osnove-Asinhronnogo-Tajmera

а, это то, что я использую для атмега8. где t - секунды


//

volatile unsigned long t = 0;

ISR (TIMER2_OVF_vect) {++t;} // обработка событий по прерыванию счётчика

void setup() {
///////////////////////////////////////////////////////////////////
cli(); // запрет прерываний глобально
TIMSK &= ~(_BV(TOIE2) | _BV(OCIE2)); // отключение прерывания Таймера 2
ASSR |= _BV(AS2); // перевод Таймера 2 в асинхронный режим тактирования от кварцевого резонатора 32768Гц
TCNT2 = 0x00; // начальная инициализация счётчика
TCCR2 = 0x05; // установка коэффициента деления 128
OCR2  = 0x00; // совпадение с частотой 1 Гц
while (ASSR & (_BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB))); // ждём готовности таймера
TIMSK |= _BV(TOIE2); // разрешаем прерывание от Таймера 2
sei(); // разрешаем прерывания глобально
///////////////////////////////////////////////////////////////////

}

void loop() {}

 

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

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

// analogWrite( 9, 240); // юстировка крайнего максимального положения стрелки измерительной головки
analogWrite(9, (t - ((t / 3600) * 3600)) * 240 / 3599); // минуты
analogWrite(10, (t - ((t / 86400) * 86400)) * 240 / 86399); // часы

Otto
Offline
Зарегистрирован: 26.06.2016

Спасибо примеры без RTC часов.