Обсуждаем контроллеры компании Atmel.
Ответить

Перевод времени в аналоговых часах. (Код или алгоритм).

Ср ноя 20, 2019 12:06:56

Привет.
Сделал часы с автоматической коррекцией времени. Часы имеют обычный двенадцати часовой циферблат со стрелками. Соответственно время можно переводить либо вперед, либо назад.
Эталонное время получаю из интернета или RTC в формате HH:MM:SS .
Пока придумал такой алгоритм:
Вычисляю разницу в секундах, ели число положительное, значит, часы отстают и стрелки нужно перевести вперед, если разница отрицательная – то назад. Так как циферблат двенадцати часовой, нужно привести время к соответствующему формату.

Код:

/*
s  – текущее время, секунды
m  – текущее время, минуты
h  – текущее время, часы

ss  – эталонное  время, секунды
mm  – эталонное  время, минуты
hh  – эталонное  время, часы
*/


  if (h  > 12) h = h  - 12;    // привести к 12 часовому виду
  if (hh > 12) hh= hh - 12;

  long sec  = (ss - s) +
              (mm - m) * 60L +
              (hh - h) * 3600L;

  long rev = 43200L - sec ;   // направление  + по часовой - против
  if (rev < sec )  sec =-rev;   // куда ближе крутить стрелки





Вроде все работает. (уже неделю =))
Может, есть другие алгоритмы или идеи?

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Чт ноя 21, 2019 21:58:12

Допустим, на часах 11:55. А фактическое время 12:10. По вашему алгоритму они будут крутиться против часовой 11 часов 45 минут.
Ну или я на ночь глядя неправильно что-то понял. )

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Пт ноя 22, 2019 11:19:40

Приветствую. Да, есть проблемы с выбором направления вращения в некоторых случаях. Но по вашему примеру должно быть правильно.

Допустим, на часах 11:55. А фактическое время 12:10...
Ну или я на ночь глядя неправильно что-то понял. )


Результат в переменной sec = 900 (сколько секунд)

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Пт ноя 22, 2019 12:49:31

Да, на ночь глядя внимание фиговое. Вчера мне показалось что if из hh вычтет 12 и сделает его равным 0.
Ну хорошо, а если на часах 11:55. А фактическое время 13:10.

ss = s = 0
m = 55; mm = 10
h = 11; hh = 13

После if'ов: h = 11; hh = 1

sec = (10 - 55) * 60 + (1 - 11) * 3600 = -38700
rev = 81900
Последний раз редактировалось NStorm Пт ноя 22, 2019 14:41:17, всего редактировалось 1 раз.

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Пт ноя 22, 2019 12:58:08

Может считать все в секундах, типа
12:10=43'800
11:55=42'900
Значит нужно перевести стрелки на 900 секунд вперед.

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Пт ноя 22, 2019 14:42:58

akl, так он и считает в секундах, только в 12-часовом формате. И 13:00:00 становятся 01:00:00 при расчетах перемотки.

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Пт ноя 22, 2019 19:58:37

Если проверку времени делать на линейном участке циферблата, то первый мой вариант вроде работает не плохо. Если между 12-час и 1-час тут непонятно что получится.
На собранных часах (сделал 3 шт.) проверяю время раз в сутки в 21 час. Разница несколько секунд успешно корректируется. Все три экземпляра идут почти секунда в секунду уже больше недели.
Вот написал другой код, должен работать лучше, хотя х.з.

Код:


/*
s  – текущее время, секунды
m  – текущее время, минуты
h  – текущее время, часы

ss  – эталонное  время, секунды
mm  – эталонное  время, минуты
hh  – эталонное  время, часы
*/

uint8_t h = 12,
        m = 55,
        s = 33;


