Převod výstupu na čas

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
Printy
Příspěvky: 10
Registrován: 07 lis 2021, 15:39
Reputation: 0

Re: Převod výstupu na čas

Příspěvek od Printy » 09 lis 2021, 17:33

Předem všem díky za odpověď.
Abych to upřesnil. Jedná se o displej na kterém se zaznamenávají data o spuštění čerpadla tlakové kanalizace. (je to můj první projekt)
https://drive.google.com/file/d/1Vjdin0 ... sp=sharing
Čerpadlo se spouští cca 4x týdně. Takže bych potřeboval aby se mi při zastavení čerpadla tzn. ukončení času na 1. řádku, zálohovaly data ze řádků 2, 3, 4.
Je to pouze ochrana kdyby vypadlo napájení.

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

Re: Převod výstupu na čas

Příspěvek od peterple » 09 lis 2021, 17:36

kiRRow píše:
09 lis 2021, 14:08
--- takhle pracují i ony EERAM, v podstatě RAMka s ROMkou v jednom pouzdře napájená přes záložní kondenzátor
Nie ROM. ROM je Read Only Memory. Tam sa zapisovať nedá. SPrávne má byť SRAM a EEPROM

Riešení predostreného problému je pomerne veľa. Niekoľko uvediem v poradí o najmenšieho počtu hw vecí
  1. vyšetrím si najldhší interval ktorý môžem použiť na zapisovanie a za akú je to cenu. Zapisovať každú minútu je zrejme extrém. Kludne stačí zapisovať každú hodinu. Ďalej nebudem zapisovať na jedno miesto ale do celej EEPROM. Ukazatel nepotrebujem. Dajme tomu že jedem záznam bude 8 byte do 512 EEPROM sa mi zmesti 512/8 záznamov * 1 hodina * 100000 zápisov to už na chvíľu vydrží
  2. Budem zapisovať iba potom čo sa údaj zmenil, nie periodicky, opäť cez celú EEPROM ak čerpadlo zapnem 100x denne tak mi to tiež vydrží dosť dlho. Finta so ápisom len pri zmene sa dá aplikovať aj na bod 1.
  3. urobím si pomocou komparátora sledovač výpadku napájania a zapisovať budem len pri výpadku. Tu už ani nemusím ísť cez celú EEPROM a je to na veky
  4. Použijem RTC. Nemusím ho ani spúštať ak nepotrebujem reálny čas. RTC má aj malú SRAM ktorá je zálohovaná. Takže tam mi to prežije výpadky aj mesiac
  5. Použijem EE-RAM, alebo F-RAM. Hlavne F-RAM je na veky aj keď budem zapisovať každú milisekundu
Kedže si medzičasom pustil doplňujúci info, tak je jasné že riešenie č.2 je dostatočné.

Uživatelský avatar
pavel1tu
Příspěvky: 2054
Registrován: 26 říj 2017, 08:28
Reputation: 0
Bydliště: Trutnov
Kontaktovat uživatele:

Re: Převod výstupu na čas

Příspěvek od pavel1tu » 09 lis 2021, 20:48

EE-RAM, FRAM (nechci tu slovíčkařit) je drahá, mám ji tu na PCB ale dle mne to pro tebe není.

Kup si externí EEPROM (https://www.laskarduino.cz/eeprom-modul--at24c02--i2c/) testoval jsem přímo zde zakoupený a 10 tisíc přepisů - pořád fungoval, pokud si dáš tu práci a seženeš zaručeně ten od Atmelu - prý má 1 milion přepisů
UNO, NANO, Mikro, PRO mini, DUE, ESP32S2, RPi PICO
Pavel1TU
"Správně napsaný kod lze číst jako knihu"

Printy
Příspěvky: 10
Registrován: 07 lis 2021, 15:39
Reputation: 0

Re: Převod výstupu na čas

Příspěvek od Printy » 10 lis 2021, 09:21

Všem moc díky za odpovědi a rady. Asi zkusím tu externí https://www.laskarduino.cz/eeprom-modul--at24c02--i2c/
Jen Vás asi ještě budu bohužel trochu otravovat s nastavením kódu až mi dorazí, páč s tímto nemám ještě žádnou zkušenost a pořád se trochu v tom psaní trápím :)
Ještě jednou díky

AstroMiK
Příspěvky: 592
Registrován: 08 pro 2017, 19:05
Reputation: 0

Re: Převod výstupu na čas

Příspěvek od AstroMiK » 11 lis 2021, 05:17

Pokud se jedná jen o 4 zápisy týdně, tak bych vůbec neřešil externí EEPROM a s klidem bych zapisoval do té vnitřní.

