Skocz do zawartości
pitu2514

Rejestrator czasu pracy - zliczanie czasu przepracowanego przez pracownika

Pomocna odpowiedź

Cześć, mam problem ze swoim małym projektem - Rejestrator Czasu Pracy. Jestem początkującym w programowaniu oraz w zabawach z Arduino. Przechodząc do głównego problemu zaprezentuje wam kawałek kodu w którym utknąłem.

void loop() {
// Sprawdzamy, czy są nowe karty
if ( mfrc522.PICC_IsNewCardPresent())
{
//odczyt karty
if ( mfrc522.PICC_ReadCardSerial()){
   unsigned long czasStart1 = 0;
   unsigned long czasStop1 = 0;
   unsigned long czas1 = 0;
   unsigned long czasStart2 = 0;
   unsigned long czasStop2 = 0;
   unsigned long czas2 = 0;
tone(8, 2000, 100); 


      if (mfrc522.uid.uidByte[0] == 0x09 && 
     mfrc522.uid.uidByte[1] == 0x87 &&
     mfrc522.uid.uidByte[2] == 0xF3 &&
     mfrc522.uid.uidByte[3] == 0x97&&
     odczyt1 == 0){
                                                
     lcd.setCursor(0,2);
      lcd.print("Wejscie ");
      Serial.print("Wejscie ");
      odczyt1++;
      unsigned long czasStart1 = millis();
      Serial.print(dayOfMonth, DEC);
      Serial.print("/");
      Serial.print(month, DEC);
      Serial.print("/");
      Serial.print(year, DEC);
      Serial.print(" ");

 if (hour<10) {
         Serial.print("0");
         Serial.print(hour, DEC);
     } 
        else {
          Serial.print(hour, DEC);
     }
      Serial.print(":");

if (minute<10) {
     Serial.print("0");
         Serial.print(minute, DEC); 
  } 
        else {
    Serial.print(minute, DEC);
    }
      Serial.print(" ");
      lcd.setCursor(0,3);
     Serial.println("Jan Nowak ");
     lcd.print("Jan Nowak ");
     delay(1000);
     lcd.clear();                                   
     }
        
        else if (mfrc522.uid.uidByte[0] == 0x09 && 
     mfrc522.uid.uidByte[1] == 0x87 &&
     mfrc522.uid.uidByte[2] == 0xF3 &&
     mfrc522.uid.uidByte[3] == 0x97&&
     odczyt1 == 1){
          
      lcd.setCursor(0,2); 
      odczyt1=odczyt1-1;
      unsigned long czasStop1 = millis();
      unsigned long Czas1 = czasStop1 - czasStart1;
      unsigned long Czas_w_s1 = Czas1 / 1000;
     unsigned long posrednie = (Czas_w_s1/3600)*60;
      unsigned long Czas_w_h1 = Czas_w_s1/3600;
      unsigned long Czas_w_m1 = (posrednie%60);

      
      lcd.print("Wyjscie");
      Serial.print("Wyjscie ");
      Serial.print(dayOfMonth, DEC);
      Serial.print("/");
      Serial.print(month, DEC);
      Serial.print("/");
      Serial.print(year, DEC);
      Serial.print(" ");
      if (hour<10) {
         Serial.print("0");
         Serial.print(hour, DEC);
     } 
          else {
          Serial.print(hour, DEC);
     }
      Serial.print(":");

if (minute<10) {
     Serial.print("0");
         Serial.print(minute, DEC); 
  } 
          else {
    Serial.print(minute, DEC);
    }
      Serial.print(" ");
      lcd.print(" Time ");
      
     
     Serial.print("Jan Nowak ");
      Serial.print("Czas pracy ");
      if (Czas_w_h1 < 10) {
    lcd.print("0");
    Serial.print("0");
    lcd.print(Czas_w_h1, DEC);
    Serial.print(Czas_w_h1, DEC); 
  } 
          else { 
    lcd.print(Czas_w_h1, DEC);
     Serial.print(Czas_w_h1, DEC); 
    }
  lcd.print(":");
  Serial.print(":"); 
  if (Czas_w_m1<10) {
    lcd.print("0");
    Serial.print("0"); 
    lcd.print(Czas_w_m1, DEC);
    Serial.print(Czas_w_m1, DEC);
    Serial.println(" ");  
  } 
          else {
    lcd.print(Czas_w_m1, DEC);
    Serial.print(Czas_w_m1, DEC);
    Serial.println(" ");   
    }
     lcd.setCursor(0,3);
     lcd.print("Jan Nowak ");
     delay(3000);
     lcd.clear();
}

To jest prosty projekt do szkoły. Mam dwóch pracowników, którzy po przyjściu do pracy "odbijają się" czytnikiem. Na wyświetlaczu jest cały czas wyświetlona data, godzina oraz dzień tygodnia. Jeżeli odbiją się pierwszy raz to wyświetla się "Wejście" do pracy oraz imię i nazwisko pracownika. Jeżeli odbiją się drugi raz to zmienia się "Wejście" na "Wyjście" wyświetla się imię, nazwisko, oraz przepracowany czas!!!! No i tu są schody. Podczas pierwszego odbicia sczytuję unsigned long czasStart1 = millis(); podczas drugiego odbicia sczytuję unsigned long czasStop1 = millis(); oraz chcę od czasStop1-czasStart1 aby wyliczyć czas pracy pracownika. To wszystko jest robione w jednej funkcji void loop() { .... } ale nie przekazuje mi zmiennej czasStart1. Pomocy, jak to mogę rozwiązać inaczej?

Udostępnij ten post


Link to post
Share on other sites

Witam.

Na początek drobne pytania. Dlaczego nie używasz "void setup()" i dlaczego zmienne definiujesz wewnątrz funkcji "loop()"? Nie widzę też uruchomienia komunikacji przez serial i podpięcia bibliotek. Wnioskuję więc, że nie jest to cały kod. Popraw, proszę , formatowanie (wcięcia), żeby poprawić czytelność i wklej całość.

Pozdrawiam.

Udostępnij ten post


Link to post
Share on other sites
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>   // standardowa biblioteka Arduino
#include <LiquidCrystal_I2C.h> // dolaczenie pobranej biblioteki I2C dla LCD


LiquidCrystal_I2C lcd(0x27, 20, 4);
#define RST_PIN 9 // Pin 9 do resetowania RC522
#define SS_PIN 10 // Pin 10 dla SS (SDA) RC522
#define ID
#define DS3231_I2C_ADDRESS 0x68

//#define DS3231time
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
int odczyt1=0;
int odczyt2=0;
 int m;
 int h;
  unsigned long czasStart1 = 0;
   unsigned long czasStop1;
   unsigned long czas1 = 0;
   unsigned long czasStart2;
   unsigned long czasStop2;
   unsigned long czas2 = 0;
MFRC522 mfrc522(SS_PIN, RST_PIN);

// Konwersja liczby dziesiętnej do postaci binarnej
byte decToBcd(byte val){
  return( (val/10*16) + (val%10) );
}

// Konwersja liczby binarnej do postaci dziesiętnej
byte bcdToDec(byte val){
  return( (val/16*10) + (val%16) );
}




void setup() {
Serial.begin(9600); //inicjujemy komunikacjÄ™ szeregowÄ…
SPI.begin(); //inicjacja magistrali SPI
mfrc522.PCD_Init(); // inicjacja RC522
pinMode(8, OUTPUT);
   Wire.begin();
  Serial.begin(9600);
  //setDS3231time(00,45,8,3,03,12,19);
  lcd.begin();   
  lcd.backlight(); // załączenie podświetlenia 
  delay(500);  
}






void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // ustawienie czasu i daty w DS3231
  
  
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);                    // określa, że następna wartość ma trafić do rejestru sekund
  Wire.write(decToBcd(second));     // ustawienie sekund
  Wire.write(decToBcd(minute));     // ustawienie minuty
  Wire.write(decToBcd(hour));       // ustawienie godziny
  Wire.write(decToBcd(dayOfWeek));  // ustawienie dnia tygodnia (1=niedziela, 7=sobota)
  Wire.write(decToBcd(dayOfMonth)); // ustawienie dnia (1-31)
  Wire.write(decToBcd(month));      // ustawienie miesiÄ…ca
  Wire.write(decToBcd(year));       // ustawienie roku (0-99)
  Wire.endTransmission();
}







void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // ustawia rejestr DS3231 na 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // żąda 7 bajtów danych od modułu DS3231 począwszy od rejestru 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}




void displayTime(){
  
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  
// Przekazanie danych do wyświetlenie w serial monitorze i do LCD

  
     if (hour<10) {
        lcd.setCursor(0,0); 
         lcd.print("0");
         lcd.print(hour, DEC); 
     } else {
          lcd.setCursor(0,0); 
          lcd.print(hour, DEC); 
    }

    
  lcd.print(":");
  
  
  if (minute<10) {
   
    lcd.setCursor(3,0); 
    lcd.print("0");
    lcd.print(minute, DEC); 
  } else {
    lcd.setCursor(3,0); 
    lcd.print(minute, DEC); 
    }
  
  // Dzień
  if (dayOfMonth<10){
    lcd.setCursor(6,0); 
    lcd.print("0");
    lcd.print(dayOfMonth, DEC); 
  } else {
    lcd.setCursor(6,0); 
    lcd.print(dayOfMonth, DEC); 
    }
    lcd.print(".");
    
  // MiesiÄ…c
  if (month<10){
    lcd.setCursor(9,0); 
    lcd.print("0");
    lcd.print(month, DEC); 
  } else {
    lcd.setCursor(9,0); 
    lcd.print(month, DEC); 
    }
    lcd.print(".");

   //Rok
    lcd.print("20");
    if (year<10){
    lcd.setCursor(14,0); 
    lcd.print("0");
    lcd.print(year, DEC); 
  } else {
    lcd.setCursor(14,0); 
    lcd.print(year, DEC); 
    }
  
 // Serial.print(" ");
  lcd.setCursor(0,1); 
  switch(dayOfWeek){
  case 1:
    //Serial.println("Niedziela");
    lcd.print("Niedziela");
    break;
  case 2:
   // Serial.println("Poniedzialek");
    lcd.print("Poniedzialek");
    break;
  case 3:
    //Serial.println("Wtorek");
    lcd.print("Wtorek");
    break;
  case 4:
   // Serial.println("Ĺšroda");
    lcd.print("Sroda");
    break;
  case 5:
   // Serial.println("Czwartek");
    lcd.print("Czwartek");
    break;
  case 6:
   // Serial.println("PiÄ…tek");
    lcd.print("Piatek");
    break;
  case 7:
    //Serial.println("Sobota");
    lcd.print("Sobota");
    break;
  }
}




void loop() {
// Sprawdzamy, czy sÄ… nowe karty
if ( mfrc522.PICC_IsNewCardPresent())
{
//odczyt karty
if ( mfrc522.PICC_ReadCardSerial()){
tone(8, 2000, 100); 


      if (mfrc522.uid.uidByte[0] == 0x09 && 
     mfrc522.uid.uidByte[1] == 0x87 &&
     mfrc522.uid.uidByte[2] == 0xF3 &&
     mfrc522.uid.uidByte[3] == 0x97&&
     odczyt1 == 0){
    
                                                        
     lcd.setCursor(0,2);
      lcd.print("Wejscie ");
      Serial.print("Wejscie ");
      odczyt1++;
      unsigned long czasStart1 = millis();
      Serial.print(dayOfMonth, DEC);
      Serial.print("/");
      Serial.print(month, DEC);
      Serial.print("/");
      Serial.print(year, DEC);
      Serial.print(" ");

 if (hour<10) {
         Serial.print("0");
         Serial.print(hour, DEC);
     } else {
          Serial.print(hour, DEC);
     }
      Serial.print(":");

if (minute<10) {
     Serial.print("0");
         Serial.print(minute, DEC); 
  } else {
    Serial.print(minute, DEC);
    }
      Serial.print(" ");
      lcd.setCursor(0,3);
     Serial.println("Jan Nowak ");
     lcd.print("Jan Nowak ");
     delay(1000);
     lcd.clear();                                   
     }
        
        
        else if (mfrc522.uid.uidByte[0] == 0x09 && 
     mfrc522.uid.uidByte[1] == 0x87 &&
     mfrc522.uid.uidByte[2] == 0xF3 &&
     mfrc522.uid.uidByte[3] == 0x97&&
     odczyt1 == 1){
        
      lcd.setCursor(0,2); 
      //liczenie czasu metoda1
      odczyt1=odczyt1-1;
      unsigned long czasStop1 = millis();
      unsigned long Czas1 = czasStop1 - czasStart1;
      unsigned long Czas_w_s1 = Czas1 / 1000;
     unsigned long posrednie = (Czas_w_s1/3600)*60;
      unsigned long Czas_w_h1 = Czas_w_s1/3600;
      unsigned long Czas_w_m1 = (posrednie%60);

      
      lcd.print("Wyjscie");
      Serial.print("Wyjscie ");
      Serial.print(dayOfMonth, DEC);
      Serial.print("/");
      Serial.print(month, DEC);
      Serial.print("/");
      Serial.print(year, DEC);
      Serial.print(" ");
      if (hour<10) {
         Serial.print("0");
         Serial.print(hour, DEC);
     } else {
          Serial.print(hour, DEC);
     }
      Serial.print(":");

if (minute<10) {
     Serial.print("0");
         Serial.print(minute, DEC); 
  } else {
    Serial.print(minute, DEC);
    }
      Serial.print(" ");
      lcd.print(" Time ");
      
     
     Serial.print("Jan Nowak ");
      Serial.print("Czas pracy ");
      if (Czas_w_h1 < 10) {
    lcd.print("0");
    Serial.print("0");
    lcd.print(Czas_w_h1, DEC);
    Serial.print(Czas_w_h1, DEC); 
  } else { 
    lcd.print(Czas_w_h1, DEC);
     Serial.print(Czas_w_h1, DEC); 
    }
  lcd.print(":");
  Serial.print(":"); 
  if (Czas_w_m1<10) {
    lcd.print("0");
    Serial.print("0"); 
    lcd.print(Czas_w_m1, DEC);
    Serial.print(Czas_w_m1, DEC);
    Serial.println(" ");  
  } else {
    lcd.print(Czas_w_m1, DEC);
    Serial.print(Czas_w_m1, DEC);
    Serial.println(" ");   
    }
     lcd.setCursor(0,3);
     
     lcd.print("Jan Nowak ");
     delay(3000);
     lcd.clear();
}


else if (mfrc522.uid.uidByte[0] == 0xA6 && 
     mfrc522.uid.uidByte[1] == 0xDC &&
     mfrc522.uid.uidByte[2] == 0xE8 &&
     mfrc522.uid.uidByte[3] == 0xF8&&
     odczyt2 == 0){
      
      unsigned long czasStart2 = millis();
      int test=9999999999;
      lcd.setCursor(0,2);
      lcd.print("Wejscie ");
      Serial.print("Wejscie ");
      odczyt2++;
      Serial.print(dayOfMonth, DEC);
      Serial.print("/");
      Serial.print(month, DEC);
      Serial.print("/");
      Serial.print(year, DEC);
      Serial.print(" ");
      if (hour<10) {
         Serial.print("0");
         Serial.print(hour, DEC);
     } else {
          Serial.print(hour, DEC);
     }
      Serial.print(":");

if (minute<10) {
     Serial.print("0");
         Serial.print(minute, DEC); 
  } else {
    Serial.print(minute, DEC);
    }
      Serial.print(" ");
      lcd.setCursor(0,3);
     Serial.println("Adam Kowalski ");
     lcd.print("Adam Kowalski ");
     delay(1000);
     lcd.clear();
      } 
       
       
       
       
       
       
       
       else if (mfrc522.uid.uidByte[0] == 0xA6 && 
     mfrc522.uid.uidByte[1] == 0xDC &&
     mfrc522.uid.uidByte[2] == 0xE8 &&
     mfrc522.uid.uidByte[3] == 0xF8&&
     odczyt2 == 1){
      lcd.setCursor(0,2); 
      
      //liczenie czasu metoda 2 -testy, cuda na kiju
      odczyt2=0;
      czasStop2 = millis();
      Serial.println(test);
      Serial.println(czasStart2);
      Serial.println(czasStop2);
      czas2 = czasStop2 - czasStart2;
      Serial.println(czas2);
      unsigned long Czas_w_s2 = czas2 / 1000;
      Serial.println(Czas_w_s2);
     unsigned long posrednie = (Czas_w_s2/3600)*60;
       Serial.println(posrednie);
      unsigned long Czas_w_h2 = Czas_w_s2/3600;
      Serial.println(Czas_w_h2);
      unsigned long Czas_w_m2 = (posrednie%60);
      Serial.println(Czas_w_m2);
      czasStart2=0;
      czasStop2=0;
      
      lcd.print("Wyjscie");
      Serial.print("Wyjscie ");
      Serial.print(dayOfMonth, DEC);
      Serial.print("/");
      Serial.print(month, DEC);
      Serial.print("/");
      Serial.print(year, DEC);
      Serial.print(" ");
      if (hour<10) {
         Serial.print("0");
         Serial.print(hour, DEC);
     } else {
          Serial.print(hour, DEC);
     }
      Serial.print(":");

if (minute<10) {
     Serial.print("0");
         Serial.print(minute, DEC); 
  } else {
    Serial.print(minute, DEC);
    }
      Serial.print(" ");
      lcd.print(" Time ");
      
     
     Serial.print("Adam Kowalski ");
      Serial.print("Czas pracy ");
      if (Czas_w_h2 < 10) {
    lcd.print("0");
    Serial.print("0");
    lcd.print(Czas_w_h2, DEC);
    Serial.print(Czas_w_h2, DEC); 
  } else { 
    lcd.print(Czas_w_h2, DEC);
     Serial.print(Czas_w_h2, DEC); 
    }
  lcd.print(":");
  Serial.print(":"); 
  if (Czas_w_m2<10) {
    lcd.print("0");
    Serial.print("0"); 
    lcd.print(Czas_w_m2, DEC);
    Serial.print(Czas_w_m2, DEC);
    Serial.println(" ");  
  } else {
    lcd.print(Czas_w_m2, DEC);
    Serial.print(Czas_w_m2, DEC);
    Serial.println(" ");   
    }
     lcd.setCursor(0,3);
     
     lcd.print("Adam Kowalski ");
     delay(3000);
     lcd.clear();
      }
}
}

displayTime(); // wyświetlanie czasu rzeczywistego
  delay(1000);   // odśwież co sekundę
  mfrc522.PICC_HaltA();
}

To jest mój cały kod. Zmienne definiowałem już gdzie się da(próby i testy) nawet i wewnątrz funkcji "loop()". Męczyłem się z tym dość sporo czasu więc fajnie by było gdyby cały ten kod nie poszedł do kosza. Chodzi mi o to gdzie popełniłem błąd oraz czy kod zbudowany w ten sposób ma prawo działać i zliczać ten przepracowany czas. Jeżeli tak to co i gdzie należy poprawić/dodać/dopisać. Wszystko inne mi działa tylko zliczanie tego czasu to kicha więc wkleiłem tylko fragment kodu odnośnie zliczania czasu. Z tego co wywnioskowałem to zmienna czasStart1 i zmienna czasStart2 nie jest widoczna w następnym else if... nie wiem jak to ogarnąć żeby była publiczna.

Udostępnij ten post


Link to post
Share on other sites

Myślę, że problem może wynikać z deklaracji zmiennych czasStart1 i czasStart2 zarówno globalnie jak i lokalnie w funkcji loop(). Zostaw definicje globalne i wywal deklaracje lokalne z funkcji loop().

Te zmienne mają przechowywać wartość nie przez jeden cykl pętli głównej programu, ale przez wiele minut/godzin. A deklaracja tych zmiennych wewnątrz funkcji loop() za każdym razem je zeruje. Jeśli się mylę, niech ktoś mnie poprawi?

Udostępnij ten post


Link to post
Share on other sites
Anonim

To się nazywa "przysłonięcie". Poza tym zrobiłeś z tego programu takie spageti, że sam się w nim zgubiłeś, ogarnij tam trochę ;P Tak się zastanawiam, skoro używasz RTC to po co to liczenie milisekund? Rozumiem, że biznes kieruje się własnymi prawami ale chyba nie ma potrzeby być aż tak chytrym pracodawcą żeby liczyć pracowników co do milisekundy haha.

Na Twoim miejscu opierał bym obliczanie czasu pracy na wskazaniach RTC. Apropo, chyba brakuje includa do niego.

Udostępnij ten post


Link to post
Share on other sites
5 godzin temu, Jamik napisał:

A deklaracja tych zmiennych wewnątrz funkcji loop() za każdym razem je zeruje. Jeśli się mylę, niech ktoś mnie poprawi?

Dokładnie. Brakuje atrybutu static.

Udostępnij ten post


Link to post
Share on other sites
11 godzin temu, atMegaTona napisał:

 Tak się zastanawiam, skoro używasz RTC to po co to liczenie milisekund? 

Używam RTC tylko do wyświetlenia bieżącego czasu i niestety tego nie wykorzystam do zliczania czasu pracy pracownika. Co jeżeli pracownik przyjdzie do pracy o 22:00 a wyjdzie o 6:00? No chyba że są na to jakieś sposoby ale ja na nie nie wpadłem. A teraz wszystko działa, sekundy poprawnie są zliczane. Wiem że to jedno wielkie spaghetti, ale no każdy się kiedyś w końcu nauczy, chyba nie ma takiego który od razu pisze wszystko pięknie i przejrzyście 😄 

 

16 godzin temu, Jamik napisał:

Myślę, że problem może wynikać z deklaracji zmiennych czasStart1 i czasStart2 zarówno globalnie jak i lokalnie w funkcji loop(). Zostaw definicje globalne i wywal deklaracje lokalne z funkcji loop().

Te zmienne mają przechowywać wartość nie przez jeden cykl pętli głównej programu, ale przez wiele minut/godzin. A deklaracja tych zmiennych wewnątrz funkcji loop() za każdym razem je zeruje. Jeśli się mylę, niech ktoś mnie poprawi?

Miałeś rację to rozwiązało mój problem, wielkie dzięki.

Udostępnij ten post


Link to post
Share on other sites

RTC nie nadaje się do zliczania czasu pracy z prostej przyczyny, nie jest monotoniczny. Pierwszy i najbardziej drastyczny przypadek to zmiana czasu - z jednej strony nikt nie chciałby za darmo pracować dłużej, z drugiej kierownictwo mogłoby nie być zachwycone płaceniem za dodatkową godzinę, której w rzeczywistości nie było. Ale nawet jeśli pominiemy zmiany czasu, problem wcale nie zniknie.

Na ogół oczekujemy że RTC wskazuje aktualną godzinę. Niestety jeśli uruchomimy dowolny w miarę tani (czyli np. nie-atomowy) zegar i zostawimy na jakiś czas, okaże się że jego wskazania nie są już idealne. I wtedy pojawia się problem - jeśli skorygujemy wskazania zegara, to albo damy komuś w prezencie dodatkowe godziny, albo je zabierzemy. Z drugiej strony jeśli nie będziemy aktualizować wskazań zegara, to R w nazwie RTC niewiele będzie miało wspólnego z "Rzeczywistością".

Dlatego np. w systemie Linux, ale pewnie i innych mamy jednocześnie wiele zegarów. Jeden z nich to tzw. zegar monotoniczny - odpowiada on millis() na arduino i czyli w sposób stały odmierza czas np. od uruchomienia systemu. Taki zegar bardzo dobrze nadaje się do odmierzania przedziałów czasu, bo niezależnie od zmian pór roku, czy korekty wskazań RTC jego odczyty zmieniają się jednostajnie, bez cofnięć, czy przeskoków.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
Anonim

Hmm.. z reguły zegar RTC ma większą precyzję  niż np. kwarce stosowane do taktowania inaczej specjalizowane układy rtc nie miałyby racji bytu. Ponadto producent gwarantuje dokładność z jaką taki układ działa, i zazwyczaj jest ona znacznie większa niż ta możliwa do uzyskania z generatorów służących do taktowania procesorów dlatego nowsze mikrokontrolery zawierają na pokładzie moduł rtc. Dlatego pozwolę sobie nie zgodzić się ze zdaniem:

34 minuty temu, Elvis napisał:

RTC nie nadaje się do zliczania czasu pracy z prostej przyczyny, nie jest monotoniczny

Co mogłoby się lepiej nadawać do zliczania czasu niż precyzyjny zegarek?? Nawet jeśli błąd pomiaru wynosi jakiś ułamek ułamka sekundy na dobę to nie jest to różnica warta rozważania w przypadku rozliczania czasu pracy. Wystarczy raz na miesiąc zsynchronizować czas z zegarem atomowym przez internet.

Udostępnij ten post


Link to post
Share on other sites

A możesz podać skąd pomysł że zegar RTC ma większą precyzję niż np. mikrokontroler? Bo o ile ja wiem jest dokładnie odwrotnie - tanie kwarce "zegarkowe" o częstotliwości 32kHz mają dużo niższą dokładność niż stosowane do taktowania MCU.

No i chyba nie zrozumiałeś co to jest zegar monotoniczny - dokładność to oddzielna sprawa. Ale RTC z założenia można przestawiać, a czasem pojawiają się przeskoki lub cofnięcia czasu. I dlatego do odmierzania przedziałów czasu trzeba stosować coś innego - to coś może być oparte o RTC, ale sam RTC bez odpowiednich zabiegów się nie sprawdzi.

Udostępnij ten post


Link to post
Share on other sites
47 minut temu, Elvis napisał:

RTC nie nadaje się do zliczania czasu pracy z prostej przyczyny, nie jest monotoniczny.

Pozwolę sobie nie zgodzić się z tym stwierdzeniem.

Jedyne co od RTC oczekujemy to podawanie na bieżąco ilości sekund, które upłynęły od chwili ZERO (przy czym owa chwila ZERO może być różna dla różnych zegarów, ale jest stała dla danego egzemplarza czy klasy zegarów). Reszta - podawanie daty, godziny, przeliczanie na czas strefowy, letni i tak dalej to kwestia aplikacji realizującej owe przeliczenia. A owa ilość nigdy nie maleje... a szczególnie nie jest zależna od strefy czasowej.

2 minuty temu, Elvis napisał:

RTC z założenia można przestawiać

To chyba coś innego przez pojęcie RTC rozumiemy. Owszem, przeskoki się pojawiają (sekunda przestępna), ale cofnięcia jeszcze nie było. A nawet gdyby - zakładając pewną dokładność potrzebną do odmierzania czasu pracy owe cofnięcia nie wpływają na pomiar czasu pracy (liczony w najlepszym przypadku w minutach, a nie sekundach).

Owszem, zgodzę się z twierdzeniem że "moduł DS cośtamcośtam się do tego nie nadaje" (chociaż pewnie dałoby się owo "nadawanie się" z niego wycisnąć).

9 minut temu, Elvis napisał:

tanie kwarce "zegarkowe" o częstotliwości 32kHz mają dużo niższą dokładność niż stosowane do taktowania MCU.

Mówimy tu o zabawkach czy profesjonalnych zastosowaniach? Bo pomiar czasu pracy zabawką raczej nie jest - szczególnie jeśli od wyników pomiarów uzależniona jest kasa w kieszeni pracownika.

Tak przy okazji - jaką dokładność mają owe "tanie kwarce" (nie mam zielonego pojęcia, dlatego pytam) i czy na pewno nie mieszczą się w granicach tolerancji dla tego typu pomiarów? Jaka jest ich dokładność w porównaniu do zegarów mechanicznych?

 

 

Udostępnij ten post


Link to post
Share on other sites

Rezonatory kwarcowe na 32kHz znane są ze słabej dokładności - można ją kompensować ustawianiem pojemności itd. Ale nie oszukujmy się, po kilku dniach, czy miesiącach czas wskazywany przez taki RTC będzie odbiegał od wzorca. W zależności czy ta różnica będzie dodatnia, czy ujemna - musimy skorygować wskazania zegara, inaczej to już nie będzie czas rzeczywisty. Dochodzi jeszcze cofanie o godzinę, albo dodawanie godziny co roku ale to inna historia.

Ja rozumiem RTC jako aktualny czas, czyli czas wskazywany przez zegar z kukułką wiszący na ścianie.

Natomiast to liczenie liczby sekund od chwili zero to dokładnie czas monotoniczny. Nie ma sensu żebym tutaj robił własne wykłady, @ethanak lubisz bawić się linuxem, poczytaj ile rodzajów zegarów jest w systemie, rozróżnienie między RTC, a czasem monotonicznym jest chociażby tutaj: https://stackoverflow.com/questions/3523442/difference-between-clock-realtime-and-clock-monotonic

Właśnie dlatego że rozliczanie czasu pracy jest poważną sprawą, nie można użyć do tego zegara który ma przeskoki, albo się cofa bo wymaga korekty. Można użyć modułów RTC do zbudowania zegara monotonicznego - wystarczy taki moduł raz ustawić i już więcej nie przestawiać. Ale to nie będzie już moduł przechowujący czas rzeczywisty, ale jakiś bliżej nieokreślony "czas odniesienia". Natomiast chcąc znać aktualną godzinę będziemy musieli wskazania odpowiednio przeliczyć.
 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
4 minuty temu, Elvis napisał:

to nie będzie już moduł przechowujący czas rzeczywisty, ale jakiś bliżej nieokreślony "czas odniesienia". Natomiast chcąc znać aktualną godzinę będziemy musieli wskazania odpowiednio przeliczyć.

Zaraz moment. Zakładając, że ów moduł jest w miarę dokładny (tzn. dobowe odchylenie nie przekracza np. 5 sekund, a tyle chyba te tanie kwarce potrafią) i istnieje możliwość automatycznej korekty według wzorca - mamy śliczny zegar monotoniczny o dokładności (czy tam rozdzielczości, nie chce mi się myśleć bo mam 39° gorączki i mogę bredzić) rzędu 10 sekund, czyli wystarczającej do rozliczania czasu pracy. Natomiast taki moduł plus jakiś przeliczacz to dopiero coś, co Ty nazwałeś RTC.

14 minut temu, Elvis napisał:

Właśnie dlatego że rozliczanie czasu pracy jest poważną sprawą, nie można użyć do tego zegara który ma przeskoki, albo się cofa bo wymaga korekty.

W takim razie rozliczanie czasu pracy jest w ogóle niemożliwe - nie istnieją zegary które nie wymagają korekty 🙂

 

 

Udostępnij ten post


Link to post
Share on other sites

Zostawmy może teoretyczne gdybania - do obliczania przedziałów czasu potrzebny jest zegar monotoniczny, jak go zbudujemy to oddzielny temat. Faktycznie korekta o kilka sekund dziennie nie będzie przez nikogo zauważona, ale już np. używanie takich zegarów w programach może mieć opłakane rezultaty (a z takim błędem dopiero co walczyłem, może jestem przewrażliwiony 😉 ).

Chodziło mi tylko o to, że z dwojga złego lepszym zegarem do liczenia czasu pracy było użycie millis() niż RTC. Chociaż oczywiście tworząc zestawienia będziemy potrzebowali godzin z zegara czasu rzeczywistego. Ale aby dokładnie ustalić ile czasu coś trwało (np. praca), zegar nie może być przestawiany.

Udostępnij ten post


Link to post
Share on other sites
Anonim
49 minut temu, Elvis napisał:

A możesz podać skąd pomysł że zegar RTC ma większą precyzję niż np. mikrokontroler? Bo o ile ja wiem jest dokładnie odwrotnie - tanie kwarce "zegarkowe" o częstotliwości 32kHz mają dużo niższą dokładność niż stosowane do taktowania MCU.

Sprawdź to eksperymentalnie, zaimplementuj sobie zegrarek na millisie() i na drugim procuku na module RTC który może być taktowany nawet byle jakim kwarcem zegarkowym i za 12 godzin porównaj wyniki a najlepiej zweryfikuj dokładność na podstawie jakiegoś zegarka co do którego jest pewność, że jest dokładny (polecam szwajcarski ;) ) np. RTC z internetu. Udanych eksperymentów i wartościowych wniosków życzę :)

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...