Часовник на живота Линеен часовник Десетичен часовник 16-ични часовници Във Варна е

Необслужваем часовник

Лъчезар Ил. Георгиев, катедра КНТ, ФИТА, ТУ–Варна (lig@tu-varna…)

В  казармата през 1979 г. по ТНТМ направих прост електромеханичен часовник, който автоматично включваше звънеца съгласно разписанието, на основата на голям корабен часовник, чиято пружина се навива веднъж на 2 седмици. Циферблата замених с печатна платка с писти, по които се плъзгаха запоени за стрелките контакти. Но контактът на минутната стрелка трябваше често да се почиства и поправя и когато се уволних, на никого не му се е занимавало с това и часовникът беше набързо „пенсиониран“. Едновременно с мен в друго наше поделение Юлиян Пенев и Иван Бончев направиха свой, по-съвършен часовник – цифров, който вършеше същата работа, без да има нужда от такова обслужване и затова предполагам, че е бил използван много по-дълго от моя. Между другото, поразително е, че и досега в училищата у нас включват звънците ръчно, при положение че в днешно време за целта може да се използва готово компютърче, чието програмиране е детска игра в сравнение с направата на часовник като нашите!

Имайки горчивия опит от тогава, реших цифровият часовник, идеята за който се зароди у мен преди година и нещо, да не се нуждае от никакво (подчертавам – никакво!) обслужване. Но това, разбира се, не означава, че няма да се нуждае от ремонт. Колкото и надеждни да са частите му, все някога нещо ще му се повреди. Възможно е също да се промени адресът на сървъра за време и какво ли още не. А аз няма вечно да бъда в катедрата. Един ден, живот и здраве, ще дойде време за пенсия. Това е и целта на тази страничка – да даде достатъчно информация на този, който евентуално ще реши да се заеме с това, за да може да извърши ремонта или промяната, когато се наложи. Надявам се, че този часовник няма да последва съдбата на гореспоменатия електромеханичен часовник или поне това няма да стане веднага след като вече няма да мога да го поддържам. Във всеки случай благодаря на всеки, който би се захванал с него след мен!

И  така, реших да направя необслужваем часовник за катедрата, който да се вижда още от началото на коридора на партера на ЕФ, за разлика от големия часовник с лампи с нажежаема жичка на доц. Митко Димчев, който не е необслужваем и се вижда само на III етаж. Мислех да го синхронизирам с предавателя DCF на 77,5 kHz в Майнфлинген, използвайки готова програма за управление с евентуални изменения. Решението на французина Брюно Гаво с динамична индикация ми хареса поради простотата си. Затова тръгнах от него и направих промени, необходими за светодиодните индикатори със 100-милиметрови цифри (по-високо захранващо напрежение и по-голям консумиран ток). И така, ето принципната електрическа схема и разположението на елементите върху печатната платка. Върху оригиналния код на Гаво (за който му изказах голямата си благодарност) направих следните промени (получавайки този код):

--- dcf77led.c-	2005-12-03 03:18:58 +0200
+++ dcf77led.c	2014-07-31 09:01:56 +0200
@@ -1,7 +1,7 @@
 /* DCF-77 LED CLOCK
  *
- * PIC16F84A
- * 10 Mhz crystal, HS clock
+ * PIC16F84A / PIC16F716
+ * 3.2768 Mhz crystal, HS clock
  *
  * PORTA.0->3, out : 7 segment cathod control
  * PORTA.4, in ; DCF pulse input
@@ -17,16 +17,16 @@
 /*
  * constant definitions
  */
-#define MAXCOUNT	9766	// number of TMR0 overflows in 1 second
-#define ADJUST		96	// extra ticks in 1 second
+#define MAXCOUNT	3200	// number of TMR0 overflows in 1 second
+#define ADJUST		0	// extra ticks in 1 second
 
 /*
  * this values are reduced in practice
  * to give some flexibility to DCF-77 pulse reception
  */
