Challenge - Výpis času

jankop
Příspěvky: 1029
Registrován: 06 zář 2017, 20:04
Reputation: 0
Bydliště: Brno
Kontaktovat uživatele:

Challenge - Výpis času

Příspěvek od jankop » 24 lis 2021, 19:03

Tak malou úlohu nejspíš jen pro tebe. :D Ve svých aplikacích občas používám zobrazování času od zapnutí - restartu, tedy jakési "motohodiny". Odvozeno je to od millis(), tedy nic přesného a po cca 50 dnech se to vynuluje, ale je to docela užitečné. Člověk získá alespoň představu o výdrži a stabilitě daného systému.
Zadání: pomocí funkce millis() vytvoř funkci, jejíž hodnotou bude String v podobě DD:HH:MM:SS , ukazující dobu od zapnutí systému. Pochopitelně konstantní délky. Vyhni se při tom globálním proměnným
face01.jpg

Uživatelský avatar
kiRRow
Příspěvky: 1152
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Challenge

Příspěvek od kiRRow » 24 lis 2021, 20:18

Očekával bych asi takovou odpoveď :

Kód: Vybrat vše

/*
Program co používá millis() pro počítání běhu svého času ... na cca 170let

Schválně nebudu používat millis() pro výpočet času po který program běží, protože vím, že každých cca 50dní přeteče.
Program napíšu proto tak, aby millis() využíval pouze ke generování cca vteřinových "impulzů" (ve skutečnosti to budou odbočky v programu).
Tím mám možnost si celkovou informaci o času běhu programu rozdělit do kolika řádu budu chtít.

Nemám tušení zda je přestupný rok, nebo ne a kolik má dní měsíc ve kterém to funguje. Budu počítat pouze dny.
*/

byte day,hour,minute,sec; // byte 0 - 255 stačí

unsigned long currentTime; // zde si uchovám aktuální počet millis() - mám ho tam i pro jinačí funkce
unsigned long lastLifeTime; // zde si uchovám akutální čas, kdy jsem kontroloval jestli program žije - více časových funkcí = více těhle proměnných

void setup() {
  Serial.begin(115200);
}