Problém je v tom, že když dojde k výpadku napájení v době čerpání, tak se zapomene poslední cyklus - od spuštění čerpadla do výpadku napájení.
Jaká je pravděpodobnost, že k tomu dojde a jak moc by to vadilo?

Pokud ale potřebuješ ukládat každou sekundu, kterou čerpadlo běží, tak si tou externí EEPROM pamětí zas tak moc nepomůžeš.
V tom případě bych se přikláněl spíš k té EERAM - neomezený počet zápisů a při výpadku se automaticky zálohuje do EEPROM.
Cena není až tak velká (od 20 do 40 Kč):
https://www.tme.eu/cz/katalog/pameti-in ... 1444022%3B

K tomu jeden nebo dva kondenzátory do 5Kč.


Pro další výpočty a úvahy by bylo dobré vědět, jak dlouho je v průměru to čerpadlo spuštěné (minuty / desítky minut / hodiny).

Printy
Příspěvky: 10
Registrován: 07 lis 2021, 15:39
Reputation: 0

Re: Převod výstupu na čas

Příspěvek od Printy » 11 lis 2021, 09:12

AstroMiK jéé to jsem rád, že mi píšete. Už jste mi jednou moc pomohl. To že vypadne napájení se stane 2x za rok. To že by se zapomněl poslední cyklus vůbec nevadí. Nejde o nějaké přesné měření, spíše jen o přibližnou informaci o provozu tlakové kanalizace. A v mém případě o první začátky s Arduinem, včetně otravování ostatních :), ale jen tak začínám chápat jak to celé funguje a pochopit kód. Jinak čerpadlo nikdy nebude běžet déle jak 10 min. takže zápis do vnitřní by byl asi nejlepší řešení. Mohl bych vás poprosit o zásah do kódu. Já nějak vůbec netuším jak to napsat. A ještě bych měl jednu prosbu, šlo by aby se při zapnutí čerpadla rozsvítilo podsvícení displeje a při vypnutí po cca 10s. zhaslo? To rozsvícení vím jak na to to zhasnutí mně moc nejde :) Ještě jednou moc moc díky...

Kód: Vybrat vše

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

//nastavíme adresu a typ displeje
LiquidCrystal_I2C lcd(0x27,20,4);
int tlacitko_pin = 7; //pin tlačítka
bool stav_tlacitka;
int cas = 0;
int cascelkem = 0;


void setup() {
pinMode(tlacitko_pin, INPUT);
Serial.begin(9600);
lcd.init(); // initializace lcd
lcd.backlight();

}


void loop() {


stav_tlacitka = digitalRead(tlacitko_pin); //čtení stavu tlačítka
cas = -1; //vynulování po vypnutí
while (stav_tlacitka == HIGH) {
stav_tlacitka = digitalRead(tlacitko_pin);
cas++;
cascelkem++;

int sekundy = cas % 60;
int minutyc = cascelkem / 60;
int sekundyc = cascelkem % 60;
int hodinyc = (cascelkem  / 60 / 60) % 24;
int minuty = cas / 60;
int spt = minutyc * 0.0183333333333333;
int litry = minutyc * 0.045;


Serial.print(minuty);
Serial.print(":");
Serial.println(sekundy);
lcd.setCursor ( 0, 0 );
lcd.print("CAS BEHU:");
//lcd.setCursor ( 9, 0 );
lcd.print(" "); //Musíme smazat předchozí hodnotu, páč, když ubylo jedno číslo, tak to poslední zůstalo za aktuálním a nepřepíše se.
lcd.setCursor ( 9, 0 ); //Vrátí kurzor za nápis "cas spusteni".

lcd.print(minuty);
lcd.print(":");
if (sekundy < 10) lcd.print('0');
lcd.print(sekundy);
lcd.setCursor ( 0, 1);
lcd.print("SPOTREBA:");
lcd.print(spt);
lcd.print(" KWh");
lcd.setCursor ( 0, 2);
lcd.print("PRECERPANO:");
lcd.print(litry);
lcd.print(" m3");
lcd.setCursor ( 0, 3);
lcd.print("CELKOVY CAS:");
lcd.print(hodinyc);
lcd.print(":");
if (minutyc < 10) lcd.print('0');
lcd.print(minutyc);
lcd.print(":");
if (sekundyc < 10) lcd.print('0');
lcd.print(sekundyc);


//delay(1000);
}
} 

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

Re: Převod výstupu na čas

Příspěvek od kiRRow » 11 lis 2021, 10:57