-#define timer_d_min 14000	// number of TMR0 overflows in 2 seconds : 19531
-#define timer_h_0 640		// number of TMR0 overflows in 0.1 second : 976
-#define timer_h_1 1400		// number of TMR0 overflows in 0.2 second : 1953
+#define timer_d_min 5120	// number of TMR0 overflows in 2 seconds : 6400
+#define timer_h_0 192		// number of TMR0 overflows in 0.1 second : 320
+#define timer_h_1 512		// number of TMR0 overflows in 0.2 second : 640
 
 /*
  * RAM variables
@@ -38,7 +38,7 @@
 unsigned char	parity ;	// count of positive bits received
 unsigned char	full = 0 ;	// set to 1 when DCF frame is complete
 unsigned char	locked = 0 ;	// set to 1 when clock has been adjusted
-unsigned char	mode = 1 ;	// 0:positive logic receiver, 1:negative logic receiver
+unsigned char	mode = 0 ;	// 0:positive logic receiver, 1:negative logic receiver
 unsigned char	mn ;		// next minutes in DCF frame
 unsigned char	hh ;		// next hours in DCF frame
 unsigned int	scaler ;	// count of TMR0 overflows for RTC
@@ -54,8 +54,8 @@
 unsigned char	i ;		// general purpose register
 
 /*
- * interrupt routine called 2500000/256 times by seconds :
- * the register TMR0 is increased each 4 clock cycles (quartz frequency is 10 Mhz),
+ * interrupt routine called 819200/256 times by seconds :
+ * the register TMR0 is increased each 4 clock cycles (quartz frequency is 3.2768 Mhz),
  * and overflows when reseting from 255 to 0,
  * fetching to the interrupt precedure with bit T0IF set
  */
