часы и термометр - помогите найти ошибки

mitos
Offline
Зарегистрирован: 11.12.2011

собрал скетч часов и градусника.не написал а собрал из нескольких примеров.

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

вместо воскресенья пишет что сегодня четверг .

Помогите найти ошибку , и если есть желание то укажите как можно улучшить скетч .

Спасибо.


#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
}

 

step962
Offline
Зарегистрирован: 23.05.2011

 Первое: если у вас вопрос по конкретной проблеме, то зачем приводить код всего скетча? (кстати, оформите вычисление номера дня недели в виде отдельной функции - легче будет и вопросы ставить, и алгоритмы вычиления заменять в случае необходимости)

Второе: поищите в Тырнете информацию по теме "формула Зеллера". Например http://en.wikipedia.org/wiki/Zeller's_congruence

mitos
Offline
Зарегистрирован: 11.12.2011

на счет функций конечно интересно , только в програмировании не силен , понять чужое пытаюсь , свое делать сложнее.

а код привел весь именно потому что не понимаю откуда вылезает неправильный день недели . 

step962
Offline
Зарегистрирован: 23.05.2011

 Строки 120-129 вынесите в отдельную функцию, назвав ее, например, calculateDayOfWeek.

Вместо строк 120-129 будет стоять, соответственно вызов этой функции:

calculateDayOfWeek();

Как минимум - будет видно, где же у вас вычисляется этот самый день недели.

Как максимум - если вы все же решитесь написать функцию для определения дня недели по формуле Зеллера, то оформив ее в виде функции, например с именем calculateDayOfWeekZeller, сможете без риска потереть что-нибудь лишнее переключаться между первой и второй функциями (а может быть - и третьей, и четвертой ...), пока не найдете наконец корректно работающий вариант.

mitos
Offline
Зарегистрирован: 11.12.2011

правильно ли я оформил функцию ?
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;
}
и в чем плюсы формулы Зеллера перед той что использую я ?

mitos
Offline
Зарегистрирован: 11.12.2011

что то не хочет функция работать , не отдает переменную " w" . подскажите что я не правильно делаю ? 

step962
Offline
Зарегистрирован: 23.05.2011

mitos пишет:
правильно ли я оформил функцию? 

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. Вам же легче будет ориентироваться в собственном коде. И поскольку вы утверждаете, что копируя куски кодов из разных источников собираетесь разобраться-таки в их сути, то это будет прекрасным поводом для того, чтобы осуществить декларируемое.

 

step962
Offline
Зарегистрирован: 23.05.2011

Процитирую самого себя:

step962 пишет:

mitos пишет:
правильно ли я оформил функцию? 

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 (конечно, это несоответствие, может быть, компенсируется в основной - длинной - формуле. Но ведь вполне возможно, что и не компенсируется! Но как это проверить без объяснения алгоритма?)

mitos
Offline
Зарегистрирован: 11.12.2011

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. В чем разница ? И где надо переменные прописывать которые в такой функции используются , в начале всего скетча или внутри функции ? 

Еще раз спасибо за помощь и терпение .

step962
Offline
Зарегистрирован: 23.05.2011

 Да - это правильный вариант - функция с возвращаемым значением, оперирующая глобальными переменными. В принципе, и значение можно не возвращать, т.е сделать  void weekdaycalc(). Главное, что надо запомнить - параметры функции (т.е. передаваемые в нее как перечень значений в скобках - ваш первый вариант) вне функции остаются неизменными (даже если вы их изменяете внутри функции). Чтобы все-таки изменить параметр и снаружи, необходимо декларировать его не как переменную ("int w"), а как указатель на переменную ("int *w"). И в обращении к функции, соответственно, передавать не переменную ("weekdaycalc(w)"), а ее адрес ("weekdaycalc(&w)"). Сложновато? Поэтому лучше совсем без параметров, либо с единственным возвращаемым (через return).

Думаю вопрос с тем, где прописывать переменные, снят? На всякий случай - если переменные, используемые в функции, используются и вне ее, то их необходимо описывать как глобальные (в самом начале скетча), либо организовывать передачу через параметры функции (если переменная не изменяется - то передаем саму переменную, если необходимо получить назад измененное значение - пеердаем адрес внешней по отношению к функции переменной). Переменные, прописанные внутри функции за ее пределами не видны. Более подробно - читайте "видимость переменных", "области видимости" и пр.

 

zhuki
Offline
Зарегистрирован: 12.10.2011

Вопрос может немного не в тему. Как точно идут подобные часы и что будет при отключении питания?

Вопрос возник по той причине ,а зачем так допотопно . Существует нормальная система с DS1307 ,работает точно,даёт и день недели и т.п. Энергонезависима 10 лет.

 

mitos
Offline
Зарегистрирован: 11.12.2011

часы и сделаны на RTC

а вот с днем недели в нем я не разобрался . 

zhuki
Offline
Зарегистрирован: 12.10.2011

Извините ,не понял сразу.

Если часы на DS1307 ,там же есть и день недели. Зачем его вычислять.

У меня это выглядит так.

   Wire.beginTransmission(0x68);
  Wire.send(0);
  Wire.endTransmission();

  Wire.requestFrom(0x68, 7);
  secs = Wire.receive();
  mins = Wire.receive();
  hrs = Wire.receive();
  day = Wire.receive();
  date = Wire.receive();
  month = Wire.receive();
  year = Wire.receive();
  //Закончили приём данных от DS1307

 И вот уже много месяцев работает исправно. Могу точно утверждать т.к. основа именно на день недели (пятница).

mitos
Offline
Зарегистрирован: 11.12.2011

У меня часы получают время от компьютера , и вот в той части скетча я не смог понять как задать день недели в 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	  }

 

step962
Offline
Зарегистрирован: 23.05.2011

Цитата:
Зачем его вычислять.

Ну, может быть, человеку сама задача интересна...

Если нет - то можно взять, например, библиотеку Time и получить в одном флаконе и поддержку DS1307, и INTP, и GPS-синхронизацию, и автоматическую настройку дня недели. Даже синхронизация с кампутером по USB/COM-линии там уже встроена. Если верить заявлениям на сайте arduino.cc.

ЗЫ: взглянул на скетч топик-мастера еще раз - похоже, эта библиотека в нем уже присутствует (если не одноименная). Ну, тогда остается на примеры по пользованию этой библиотекой взглянуть повнимательнее. В общем, братцы - RTFM.

mitos
Offline
Зарегистрирован: 11.12.2011

Задача мне конечно интересна :) 

Но я сам не смог понять как поправить тот фрагмент скетча что отвечает за получение времени от компа для установки дня недели в rtc .Видимо надо поправить и запрос и то что отсылается из процессинга на ардуину .

Если сможете мне обЪяснить то я конечно уберу лишние расчеты и скетч станет проще и правильнее .

Спасибо. 

p.s. странный глюк , не могу в тексте использовать Ъ в нижнем регистре , вместо него шрифт в болд переключается 

zhuki
Offline
Зарегистрирован: 12.10.2011

Вам видимо надо так:

RTC.set(DS1307_DOW,XXX);

Где ХХХ  десятичное от 1-7

www.arduino.cc/cgi-bin/yabb2/YaBB.pl