Já se obávám, že za chvíli se dostaneš do bodu, kdy zjistíš, že takto psaný kód je pro použití v praxi nevhodný. Ale na ověření teorie, naučit se něco ( hlavně dělat a opravovat chyby ) naprosto dostačující. Budeš čím dál tím více narážet na různá omezení - hlavně když tě napadne ještě něco připrogramovat.

Já bych se teď momentálně vrhnul na zkrocení millis() a ošetření nežádoucích překmitů, pak bych se naučil u tlačítka rozeznávat 4 stavy ... puštěno, právě teď stisknuto, drženo, právě teď uvolněno.
Pak bych si udělal program, který mi po stisku, po celou dobu držení bude vypisovat do sériové linky 1x za vteřinu "tick". To bude vždy čas, kdy je potřeba provést update dat. A po uvolnění tlačítka mi ten program jen jednoukrát vypíše "ukládám do EEPROM".
Tick pak nahradíš updatem času, přepočtem hodnot a výpisem na displej ( to už vlastně umíš ), výpis o EEPROM se nahradí skutečným příkazem a do setupu dáš načtení hodnot z EEPROM. Pak už bude hračka připlácnout k tomu to podsvícení displeje, stačí mít v paměti hodnotu jak dlouho displej má svítit a každým tickem, kdy není drženo tlačítko ji snížit. Pokud drženo je, tak ji neustále resetovat na původní hodnotu.

Nenech se odradit. Každému kdo něco kdy vymýšlel a vytvářel se stane to, že své milované dílo zahodí do koše a začne znovu, lépe a poučen z vlastních omylů. Takový rázovej přeskok na vyšší level.

Printy
Příspěvky: 10
Registrován: 07 lis 2021, 15:39
Reputation: 0

Re: Převod výstupu na čas

Příspěvek od Printy » 11 lis 2021, 13:36

Zdravím, na millis() už koukám a snažím se pochopit. Ohromně mi pomáhá, když mě někdo trochu nakopne, ideálně třeba zásahem do kódu. Kdy pak lépe pochopím proč a jak a příště už si pamatuji. Jinak prostě studuji a jedu pokus omyl. Což je běh na dlouhou trať. Jinak Arduino už bylo v koši dvakrát a i slzičky byly :) Ale nevzdávám se. Díky, že jsem narazil na tak úžasnou a vstřícnou komunitu . Moc díky za každý podnět

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

Re: Převod výstupu na čas

Příspěvek od kiRRow » 11 lis 2021, 14:24

Jednou diodou chci blikat co vteřinu a druhou co pět.
Potřebuji tři proměnné ... počet millis (currentTime), počet millis kdy jsem bliknul jednou (led1Time) a počet millis kdy jsem bliknul druhou (led2Time)

Na začátku celého loopu si uložím do proměnné hodnotu millis().
Odečtu od currentTime hodnotu led1Time a jeli větší než 1000 změním stav led, zapíšu si do led1Time = currentTime
Odečtu od currentTime hodnotu led2Time a jeli větší než 5000 změním stav led, zapíšu si do led2Time = currentTime

AstroMiK
Příspěvky: 592
Registrován: 08 pro 2017, 19:05
Reputation: 0

Re: Převod výstupu na čas

Příspěvek od AstroMiK » 11 lis 2021, 19:46

Pro millis() zkus pochopit následující příklad.


Slouží k pravidelnému spouštění podprogramu každou sekundu - nezávisle na tom, jak dlouho podprogram trvá.
(samozřejmě musí trvat kratší dobu než jednu sekundu)


Kód: Vybrat vše

//==============================================================================
unsigned int interval = 1000;              // interval v milisekundách mezi spouštěním podprogramu
unsigned long posledni_aktivace = 0;


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


//==============================================================================
void loop(void)
  {

    // hlavní smyčka běhá v tomhle případě hrozně rychle, ale jediné co dělá je test času
    
    if (millis() - posledni_aktivace >= interval )
      {
        //---------------------------------------
        // tahle část se spustí jen 1x za sekundu - tahle sekunda je ale přesná (nezávisle na tom, jak dlouho trvá vykonávání poprogramu)

        posledni_aktivace = millis();
        podprogram();
        
        //---------------------------------------
      }   
  }
//==============================================================================


//==============================================================================
void podprogram(void)
  {
    Serial.print("posledni aktivace podprogramu [ms] = ");
    Serial.println(posledni_aktivace); 
    
    delay(random(900));        // Nezáleží na tom, jak dlouho se bude tahle část vykonávat. K dalšímu spuštění dojde přesně za sekundu.
                               //  příkaz delay(random(900));   je náhodně dlouhá pauza mezi 0 a 0,9 sekundy.
                               //   je to tu jenom aby bylo názorně vidět, že spuštění je nezávislé na době vykonávání podprogramu
  }