void loop() {
  currentTime = millis(); // zapíšu si aktuální čas -- chceteli si hrát, dejte tu = micros(); a o dva řádky později

  //---- Zde porovnávám aktuální a poslední čas
  if((unsigned long)(currentTime - lastLifeTime) > 1000){ // výsledek je definován jako unsigned long, nikdy tedy nebude záporný, přeteče-li mi milis dostanu nechutně vysoké číslo ... jinak pokud je vždy větší než 1000ms -- chceteli si hrát nahradit > 1
    if(sec < 59){ // vteřin je sice 60, ale kdo kdy viděl 01:60
      sec++; // méně jak 59, počítám vteřiny
    } else { // přetekly vteřiny
      sec = 0; // vynuluji vteřiny
      if(minute < 59){ // kdo kdy viděl 00:60:00
        minute++; // počítám minuty
      } else { // přetekly minuty
        minute = 0; // vynuluji minuty
        hour++; // počítám hodiny
        if(hour < 23){ // všichni známe 00:00:00
          hour++; // počítám hodiny
        } else { // přetekly hodiny
          hour = 0; // vynuluji hodiny
          day++; // počítám dny
        }
      }
    }
/*
Vím že zadání bylo 00:00:00:00 - jen pro ukázku modifikace
Vypisuji na sériovou linku, zde je prostor pro odeslání dat kam potřebuješ
*/
    Serial.print(day); //dny
    Serial.print("d"); //oddělovač dní od hodin ... nahradit : pokud je třeba
    if(hour < 10) Serial.print("0"); // méně než 10 a chci tam úvodní nulu
    Serial.print(hour); // vypiš hodiny
    Serial.print(":"); // oddělovač hodin od minut
    if(minute < 10) Serial.print("0"); // méně než 10 a chci tam úvodní nulu
    Serial.print(minute); // vypiš minuty
    Serial.print(":"); // oddělovač minut od vteřin
    if(sec < 10) Serial.print("0"); // méně než 10 a chci tam úvodní nulu
    Serial.println(sec); // vypiš vteřiny

    lastLifeTime = currentTime; // všechno hotovo, zapiš čas (a uvidíme se příští cca vteřinu)
  }
}
Zatím jsem se nevyhnul globálním proměnným. Kód je odzkoušen a je plně funkční na arduino Mega. Napíše to někdo jako lépe ? Třeba jako vnitřně se řídící třídu, která s každým zavoláním .update() sama sebe testne a vyplivne požadované data či vykoná potřebnou činost ?
edit : A když to čtu znovu, nemám ještě splněno, že to bude string :(

Uživatelský avatar
kiRRow
Příspěvky: 1152
Registrován: 07 kvě 2019, 07:03
Reputation: 0
Bydliště: Opava

Re: Challenge

Příspěvek od kiRRow » 24 lis 2021, 20:27

Ale zase na druhou stranu bych rád viděl tvůj počin, jak to tam drtíš ... už v samotném challengi

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Challenge

Příspěvek od peterple » 24 lis 2021, 20:59

Toto by sa sa vám ako páčilo?

Kód: Vybrat vše

void setup() {
  Serial.begin(9600);
}

#define DAY_SEC  86400L
#define HOUR_SEC 3600L
#define MIN_SEC  60L

void print2digit (String& s, uint8_t val, uint8_t pos){
s.setCharAt(pos++, (val/10)|'0' );
s.setCharAt(pos, (val%10)|'0');
}

void toTime(String& s, uint32_t ms){
  uint8_t val;
  ms /= 1000;
  val = ms / DAY_SEC;
  print2digit(s, val,0);
  ms %= DAY_SEC;
  val = ms / HOUR_SEC;
  print2digit(s, val,3);
  ms %= HOUR_SEC;
  val = ms / MIN_SEC;
  print2digit(s, val,6);
  ms %= MIN_SEC;
  print2digit(s, (uint8_t)ms, 9);
}

void loop() {
  String s= String(F("  :  :  :  "));
  uint32_t ms;
  ms = millis();
  toTime(s, ms);
  Serial.println(s);
}

jankop
Příspěvky: 1029
Registrován: 06 zář 2017, 20:04
Reputation: 0
Bydliště: Brno
Kontaktovat uživatele:

Re: Challenge

Příspěvek od jankop » 24 lis 2021, 21:03

Zajímavá je tvoje idea, brát z millis jen sekundové intervaly a mít tedy čítání delší. To asi zkusím v modifikaci zapracovat do svého programu. Ale přináší to některé problémy. Ten tvůj program funguje, vyzkoušel jsem ho, ale zadání úplně nesplňuje. Když budu mít nějaký displej nebo webovou stránku, pak musím celý výstup pracně přepisovat. Je to takové nekompaktní a vyžaduje to každou sekundu nějakou činnost. Moje řešení prostě při zavolání spočítá dobu běhu a basta.

Kód: Vybrat vše

void setup() {
  Serial.begin(115200);
  Serial.println("");
}

void loop() {
  Serial.println(TimeToString());
  delay(1000);
}
String TimeToString(void) {
  // conversion of millis to time string DD:HH:MM:SS
  uint32_t times = millis() / 1000;
  uint8_t  days = (uint8_t)floor(times / 86400);
  uint8_t  hours = (uint8_t)floor((times % 86400) / 3600);
  uint8_t  mins = (uint8_t)floor((times % 3600) / 60);
  uint8_t  secs = (uint8_t)floor(times % 60);
  String uts = (days < 10 ? "0" + String(days) : String(days))
               + ":" + (hours < 10 ? "0" + String(hours) : String(hours))
               + ":" + (mins < 10 ? "0" + String(mins) : String(mins))
               + ":" + (secs < 10 ? "0" + String(secs) : String(secs));
  return uts;
}
A na tomhle se dobře ladí.
zdroj.png
Naposledy upravil(a) jankop dne 24 lis 2021, 21:16, celkem upraveno 1 x.

jankop
Příspěvky: 1029
Registrován: 06 zář 2017, 20:04
Reputation: 0
Bydliště: Brno
Kontaktovat uživatele:

Re: Challenge

Příspěvek od jankop » 24 lis 2021, 21:15

peterple píše:
24 lis 2021, 20:59
Toto by sa sa vám ako páčilo?
Ten tvůj prográmek zadání nepochybně splňuje, funguje a je v každém případě velmi nekonvenční. :D

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Challenge

Příspěvek od peterple » 24 lis 2021, 21:27

Toto funguje ako?

Kód: Vybrat vše

String TimeToString(void) {
  // conversion of millis to time string DD:HH:MM:SS
  uint32_t times = millis() / 1000;
  uint8_t  days = (uint8_t)floor(times / 86400);
  uint8_t  hours = (uint8_t)floor((times % 86400) / 3600);
  uint8_t  mins = (uint8_t)floor((times % 3600) / 60);
  uint8_t  secs = (uint8_t)floor(times % 60);
  String uts = (days < 10 ? "0" + String(days) : String(days))
               + ":" + (hours < 10 ? "0" + String(hours) : String(hours))
               + ":" + (mins < 10 ? "0" + String(mins) : String(mins))
               + ":" + (secs < 10 ? "0" + String(secs) : String(secs));
  return uts;
}
Keď opustíš funkciu tak sa premenná uts na zásobníku nedealokuje?

jankop
Příspěvky: 1029
Registrován: 06 zář 2017, 20:04
Reputation: 0
Bydliště: Brno
Kontaktovat uživatele:

Re: Challenge

Příspěvek od jankop » 24 lis 2021, 21:40

uts je lokální ve své funkci a její hodnota se vrací prostřednictvím hodnoty funkce. Globálně neexistuje.

peterple
Příspěvky: 156
Registrován: 22 zář 2021, 20:20
Reputation: 0

Re: Challenge

Příspěvek od peterple » 24 lis 2021, 21:55

aha, takže sa to niekam prekopíruje zase do nejakého iného Stringu. Nie je jednoduchšie a rýchlejšie odovzdávať si referenciu, ako kopírovať celý objekt? A ešte k tomu vnútru, to ti nevadí že tam máš v tej funkcii "tisíc" nových alokácií pre fúru String objektov a pri operátore +. A že sa ti pravdepodobne fragmentuje heap? Moje hodnotenie tej funkcie TimeToString je 3-. Takto si môžem dovoliť programovať v JAVe alebo JavaScripte kde to GCC uprace, ale na AVR ťa to rýchlo dostane do pamäťovej núdze. Na tom ESP či čo to je, asi nebude taká akútna.

jankop
Příspěvky: 1029
Registrován: 06 zář 2017, 20:04
Reputation: 0
Bydliště: Brno
Kontaktovat uživatele:

Re: Challenge

Příspěvek od jankop » 24 lis 2021, 22:08

Já jsem netvrdil, že moje řešení je nejlepší. Vracet hodnoty funkcí je ale naprosto přirozené. Předávání referencí je asi lepší metoda. Máš pravdu, že ESP8266 má k dispozici podstatně víc paměti. Na druhé straně jsem spojoval řetězce takhle

Kód: Vybrat vše

void MainPage(void) {
  // Authentication is required ?
  AuthWeb();
  // website layout
  String buff  = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
  buff += "<html><head><meta content=\"text/html; charset=utf-8\"><meta http-equiv=\"refresh\" content=\"" + String(PageRefreshPeriod) + "\">\n";
  buff +="<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n";
  buff += "<title>ESP8266 Humidity</title></head><body style=\"font-family:Arial,sans-serif\">\n";
  buff += "<table frame=\"box\" cellpadding=\"5\" style=\"text-align:left; Font-weight:bold; font-size:large; padding: 0; border-spacing: 0;\">\n";
  buff += "<tr style=\"background-color:#f0f0f0\"><td>NAME</td><td colspan=\"2\">" + String(SensorName) + "</td><td>" + String(Version) + "</td></tr>\n";
  buff += "<tr style=\"background-color:#ffffff\"><td>MAC</td><td colspan=\"2\">" + StrMacAddr + "</td><td></td></tr>\n";
  buff += "<tr style=\"background-color:#f0f0f0\"><td>VALUE</td><td colspan=\"2\">TEMPERATURE</td><td>" + String(temperature, FloatRounding) + " &deg;C</td></tr>\n";
  buff += "<tr style=\"background-color:#ffffff\"><td>VALUE</td><td colspan=\"2\">HUMIDITY</td><td>" + String(humidity, FloatRounding) + " %</td></tr>\n";
  buff += "<tr style=\"background-color:#f0f0f0\"><td>RESET</td><td colspan=\"2\">" + String(ResetReason) + "</td ><td></td></tr>\n";
  buff += "<tr style=\"background-color:#ffffff\"><td>ON</td><td colspan=\"2\">" + TimeString + "</td ><td></td></tr>\n";
  buff += "<tr style=\"background-color:#f0f0f0\"><td>WiFi</td><td colspan=\"2\">" + String(rssi) + " dBm</td><td>" + String(PercentRssi, 0) + " %</td ></tr>\n";
  buff += "<tr style=\"background-color:#ffffff\"><td>RAM</td><td colspan=\"2\">" + String(FreeHeap) + "</td><td>BYTE</td></tr>\n";
  buff += "<tr style=\"background-color:#f0f0f0\"><td>VCC</td><td colspan=\"2\">CHIP VOLTAGE</td><td>" + String(Vcc, 2) + " V</td></tr>\n";
  buff += "<tr style=\"background-color:#ffffff\"><td></td><td colspan=\"2\">" + message + "</td><td>" + SymbolRefresh + "</td></tr>\n";
  buff += "<tr style=\"background-color:#f0f0f0\"><td></td><td colspan=\"2\">" + response + "</td><td></td></tr>\n";
  buff += "</table>\n";
  buff += "</body></html>\n";
  server.send(200, "text/html", buff);
}
i takhle

Kód: Vybrat vše

//http main page
void MainPage(void) {
  // Authentication is required ?
  AuthWeb();
  // website layout
  String buff  = F("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
  buff.concat("<html><head><meta content=\"text/html; charset=utf-8\"><meta http-equiv=\"refresh\" content=\"" + String(PageRefreshPeriod) + "\">\n");
  buff.concat(F("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n"));
  buff.concat(F("<title>ESP8266 Humidity</title></head><body style=\"font-family:Arial,sans-serif\">\n"));
  buff.concat(F("<table frame=\"box\" cellpadding=\"5\" style=\"text-align:left; Font-weight:bold; font-size:large; padding: 0; border-spacing: 0;\">\n"));
  buff.concat("<tr style=\"background-color:#f0f0f0\"><td>NAME</td><td colspan=\"2\">" + String(SensorName) + "</td><td>" + String(Version) + "</td></tr>\n");
  buff.concat("<tr style=\"background-color:#ffffff\"><td>MAC</td><td colspan=\"2\">" + StrMacAddr + "</td><td></td></tr>\n");
  buff.concat("<tr style=\"background-color:#f0f0f0\"><td>VALUE</td><td colspan=\"2\">TEMPERATURE</td><td>" + String(temperature, FloatRounding) + " &deg;C</td></tr>\n");
  buff.concat("<tr style=\"background-color:#ffffff\"><td>VALUE</td><td colspan=\"2\">HUMIDITY</td><td>" + String(humidity, FloatRounding) + " %</td></tr>\n");
  buff.concat("<tr style=\"background-color:#f0f0f0\"><td>RESET</td><td colspan=\"2\">" + String(ResetReason) + "</td ><td></td></tr>\n");
  buff.concat("<tr style=\"background-color:#ffffff\"><td>ON</td><td colspan=\"2\">" + TimeString + "</td ><td></td></tr>\n");
  buff.concat("<tr style=\"background-color:#f0f0f0\"><td>WiFi</td><td colspan=\"2\">" + String(rssi) + " dBm</td><td>" + String(PercentRssi, 0) + " %</td ></tr>\n");
  buff.concat("<tr style=\"background-color:#ffffff\"><td>RAM</td><td colspan=\"2\">" + String(FreeHeap) + "</td><td>BYTE</td></tr>\n");
  buff.concat("<tr style=\"background-color:#f0f0f0\"><td>VCC</td><td colspan=\"2\">CHIP VOLTAGE</td><td>" + String(Vcc, 2) + " V</td></tr>\n");
  buff.concat("<tr style=\"background-color:#ffffff\"><td></td><td colspan=\"2\">" + message + "</td><td>" + SymbolRefresh + "</td></tr>\n");
  buff.concat("<tr style=\"background-color:#f0f0f0\"><td></td><td colspan=\"2\">" + response + "</td><td></td></tr>\n");
  buff.concat (F("</table>\n"));
  buff.concat (F("</body></html>\n"));
  server.send(200, "text/html", buff);
}
ale nebyl ve využití paměti rozdíl.
BTW: Nejsem programátor.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 10 hostů