часы и термометр - помогите найти ошибки
- Войдите на сайт для отправки комментариев
Вс, 19/02/2012 - 23:02
собрал скетч часов и градусника.не написал а собрал из нескольких примеров.
в скетче есть вычисление дня недели, и он работает , но после правильных показаний на экране появляются не правильные , не могу понять из за чего это происходит .
вместо воскресенья пишет что сегодня четверг .
Помогите найти ошибку , и если есть желание то укажите как можно улучшить скетч .
Спасибо.
#include <WProgram.h> #include <Wire.h> #include <DS1307.h> #include <OneWire.h> #include <Time.h> #include <LiquidCrystal.h> OneWire ds(9); // датчик ds18b20 pin на 12 входе Ардуино unsigned long time_cam; byte i; byte present = 0; byte data[12]; byte addr[8]; enum { SYMBOL_HEIGHT = 8 }; byte cels[SYMBOL_HEIGHT] = { B01110, B10001, B10001, B01110, B00000, B00000, B00000, B00000, }; int HighByte, LowByte,Whole, Fract, TReading, Tc_100, HighTemp ; LiquidCrystal lcd(22, 24, 31, 30, 33, 32); // выводы lcd 4 6 11 12 13 14 //LiquidCrystal lcd(2, 3, 5, 4, 7, 6); int d, m, w, d1, y1, dmax, m1, a, b ,y , s_p; char* weekd[]= {"Sun", "Mon","Tue","Wed","Thu","Fri","Sat"}; char* mon[]={"Jan", "Feb" ,"Mar","Apr","May","Jun","Jul","Aug", "Sep","Oct","Nov","Dec"}; #define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by unix time_t as ten ascii digits #define TIME_HEADER 'T' // Header tag for serial time sync message #define TIME_REQUEST 7 // ASCII bell character requests a time sync message void setup() { if ( !ds.search(addr)) { time_cam = millis(); if ((millis()-time_cam) > 1000){ } ds.reset_search(); return; } Serial.begin(9600); lcd.createChar(1, cels); lcd.begin(20, 2); //setSyncProvider( requestSync); //set function to call when sync required //Serial.println("Waiting for sync message"); //lcd.print("Waiting for sync "); } void getTemp() { ds.reset(); ds.select(addr); ds.write(0x44,1); present = ds.reset(); ds.select(addr); ds.write(0xBE); for ( i = 0; i < 9; i++) { data[i] = ds.read(); } LowByte = data[0]; HighByte = data[1]; HighTemp = data[2]; TReading = (HighByte << 8) + LowByte; Tc_100 = (6 * TReading) + TReading / 4; Whole = Tc_100 / 100; Fract = Tc_100 % 100; } void loop(){ getTemp(); time_cam = millis(); if ((millis()-time_cam) > 1000){ } digitalClockDisplay(); if(Serial.available() ) { processSyncMessage(); } if(timeStatus()!= timeNotSet) { digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh digitalClockDisplay(); } delay(1000); // timeR = 0; } void digitalClockDisplay(){ // digital clock display of the time lcd.clear(); lcd.setCursor(0,0); lcd.print(RTC.get(DS1307_HR,true)); s_p = RTC.get(DS1307_SEC,false); if(s_p%2) {lcd.print(":");} else {lcd.print(".");} printDigits(RTC.get(DS1307_MIN,false)); lcd.print(" "); // расчет дня недели m=month(); y=year(); d=day(); a=(14-m)/12; y1=y-a; m1=m+12*a-2; w=(7000+(d+y1+y1/4-y1/100+y1/400+(31*m1)/12))%7; lcd.print(weekd[w]) ; lcd.print(" " ); lcd.print(RTC.get(DS1307_DATE,false)); lcd.print(" " ); m =RTC.get(DS1307_MTH,false) ; b = m - 1; lcd.print(mon[b]); lcd.print(" "); lcd.setCursor(0,1); lcd.print("modem "); lcd.print(Whole); /* lcd.print("."); if (Fract < 10) { lcd.print("0"); } lcd.print(Fract); */ lcd.print("\1C"); } void printDigits(int digits){ // utility function for digital clock display: prints preceding colon and leading 0 if(digits < 10) lcd.print('0'); lcd.print(digits); } void processSyncMessage() { // if time sync available from serial port, update time and return true while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits char c = Serial.read() ; Serial.print(c); if( c == TIME_HEADER ) { time_t pctime = 0; lcd.setCursor(11,1); lcd.print("test1"); for(int i=0; i < TIME_MSG_LEN -1; i++){ c = Serial.read(); if( c >= '0' && c <= '9'){ pctime = (10 * pctime) + (c - '0') ; // convert digits to a number } } setTime(pctime); // Sync Arduino clock to the time received on the serial port RTC.stop(); RTC.set(DS1307_SEC,second()); //set the seconds RTC.set(DS1307_MIN,minute()); //set the minutes RTC.set(DS1307_HR,hour()); //set the hours RTC.set(DS1307_DATE,day()); //set the date RTC.set(DS1307_MTH,month()); //set the month RTC.set(DS1307_YR,year()); //set the year RTC.start(); } } } time_t requestSync() { //Serial.print(TIME_REQUEST,byte); return 0; // the time will be sent later in response to serial mesg }
Первое: если у вас вопрос по конкретной проблеме, то зачем приводить код всего скетча? (кстати, оформите вычисление номера дня недели в виде отдельной функции - легче будет и вопросы ставить, и алгоритмы вычиления заменять в случае необходимости)
Второе: поищите в Тырнете информацию по теме "формула Зеллера". Например http://en.wikipedia.org/wiki/Zeller's_congruence
на счет функций конечно интересно , только в програмировании не силен , понять чужое пытаюсь , свое делать сложнее.
а код привел весь именно потому что не понимаю откуда вылезает неправильный день недели .
Строки 120-129 вынесите в отдельную функцию, назвав ее, например, calculateDayOfWeek.
Вместо строк 120-129 будет стоять, соответственно вызов этой функции:
calculateDayOfWeek();
Как минимум - будет видно, где же у вас вычисляется этот самый день недели.
Как максимум - если вы все же решитесь написать функцию для определения дня недели по формуле Зеллера, то оформив ее в виде функции, например с именем calculateDayOfWeekZeller, сможете без риска потереть что-нибудь лишнее переключаться между первой и второй функциями (а может быть - и третьей, и четвертой ...), пока не найдете наконец корректно работающий вариант.
правильно ли я оформил функцию ?
void weekdaycalc(int w){
m=month();
y=RTC.get(DS1307_YR,false);
d=day();
a=(14-m)/12;
y1=y-a;
m1=m+12*a-2;
w=(7000+(d+y1+y1/4-y1/100+y1/400+(31*m1)/12))%7;
}
и в чем плюсы формулы Зеллера перед той что использую я ?
что то не хочет функция работать , не отдает переменную " w" . подскажите что я не правильно делаю ?
и в чем плюсы формулы Зеллера перед той что использую я ?
Сначала о преимуществах формулы Зеллера:
- она проверена многократно бесчисленным количеством пользователей. То, что используется у вас, тоже, похоже растет из нее, но вместо логических операций при определении параметров m1 и y1 используются арифметические вычисления, что чревато побочными эффектами.
- она имеет более или менее подробные объяснения и вы уже не тупо повторяете написанное кем-то другим, а можете разобраться в том, что же, собственно, происходит.
О функции:
строку 1 ("void weekdaycalc(int w){") перепишите:
int weekdaycalc(){
после нее поставьте определение внутренней переменной w:
int w;
а перед завершающей скобкой поставьте
return w;
Вызов будет выглядеть, соответственно, не так:
weekdaycalc(w);
а так:
w=weekdaycalc();
И перейдите на осмысленные имена переменных. Вместо w используйте Week (WeekDay), вместо m - Month. Вам же легче будет ориентироваться в собственном коде. И поскольку вы утверждаете, что копируя куски кодов из разных источников собираетесь разобраться-таки в их сути, то это будет прекрасным поводом для того, чтобы осуществить декларируемое.
Процитирую самого себя:
и в чем плюсы формулы Зеллера перед той что использую я ?
Сначала о преимуществах формулы Зеллера:
- она проверена многократно бесчисленным количеством пользователей. То, что используется у вас, тоже, похоже растет из нее, но вместо логических операций при определении параметров m1 и y1 используются арифметические вычисления, что чревато побочными эффектами.
При использовании формулы Зеллера март имеет номер 3, апрель - 4 и так далее, январь - 13, февраль - 14.
А что в вашем алгоритме?
Февраль - m=2
a=(14-m)/12 -> 1 (предполагается целочисленная арифметика)
m1=m+12*a-2=2+12-2 -> 12, а надо бы 14 (конечно, это несоответствие, может быть, компенсируется в основной - длинной - формуле. Но ведь вполне возможно, что и не компенсируется! Но как это проверить без объяснения алгоритма?)
step962, огромное спасибо за помощь!
Никогда не учился программировать.И вот завел себе, на старости лет, головную боль :)
В описании ардуино нет ничего про такие тонкости как функции и правильная организация кода, а жаль .
мой пример должен выглядеть так ?
Не понимаю почему надо делать не void weekdaycalc а int weekdaycalc. В чем разница ? И где надо переменные прописывать которые в такой функции используются , в начале всего скетча или внутри функции ?
Еще раз спасибо за помощь и терпение .
Да - это правильный вариант - функция с возвращаемым значением, оперирующая глобальными переменными. В принципе, и значение можно не возвращать, т.е сделать void weekdaycalc(). Главное, что надо запомнить - параметры функции (т.е. передаваемые в нее как перечень значений в скобках - ваш первый вариант) вне функции остаются неизменными (даже если вы их изменяете внутри функции). Чтобы все-таки изменить параметр и снаружи, необходимо декларировать его не как переменную ("int w"), а как указатель на переменную ("int *w"). И в обращении к функции, соответственно, передавать не переменную ("weekdaycalc(w)"), а ее адрес ("weekdaycalc(&w)"). Сложновато? Поэтому лучше совсем без параметров, либо с единственным возвращаемым (через return).
Думаю вопрос с тем, где прописывать переменные, снят? На всякий случай - если переменные, используемые в функции, используются и вне ее, то их необходимо описывать как глобальные (в самом начале скетча), либо организовывать передачу через параметры функции (если переменная не изменяется - то передаем саму переменную, если необходимо получить назад измененное значение - пеердаем адрес внешней по отношению к функции переменной). Переменные, прописанные внутри функции за ее пределами не видны. Более подробно - читайте "видимость переменных", "области видимости" и пр.
Вопрос может немного не в тему. Как точно идут подобные часы и что будет при отключении питания?
Вопрос возник по той причине ,а зачем так допотопно . Существует нормальная система с DS1307 ,работает точно,даёт и день недели и т.п. Энергонезависима 10 лет.
часы и сделаны на RTC
а вот с днем недели в нем я не разобрался .
Извините ,не понял сразу.
Если часы на DS1307 ,там же есть и день недели. Зачем его вычислять.
У меня это выглядит так.
И вот уже много месяцев работает исправно. Могу точно утверждать т.к. основа именно на день недели (пятница).
У меня часы получают время от компьютера , и вот в той части скетча я не смог понять как задать день недели в rtc .
Ну, может быть, человеку сама задача интересна...
Если нет - то можно взять, например, библиотеку Time и получить в одном флаконе и поддержку DS1307, и INTP, и GPS-синхронизацию, и автоматическую настройку дня недели. Даже синхронизация с кампутером по USB/COM-линии там уже встроена. Если верить заявлениям на сайте arduino.cc.
ЗЫ: взглянул на скетч топик-мастера еще раз - похоже, эта библиотека в нем уже присутствует (если не одноименная). Ну, тогда остается на примеры по пользованию этой библиотекой взглянуть повнимательнее. В общем, братцы - RTFM.
Задача мне конечно интересна :)
Но я сам не смог понять как поправить тот фрагмент скетча что отвечает за получение времени от компа для установки дня недели в rtc .Видимо надо поправить и запрос и то что отсылается из процессинга на ардуину .
Если сможете мне обЪяснить то я конечно уберу лишние расчеты и скетч станет проще и правильнее .
Спасибо.
p.s. странный глюк , не могу в тексте использовать Ъ в нижнем регистре , вместо него шрифт в болд переключается
Вам видимо надо так:
RTC.set(DS1307_DOW,XXX);
Где ХХХ десятичное от 1-7
www.arduino.cc/cgi-bin/yabb2/YaBB.pl