//==============================================================================



Dál nečti, než tomu prvnímu příkladu neporozumíš.


A pak už stačí "podprogram" nahradit trochu jiným kódem, který bude každou sekundu testovat běh čerpadla (stav tlačítka).

A podle toho jestli běží (je stisknuté), stojí (je uvolněné), právě se rozběhlo (právě bylo stisknuto), nebo se právě zastavilo (právě bylo uvolněno), vykoná nějaké činnosti.

V programu jsou jen naznačeny operace s displejem a EEPROM. Ty se ještě musí dodělat.
Kostra je ale v podstatě hotová.

Kód: Vybrat vše


#define tlacitko_pin  7                    // pin pro připojení tlačítka

unsigned int interval = 1000;              // interval v milisekundách mezi spuštěním podprogramu
unsigned long posledni_aktivace = 0;

unsigned long cas;                         // celkový čas běhu v sekundách

boolean aktualni_stav;                     // proměnné, pomocí kterých se pozná, že došlo právě ke spuštění, nebo k vypnutí
boolean minuly_stav;

unsigned int odpocet_zhasnuti;             // proměnná, která udrží podsvět rozsvícený ještě několik sekund po vypnutí tlačítka

//==============================================================================
void setup(void)
  {
    Serial.begin(9600);    
    pinMode(tlacitko_pin, INPUT);          // tlačítko bude spínat proti plusu. V rozepnutém stavu bude přes odpor proti GND udržováno v LOW

    Serial.println("nacitam predchozi ulozeny stav promennych z EEPROM");
    // tady by byly operace se čtením uložených hodnot z EEPROM
    
  }


//==============================================================================
void loop(void)
  {
    // hlavní smyčka běhá v tomhle případě hrozně rychle, ale jediné co dělá je test času
    
    if (millis() - posledni_aktivace >= interval )
      {
        //---------------------------------------
        // tahle část se spustí jen 1x za sekundu - tahle sekunda je ale přesná (nezávisle na tom, jak dlouho trvají )

        posledni_aktivace = millis();
        podprogram();
        
        //---------------------------------------
      }    
  }

//==============================================================================
void podprogram(void)
  {
    aktualni_stav = digitalRead(tlacitko_pin);           // HIGH = aktuálně je sepnuto, LOW = aktuálně je rozepnuto

    //-----
    if (minuly_stav == LOW and aktualni_stav == HIGH)    // v předchozí sekundě bylo tlačítko rozepnuté, ale teď je sepnuté. To znamená, že se právě sepnulo
      {
        Serial.println("Prave se zapnulo cerpadlo");

        // tady by se rozsvítil podsvět
        Serial.println("rozsvěcuji podsvet");

        odpocet_zhasnuti = 10;                           // při rozsvícení se už rovnou připraví počítadlo zpožděného zhasnutí displeje (číslo udává počet sekund zpoždění zhasnutí) 
      }

    //-----
    if (minuly_stav == HIGH and aktualni_stav == LOW)    // v předchozí sekundě bylo tlačítko sepnuté, ale teď je rozepnuté. To znamená, že se právě rozepnulo
      {
        Serial.println("Prave se vypnulo");

        // a tady by se aktuální proměnné uložily do EEPROM
        Serial.println("Ukladam stav promennych do EEPROM");

      }

    //-----
    if (aktualni_stav == HIGH)                           // je sepnuto ...
      {
        cas ++;                                          // k času se přičte jedna sekunda

        // tady by byl převod na minuty a sekundy
        // tady nějaké zobrazení na displeji
        Serial.print("pocitani casu, zobrazeni na displeji.... aktualni nastradany cas [s] = ");
        Serial.println(cas);        
      }

    //-----
    if (aktualni_stav == LOW)                            // je rozepnuto ...
      {
        Serial.print("cas je zastaveny ...   " );
        if (odpocet_zhasnuti > 0)                        // když ještě nedobehl odpočet zpožděného zhasnutí do 0 ...
          {
            odpocet_zhasnuti --;                         //    ... tak se odečte 1
            Serial.print("do zhasnuti podsvetu zbyva [s] ... ");
            Serial.println(odpocet_zhasnuti);         
          }
        else                                             // odpočet zpožděného zhasnutí už doběhnul do 0
          {
            // tady by se podsvět zhasínal
            Serial.println("podsvet zhasnuty");
          }
      }

    minuly_stav = aktualni_stav;                         // aktuální stav se zapamatuje pro příští (sekundové) spuštění podprogramu
  }


Odpovědět

Kdo je online

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