for (uint8_t i=0; i<23;i++)
 {

uint8_t hh = i,
        mm = 10,
        ss = 33;



Serial.print ("Time: ");
Serial.print (h);
Serial.print (":");
Serial.print (m);
Serial.print (":");
Serial.print (s);
Serial.print (" >>> ");
Serial.print (hh);
Serial.print (":");
Serial.print (mm);
Serial.print (":");
Serial.println (ss);


  if (h  > 12) h = h  - 12;    // привести к 12 часовому виду
  if (hh > 12) hh= hh - 12;

 
  // Первый результат. Смещение в секундах. 
  // Положительное число вращение вправо (по часовой стрелке),
  // Отрицательное  -  влево (против  часовой стрелки).

  long sec  = (ss - s) +
              (mm - m) * 60L +
              (hh - h) * 3600L;


  // Если применить абсолютные значения можно узнать оба (влево, вправо) смещения.
  // Но при этом потеряем направление вращения.
 
  long var1  = abs(sec);          // Прямое  направление
  long var2  = 43200L - var1;     // Противоположное направление (43200 = 12 часов * 3600 секунд)


Serial.print ("Variant 1: ");
Serial.println (var1);
Serial.print ("Variant 2: ");
Serial.println (var2);

// Получаем направление вращения, но тут я не уверен…   
// Выбираем наименьшее значение смещения.
// Если первоначальное направление в право, меняем на противоположное.

 
  if (var2 < var1 )
   {
   if (sec > 0)  sec=-var2;  else  sec=var2; // Волшебство =)   
   }




Serial.print ("Select: ");
Serial.print(sec);
Serial.print (" >>> ");

sec = abs(sec);
 
 hh =  sec / 3600;
 mm = (sec - hh * 3600) / 60;
 ss =  sec - hh * 3600 - mm * 60;


Serial.print (hh);
Serial.print (":");
Serial.print (mm);
Serial.print (":");
Serial.println (ss);


Serial.println("----------");
 }


delay(5000);




Вывод терминала
Спойлер
Код:

Time: 12:55:33 >>> 0:10:33
Variant 1: 45900
Variant 2: -2700
Select: -2700 >>> 0:45:0
----------
Time: 12:55:33 >>> 1:10:33
Variant 1: 42300
Variant 2: 900
Select: 900 >>> 0:15:0
----------
Time: 12:55:33 >>> 2:10:33
Variant 1: 38700
Variant 2: 4500
Select: 4500 >>> 1:15:0
----------
Time: 12:55:33 >>> 3:10:33
Variant 1: 35100
Variant 2: 8100
Select: 8100 >>> 2:15:0
----------
Time: 12:55:33 >>> 4:10:33
Variant 1: 31500
Variant 2: 11700
Select: 11700 >>> 3:15:0
----------
Time: 12:55:33 >>> 5:10:33
Variant 1: 27900
Variant 2: 15300
Select: 15300 >>> 4:15:0
----------
Time: 12:55:33 >>> 6:10:33
Variant 1: 24300
Variant 2: 18900
Select: 18900 >>> 5:15:0
----------
Time: 12:55:33 >>> 7:10:33
Variant 1: 20700
Variant 2: 22500
Select: -20700 >>> 5:45:0
----------
Time: 12:55:33 >>> 8:10:33
Variant 1: 17100
Variant 2: 26100
Select: -17100 >>> 4:45:0
----------
Time: 12:55:33 >>> 9:10:33
Variant 1: 13500
Variant 2: 29700
Select: -13500 >>> 3:45:0
----------
Time: 12:55:33 >>> 10:10:33
Variant 1: 9900
Variant 2: 33300
Select: -9900 >>> 2:45:0
----------
Time: 12:55:33 >>> 11:10:33
Variant 1: 6300
Variant 2: 36900
Select: -6300 >>> 1:45:0
----------
Time: 12:55:33 >>> 12:10:33
Variant 1: 2700
Variant 2: 40500
Select: -2700 >>> 0:45:0
----------
Time: 12:55:33 >>> 13:10:33
Variant 1: 42300
Variant 2: 900
Select: 900 >>> 0:15:0
----------
Time: 12:55:33 >>> 14:10:33
Variant 1: 38700
Variant 2: 4500
Select: 4500 >>> 1:15:0
----------
Time: 12:55:33 >>> 15:10:33
Variant 1: 35100
Variant 2: 8100
Select: 8100 >>> 2:15:0
----------
Time: 12:55:33 >>> 16:10:33
Variant 1: 31500
Variant 2: 11700
Select: 11700 >>> 3:15:0
----------
Time: 12:55:33 >>> 17:10:33
Variant 1: 27900
Variant 2: 15300
Select: 15300 >>> 4:15:0
----------
Time: 12:55:33 >>> 18:10:33
Variant 1: 24300
Variant 2: 18900
Select: 18900 >>> 5:15:0
----------
Time: 12:55:33 >>> 19:10:33
Variant 1: 20700
Variant 2: 22500
Select: -20700 >>> 5:45:0
----------
Time: 12:55:33 >>> 20:10:33
Variant 1: 17100
Variant 2: 26100
Select: -17100 >>> 4:45:0
----------
Time: 12:55:33 >>> 21:10:33
Variant 1: 13500
Variant 2: 29700
Select: -13500 >>> 3:45:0
----------
Time: 12:55:33 >>> 22:10:33
Variant 1: 9900
Variant 2: 33300
Select: -9900 >>> 2:45:0
----------






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

