часы и термометр - помогите найти ошибки
- Войдите на сайт для отправки комментариев
Вс, 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" . подскажите что я не правильно делаю ?
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; }и в чем плюсы формулы Зеллера перед той что использую я ?
Сначала о преимуществах формулы Зеллера:
- она проверена многократно бесчисленным количеством пользователей. То, что используется у вас, тоже, похоже растет из нее, но вместо логических операций при определении параметров m1 и y1 используются арифметические вычисления, что чревато побочными эффектами.
- она имеет более или менее подробные объяснения и вы уже не тупо повторяете написанное кем-то другим, а можете разобраться в том, что же, собственно, происходит.
О функции:
строку 1 ("void weekdaycalc(int w){") перепишите:
int weekdaycalc(){
после нее поставьте определение внутренней переменной w:
int w;
а перед завершающей скобкой поставьте
return w;
Вызов будет выглядеть, соответственно, не так:
weekdaycalc(w);
а так:
w=weekdaycalc();
И перейдите на осмысленные имена переменных. Вместо w используйте Week (WeekDay), вместо m - Month. Вам же легче будет ориентироваться в собственном коде. И поскольку вы утверждаете, что копируя куски кодов из разных источников собираетесь разобраться-таки в их сути, то это будет прекрасным поводом для того, чтобы осуществить декларируемое.
Процитирую самого себя:
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; }и в чем плюсы формулы Зеллера перед той что использую я ?
Сначала о преимуществах формулы Зеллера:
- она проверена многократно бесчисленным количеством пользователей. То, что используется у вас, тоже, похоже растет из нее, но вместо логических операций при определении параметров m1 и y1 используются арифметические вычисления, что чревато побочными эффектами.
При использовании формулы Зеллера март имеет номер 3, апрель - 4 и так далее, январь - 13, февраль - 14.
А что в вашем алгоритме?
Февраль - m=2
a=(14-m)/12 -> 1 (предполагается целочисленная арифметика)
m1=m+12*a-2=2+12-2 -> 12, а надо бы 14 (конечно, это несоответствие, может быть, компенсируется в основной - длинной - формуле. Но ведь вполне возможно, что и не компенсируется! Но как это проверить без объяснения алгоритма?)
step962, огромное спасибо за помощь!
Никогда не учился программировать.И вот завел себе, на старости лет, головную боль :)
В описании ардуино нет ничего про такие тонкости как функции и правильная организация кода, а жаль .
мой пример должен выглядеть так ?
int 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; return w; }Не понимаю почему надо делать не void weekdaycalc а int weekdaycalc. В чем разница ? И где надо переменные прописывать которые в такой функции используются , в начале всего скетча или внутри функции ?
Еще раз спасибо за помощь и терпение .
Да - это правильный вариант - функция с возвращаемым значением, оперирующая глобальными переменными. В принципе, и значение можно не возвращать, т.е сделать void weekdaycalc(). Главное, что надо запомнить - параметры функции (т.е. передаваемые в нее как перечень значений в скобках - ваш первый вариант) вне функции остаются неизменными (даже если вы их изменяете внутри функции). Чтобы все-таки изменить параметр и снаружи, необходимо декларировать его не как переменную ("int w"), а как указатель на переменную ("int *w"). И в обращении к функции, соответственно, передавать не переменную ("weekdaycalc(w)"), а ее адрес ("weekdaycalc(&w)"). Сложновато? Поэтому лучше совсем без параметров, либо с единственным возвращаемым (через return).
Думаю вопрос с тем, где прописывать переменные, снят? На всякий случай - если переменные, используемые в функции, используются и вне ее, то их необходимо описывать как глобальные (в самом начале скетча), либо организовывать передачу через параметры функции (если переменная не изменяется - то передаем саму переменную, если необходимо получить назад измененное значение - пеердаем адрес внешней по отношению к функции переменной). Переменные, прописанные внутри функции за ее пределами не видны. Более подробно - читайте "видимость переменных", "области видимости" и пр.
Вопрос может немного не в тему. Как точно идут подобные часы и что будет при отключении питания?
Вопрос возник по той причине ,а зачем так допотопно . Существует нормальная система с DS1307 ,работает точно,даёт и день недели и т.п. Энергонезависима 10 лет.
часы и сделаны на RTC
а вот с днем недели в нем я не разобрался .
Извините ,не понял сразу.
Если часы на DS1307 ,там же есть и день недели. Зачем его вычислять.
У меня это выглядит так.
И вот уже много месяцев работает исправно. Могу точно утверждать т.к. основа именно на день недели (пятница).
У меня часы получают время от компьютера , и вот в той части скетча я не смог понять как задать день недели в rtc .
173 void processSyncMessage() { 174 175 // if time sync available from serial port, update time and return true 176 while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits 177 char c = Serial.read() ; 178 Serial.print(c); 179 if( c == TIME_HEADER ) { 180 time_t pctime = 0; 181 lcd.setCursor(11,1); 182 lcd.print("test1"); 183 for(int i=0; i < TIME_MSG_LEN -1; i++){ 184 c = Serial.read(); 185 if( c >= '0' && c <= '9'){ 186 pctime = (10 * pctime) + (c - '0') ; // convert digits to a number 187 188 } 189 } 190 setTime(pctime); // Sync Arduino clock to the time received on the serial port 191 192 RTC.stop(); 193 RTC.set(DS1307_SEC,second()); //set the seconds 194 RTC.set(DS1307_MIN,minute()); //set the minutes 195 RTC.set(DS1307_HR,hour()); //set the hours 196 197 RTC.set(DS1307_DATE,day()); //set the date 198 RTC.set(DS1307_MTH,month()); //set the month 199 RTC.set(DS1307_YR,year()); //set the year 200 201 202 RTC.start(); 203 204 205 } 206 }Ну, может быть, человеку сама задача интересна...
Если нет - то можно взять, например, библиотеку 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