@@ -74,7 +74,7 @@
 				bitnum = 0 ;			// yes, reset bit number
 				if(full)			// is the DCF frame complete ?
 					{
-					rhh = hh ;		// yes, set hours, min and seconds of RTC
+					rhh = hh < 23 ? hh + 1 : 0 ;// yes, set hours, min and seconds of RTC
 					rmn = mn ;
 					rss = 0 ;
 					scaler = 0 ;		// reset my scaler

Не щеш ли, се оказа, че дори и най-добрият приемник на сигнала от гореспоменатия предавател с амплитудна демодулация не може да се справи с катастрофално ниското съотношение сигнал / шум в близост до часовника или при включен кабел към него. И при двата приемника, които изпробвах (на „Конрад“ и на „HKW-Електроник“) резултатите бяха плачевни. Имаше възможност да се направи и цифров приемник с фазова демодулация (например този на англичанина д-р Стийв Марчънт), но къде е гаранцията, че и този много по-сложен приемник ще свърши работа? Тогава, за да спася проекта, реших да заменя приемника с преобразувател от NTP към DCF. За щастие се оказа, че швейцарецът Алексондр Сютер съвсем наскоро вече бил направил точно такъв преобразувател! С показаните по-долу промени (получавайки този архив на цялата програма) той ми свърши чудесна работа, за което сърдечно му благодарих:

--- ntp2dcf.in0	2014-10-20 12:05:58.000000000 +0300
+++ ntp2dcf.ino	2014-11-24 18:57:12.000000000 +0200
@@ -32,18 +32,18 @@
 
 
 // set to 1 to enable serial output, 0 to disable
-#define DEBUG 0
+#define DEBUG 1
 
 // this is the pin used to output the DCF77 signal; don't forget that 10-13 are used by the ethernet shield
 const int DCFOUT = 9;
 
 // if your ethernet shield came with a MAC address, you can enter it here
-byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
+byte mac[] = { 0x00, 0x08, 0xDC, 0x11, 0x22, 0x33 };
 
 // enter the IP address of the NTP server you intend to use.
 // please pay attention to the usage rules - best would be to use a local one synced to a pool of servers
 // see http://support.ntp.org/servers
-IPAddress timeServer(192, 168, 0, 1);
+IPAddress timeServer(10, 254, 254, 208);
 
 // assumed delay (in ms) to receive and process NTP info - this is added to the received timestamp
 const unsigned int assumedDelay = 25;
@@ -76,14 +76,11 @@
     delay(250);
     Serial.println("NTP to DCF77");
   #endif
-  if (Ethernet.begin(mac) == 0) {
-    // no point in carrying on, so do nothing forevermore:
-    while (1) {
-      #if DEBUG
-        Serial.println("Failed to configure Ethernet using DHCP");
-      #endif
-      delay(10000);
-    }
+  while (Ethernet.begin(mac) == 0) {
+    #if DEBUG
+      Serial.println("Failed to configure Ethernet using DHCP, will try again...");
+    #endif
+    delay(10000);
   }
   #if DEBUG
     Serial.print("IP number assigned by DHCP is ");
@@ -99,7 +96,7 @@
 
 void loop()
 {  
-  if (timeStatus() != timeNotSet) {
+  if (timeStatus() == timeSet) {
     if (now() != lastUpdate) { // new pulse every second
       lastUpdate = now();
       uint8_t curSec = second();
@@ -144,7 +141,7 @@
         digitalClockDisplay();
       #endif
     }
-    if (outOff < millis()) {
+    if ((signed long)(outOff - millis()) < 0) {
       digitalWrite(DCFOUT, LOW);
     }  
   }
@@ -294,7 +291,7 @@
   #endif
   sendNTPpacket(timeServer);
   uint32_t beginWait = millis();
-  while (millis() - beginWait < 1500) {
+  while ((signed long)(millis() - beginWait) < 1500) {
     int size = Udp.parsePacket();
     if (size >= NTP_PACKET_SIZE) {
       #if DEBUG

Замяната на условието на проверката в промяната около ред №100 е продиктувана от необходимостта да се спре изпращането на данни към часовника, ако поредният опит за синхронизация по NTP се провали. Работата е там, че на „Ардуино Уно“ (за разлика от „Дуемиланове“) вместо кварцов резонатор има керамичен, който за 10 минути успява да изостане с до 1 секунда! Затова до следващата синхронизация по NTP часовникът се оставя да върви с точността на своя собствен кварцов резонатор, който избързва с по-малко от секунда на денонощие. Промяната около ред №300 всъщност не е задължителна и е само за уеднаквяване на стила с тази около ред №150, която е необходима за обработка на превъртането на променливата за милисекундите веднъж на 49¾ денонощия. Останалите промени са очевидни от самия код и мисля, че не се нуждаят от отделно обяснение.

След години може да се наложи да се променят правилата за лятното часово време на редове №№ 52–54. (Текущите правила са въведени у нас през 1999 г.) Трябва да се има предвид, че часовникът измества с един час напред приетото от него време – вж. промените в управляващата го програма по-горе. Възможно е и лятното часово време да бъде отменено (колкото по-рано стане това, толкова по-добре). Надявам се, че ако (когато) се наложат такива промени, изходните текстове ще могат успешно да се компилират с компилатора от средата за програмиране на „Ардуино“, която ще бъде налична тогава (или поне „класическата“ 1.0.6, която използвам аз), както и да бъде препрограмиран от нея едночиповият микрокомпютър на „Ардуино Уно“. В противен случай може да се наложи да се прочете, промени и препрограмира съдържанието на постоянната му памет с програматор, което би било много по-неудобно.


Всичко това показва силата на открития код. А представете си какво щеше да стане, ако се беше образувал и межународен колектив за разработка на оптимално решение на проблема. Именно в такива случаи най-категорично личи предимството на модела на работа с открит код пред собственическия. Затова съм твърдо убеден, че бъдещето е именно на открития код и най-вече на свободното програмно осигуряване, чийто манифест бе публикуван още през 1985 г. от Ричард Столман. (Надявам се, че ще се намери кой да го преведе и на български, но щом дори и химнът му, който е с мелодията на българска народна песен, още не е преведен… Макар че мерена реч се превежда много по-трудно.) Впрочем, ОПОП ГНУ е малко или много американоцентрично и затова вече има не само ПЛЕС, но и РРЛСП.

SuperGNU+Tux