Добавлено after 2 minutes 51 second:
P.S.
За Ардуину не ругайте, это только для отладки =)
:)

Добавлено after 46 minutes 28 seconds:
Да, на ночь глядя внимание фиговое. Вчера мне показалось что if из hh вычтет 12 и сделает его равным 0.
Ну хорошо, а если на часах 11:55. А фактическое время 13:10.

ss = s = 0
m = 55; mm = 10
h = 11; hh = 13

После if'ов: h = 11; hh = 1

sec = (10 - 55) * 60 + (1 - 11) * 3600 = -38700
rev = 81900


Сейчас проверил.

Первый алгоритм (в принципе верно, но направление вращения не верное):
Код:
Текущее время: 11:55:33 >> 1:10:33
Выбрано: 10:45:00 ( -38700 )


Второй алгоритм (тут лучше):
Код:
Текущее время: 11:55:33 >> 1:10:33
Вариант 1: 10:45:00 ( 38700 )
Вариант 2: 01:15:00 ( 4500 )
Выбрано: 01:15:00 ( 4500 )

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Сб ноя 23, 2019 12:49:41

а если возьмем наоборот - эталонное 11:55, а текущее 1:10.
в какую сторону и на сколько у тебя будет крутить?

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Сб ноя 23, 2019 23:28:30

Если ни у кого нет идей а только вопросы “Куда оно будет крутить ?”
Вот сделал эмулятор, этого алгоритма.

Эээ...мулятор

Если, что, писал на коленке, да и засыпаю уже, пойду чай пить и спать… :)

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вс ноя 24, 2019 13:18:43

а мне вот непонятно, зачем из 24-часового формата переводить в 12-часовой?

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вс ноя 24, 2019 13:38:06

Потому что сегментов на циферблате 12.

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вс ноя 24, 2019 20:35:06

ну и что?
зачем из 13 часов вычитать 12, а потом ломать голову, как из 1 часа скорректировать к 11 часам?
если сразу можно вычислить, сколько секунд будет в 13:10 и сразу пересчитать к 11:55.

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вс ноя 24, 2019 20:44:11

шаговые моторы во 2часах НЕРЕВЕРСИВНЫЕ питаются 1ф разнополяркой --П---U---П----U---
пауза +30в пауза 2минута =-пауза 3мин +30в пауза4 мин-пауза и ТД
так что про перевод протиф часовой сразу забудте!!!

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Пн ноя 25, 2019 22:51:25

ну и что?
зачем из 13 часов вычитать 12, а потом ломать голову, как из 1 часа скорректировать к 11 часам?
если сразу можно вычислить, сколько секунд будет в 13:10 и сразу пересчитать к 11:55.


Чем меньше числа, тем меньше переменные, тем меньше и быстрее программа. Попробуйте впихнуть код в attiny13 и познаете дзен.
А вообще, в 12 часовом циферблате, при переводе времени используется только +6 или -6 часов, остальное излишне =) Если стрелки можно крутить в обе стороны.

Добавлено after 5 minutes 42 seconds:
шаговые моторы во 2часах НЕРЕВЕРСИВНЫЕ питаются 1ф разнополяркой --П---U---П----U---
пауза +30в пауза 2минута =-пауза 3мин +30в пауза4 мин-пауза и ТД
так что про перевод протиф часовой сразу забудте!!!

Что мешает поставить шаговик который крутится в обе стороны? Если нет возможности вращать стрелки против часовой, можно подождать (пропустить некоторое количество секунд), для точной настройки времени, если часы пропустят минуту , этого ни кто и не заметит. Тут много вариантов.

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вт ноя 26, 2019 07:20:45

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

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вт ноя 26, 2019 08:48:01

Да ладно. На 10..20% всего. И всё зависит от умения готовить как с одной, так и с другой стороны.)

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вт ноя 26, 2019 12:00:16

только часы: Y=(((X2-X1)+18)%12)-6
или в секундах
signed int dT= ((unsigned long int)(((((H2-H1)*60+M2-M1)*60)+C2-C1)+(18*60*60-1))%(12*60*60))-(6*60*60-1);
-1 это для того, чтобы при ровно 6 часах разницы часы пошли вперед, а не назад...

Добавлено after 2 hours 34 minutes 7 seconds:
или, чтобы с большими числами не работать, можно подводить по частям...
signed int dT=( (unsigned char)(H2-H1+30)%12)-6; //поддерживается 12 и 24 часовой формат в любом сочетании
dT*=60;
dT+=((unsigned char)(M2-M1+90)%60)-30;
dT*=60;
dT+=((unsigned char)(C2-C1+90)%60)-30;

вроде тоже должно нормально заработать...

Добавлено немного погодя:
Вот бы ещё мозги у часов могли бы определять реальное положение стрелок... в шестернях стрелок просверлить по дырочке, чтобы эти дырочки сходились в полночь и оптопару...

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вт ноя 26, 2019 17:53:30

signed int dT= ((unsigned long int)(((((H2-H1)*60+M2-M1)*60)+C2-C1)+(18*60*60-1))%(12*60*60))-(6*60*60-1);

Огромное спасибо за формулу, даже не думал что кто-то поможет с кодом.
signed int dT=( (unsigned char)(H2-H1+30)%12)-6; //поддерживается 12 и 24 часовой формат в любом сочетании
dT*=60;
dT+=((unsigned char)(M2-M1+90)%60)-30;
dT*=60;
dT+=((unsigned char)(C2-C1+90)%60)-30;

вроде тоже должно нормально заработать...

То что поддерживается 24 часовой формат, понятно ведь %12 как раз и приводит к такому формату…
Вот с остальным не совсем понятно откуда 90 и 30
Если возможно, напиши код для часов и минут. Ну, или алгоритм расчета. Заранее благодарю.

Вот бы ещё мозги у часов могли бы определять реальное положение стрелок... в шестернях стрелок просверлить по дырочке, чтобы эти дырочки сходились в полночь и оптопару.

Делал когда-то нечто подобное, только оптопара была под часовой стрелкой, на циферблате.
Удалось даже обойтись одним датчиком, так как, часовая стрелка загораживает его дольше, чем минутная.
Если у часов автономное питание, смысла в этом нет. Время выставляется только при включении, потом можно просто запоминать положение стрелок даже перед выключением.

Добавлено after 8 minutes 4 seconds:
чтобы легко впихнуть код в attiny13, нужно писать на ассемблере.

Пробовал, не понравилось :)
Делал опрос термодатчика, разница получилась около 100 байт… На эмуляторе работало на ура, по факту ассемблерный код на схеме не заработал. Самая большая проблема в ассемблере, для меня, по крайней мере, сделать аналог _delay_ms(); _delay_us();

Re: Перевод времени в аналоговых часах. (Код или алгоритм).

Вт ноя 26, 2019 19:10:54

мне вообще функция остатка от деления нравится,
например какой нибудь двунаправленый кольцевой счетчик: 0<=i<n
i=i±x
i=(i mn)%n
где m - целое число (mn не дают остатка)
n - длина счетчика
x - какоето число, изменяющее счётчик, x<mn
диапазон можно сдвинуть: k<=i<(n+k)
i=((i-k+mn)%n)+k;
важно только проследить, чтобы не было переполнения по вместимости переменной...
вот и в том примере длина = сутки, смещение = -полсуток...
а потом тоже, но по частям, сначала часы (длина 12, смещение -6), потом переведя в минуты - минуты (длина 60, смещение -30), и наконец секунды...
правда код я не проверял, но, думаю, он заработает
Ответить