Správanie stopiek

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, ...)
Odpovědět
martinius96
Příspěvky: 579
Registrován: 01 srp 2017, 19:29
Reputation: 0
Bydliště: Poprad
Kontaktovat uživatele:

Správanie stopiek

Příspěvek od martinius96 » 20 srp 2019, 11:55

Ahojte, mám program pre stopky, ktoré používam vo viacerých projektoch. Sú to stopky, ktoré fungujú na báze desatín sekundy s millisom().
Chcel by som ho rozšíriť pre počítanie na stotiny sekundy (2 desatinné miesta).
Program, ktorý používam momentálne je:

Kód: Vybrat vše

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//I2C adresa, stlpce, riadky, pouziva sa i 0x3F pre displej 20x4, 0x27 pre 16x2, skontruj cez I2C scanner https://playground.arduino.cc/Main/I2cScanner/
LiquidCrystal_I2C lcd(0x3F, 20, 4);

//DEKLARACIA DIGITALNYCH PINOV NA KTORE SU NAPOJENE TLACIDLA
const int start_tlacidlo = 12;
const int lavy_terc_kontakt = 11;
const int pravy_terc_kontakt = 10;
const int vynulovat_cas_tlacidlo = 9;

boolean run = false;         //bezi cas pre LAVY UTOK?
boolean run2 = false;         //bezi cas pre PRAVY UTOK?

//STAVY NACITANYCH LOGICKYCH HODNOT TLACIDIEL
int start_tlacidlo_stav = HIGH;
int lavy_terc_kontakt_stav = HIGH;
int pravy_terc_kontakt_stav = HIGH;
int vynulovat_cas_tlacidlo_stav = HIGH;

unsigned long timer = 0; //timer

//PREMENNE PRE PRVY CAS - LAVY UTOK
int second = 0;
int minute = 0;
int tenth = 0;

//PREMENNE PRE DRUHY CAS - PRAVY UTOK
int second2 = 0;
int minute2 = 0;
int tenth2 = 0;

void setup() {
  lcd.begin(); //incializacia displeja na I2C zbernici
  lcd.backlight(); //zapnutie podsvietenia
  pinMode(start_tlacidlo, INPUT_PULLUP); //nastav ako vstup proti internemu 50kohm pullup rezistoru
  pinMode(lavy_terc_kontakt, INPUT_PULLUP);
  pinMode(pravy_terc_kontakt, INPUT_PULLUP);
  pinMode(vynulovat_cas_tlacidlo, INPUT_PULLUP);
  lcd.setCursor(0, 0); //nastav kurzor pre zapis na 1. riadok, 1. stlpec
  lcd.print("00:00:0 L. PRUD");
  lcd.setCursor(0, 1); //nastav kurzor pre zapis na 2. riadok, 1. stlpec
  lcd.print("00:00:0 P. PRUD");
}

void tickClock() {
  Serial.println(millis() / 10);
  if ((timer - millis() / 100) >= 100 || timer == 0) {
    tick();
    timer = millis() / 100;
  }
}

void loop() {
  tickClock();
  start_tlacidlo_stav = digitalRead(start_tlacidlo);
  lavy_terc_kontakt_stav = digitalRead(lavy_terc_kontakt);
  pravy_terc_kontakt_stav = digitalRead(pravy_terc_kontakt);
  vynulovat_cas_tlacidlo_stav = digitalRead(vynulovat_cas_tlacidlo);
  checkStart();
}

void checkStart() {
  if (start_tlacidlo_stav == LOW ) {
    run = true; //aktivuj cas pre lavy prud
    run2 = true; //aktivuj cas pre pravy prud
  }
  if (lavy_terc_kontakt_stav == LOW ) {
    run = false;
  }
  if (pravy_terc_kontakt_stav == LOW ) {
    run2 = false;
  }
  if (vynulovat_cas_tlacidlo_stav == LOW ) {
    run = false;
    run2 = false;
    second = 0;
    minute = 0;
    tenth = 0;
    second2 = 0;
    minute2 = 0;
    tenth2 = 0;
    updateLCD();
    updateLCD2();
  }
}


void tick() { //tick sa vykonava kazdych 100 miliseund, teda kazdu desatinu sekundy
  //LOGIKA BEZIACEHO CASU PRVEHO UTOKU (UTOK LAVY)
  if (run) {
    updateLCD();
    if (tenth == 9) {
      tenth = 0;
      if (second == 59) {
        second = 0;
        minute++;
      } else {
        second++;
      }
    } else {
      tenth++;
    }
  }

  //LOGIKA BEZIACEHO CASU DRUHEHO UTOKU (UTOK PRAVY)
  if (run2) {
    updateLCD2();
    if (tenth2 == 9) {
      tenth2 = 0;
      if (second2 == 59) {
        second2 = 0;
        minute2++;
      } else {
        second2++;
      }
    } else {
      tenth2++;
    }
  }
}

//VYPIS PRVEHO UTOKU NA DISPLEJ (UTOK LAVY)
void updateLCD() {
  lcd.setCursor(0, 0);
  if (minute < 10) {
    lcd.print("0");
  }
  lcd.print(minute, DEC);
  lcd.print(":");
  if (second < 10) {
    lcd.print("0");
  }
  lcd.print(second, DEC);
  lcd.print(":");
  lcd.print(tenth, DEC);
}

//VYPIS DRUHEHO UTOKU NA DISPLEJ (UTOK PRAVY)
void updateLCD2() {
  lcd.setCursor(0, 1);
  if (minute2 < 10) {
    lcd.print("0");
  }
  lcd.print(minute2, DEC);
  lcd.print(":");
  if (second2 < 10) {
    lcd.print("0");
  }
  lcd.print(second2, DEC);
  lcd.print(":");
  lcd.print(tenth2, DEC);
}
Nerozumiem tejto časti programu:

Kód: Vybrat vše

void tickClock() {
  Serial.println(millis() / 10);
  if ((timer - millis() / 100) >= 100 || timer == 0) {
    tick();
    timer = millis() / 100;
  }
}
Ak v tejto časti programu zmažem millis() / 100 pre timer aj v if, tak to začne počítať úplne dementne. Ako je to možné? Veď som vymazal iba to delenie, a odčítanie by malo byť vždy presne to isté.. Alebo sa mýlim? Je jedno, či odčítam 4000 - 3900 alebo 400000 - 390000...
Chcel by som to upraviť tak, aby sa mi vykonávalo každých 10 ms.
Skúšal som to napríklad takto:

Kód: Vybrat vše

void tickClock() {
  Serial.println(millis() / 10);
  if ((timer - millis() / 100) >= 10 || timer == 0) {
    tick();
    timer = millis() / 100;
  }
}
aj takto:

Kód: Vybrat vše

void tickClock() {
  Serial.println(millis() / 10);
  if ((timer - millis()) >= 10 || timer == 0) {
    tick();
    timer = millis();
  }
}
Ale to počítanie je úplne zlé. Proste by som povedal, že každých x ms mi to pripočíta sekundu. Takže to ráta sekundy tak ako desatiny.
Výstup pôvodného programu je:
Obrázek
Ten chcem rozšíriť na stotiny, teda o ďalšie desatinné miesto.

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

Re: Správanie stopiek

Příspěvek od pavel1tu » 20 srp 2019, 12:23

Já to nechápu, milis() přeci neustále přibývá tak to máš nějak obráceně ...
Já bych ...

if( millis() / 10 - timer > 10 ) .....
timer = milis() / 10;

možná mi to nemyslí, nevím ....
UNO, NANO, Mikro, PRO mini, DUE, ESP32S2, RPi PICO
Pavel1TU
"Správně napsaný kod lze číst jako knihu"

martinius96
Příspěvky: 579
Registrován: 01 srp 2017, 19:29
Reputation: 0
Bydliště: Poprad
Kontaktovat uživatele:

Re: Správanie stopiek

Příspěvek od martinius96 » 20 srp 2019, 12:45

O áno, to som si nevšimol, ale fungovalo to.
Prehodil som to, ale nefunguje mi to. Funguje iba na >= 100 na desatiny. Pri >=10 to nefunguje správne. (upravil som aj tenth na podmienku 99 pri >=10, aby tam tá logika fungovala). Počítanie jednej sekundy prebehne za približne cca 4 sekundy.

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

Re: Správanie stopiek

Příspěvek od pavel1tu » 20 srp 2019, 13:22

No já si myslím že je to už moc časté volání podprogramu UpdateLcd() možná i ten tick() - nestíhá to.

Překopej to komplet:
- po START ulož čas startu StartMilis
- každých >= 100 milis nech běžet jak tick() tak UpdateDisplay()
- po STOP - odečti čas StopMilis a odečti od StartMilis - pak musíš přepočítat výsledný čas pro display a zobrazit

- skutečný čas se bude počítat dle milis(), to kolem bude jen omáčka aby "běžel čas" na displeji - klidně jen na desetiny bych to nechal

PS: a máš tam jeden serialprint - ten smaž asi také, nemáš definovanou linku a asi by to zpomalovalo
UNO, NANO, Mikro, PRO mini, DUE, ESP32S2, RPi PICO
Pavel1TU
"Správně napsaný kod lze číst jako knihu"

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

Re: Správanie stopiek

Příspěvek od kiRRow » 20 srp 2019, 16:48

Taky tomu moc nerozumím. Proč je nutno millis dělit ? Pokud chci aby se něco dělo každých 10milisekund

Kód: Vybrat vše

void tickClock() {
  Serial.println(millis() / 10);
  if ((timer - millis() / 100) >= 100 || timer == 0) {
    tick();
    timer = millis() / 100;
  }
}

// takhle bych to napsal já
void tickClock() {
  Serial.println(millis()); // vypíše millis do seriového portu - po vývoji zakomentovat, bude to zbytečně brzdit program
  if (millis()-timer >= 10) { // pokud je millis - timer větší než 10 milivteřin (pokud bude timer 0, tak rozhodně to bude větší než 10)
    tick(); // provedu tick();
    timer = millis(); // zapíšu si poslední čas provedení ticku
  }
}
a čemu se to chová divně ? ... jádro pudla bude tady

Kód: Vybrat vše

void tick() { //tick sa vykonava kazdych 100 miliseund, teda kazdu desatinu sekundy
  //LOGIKA BEZIACEHO CASU PRVEHO UTOKU (UTOK LAVY)
  if (run) {
    updateLCD();
    if (tenth == 9) { // jelikož už počítáš na setiny, musíš tu dát 99 místo 9
      tenth = 0;
      if (second == 59) {
        second = 0;
        minute++;
      } else {
        second++;
      }
    } else {
      tenth++;
    }
  }

  //LOGIKA BEZIACEHO CASU DRUHEHO UTOKU (UTOK PRAVY)
  if (run2) {
    updateLCD2();
    if (tenth2 == 9) { // jelikož už počítáš na setiny, musíš tu dát 99 místo 9
      tenth2 = 0;
      if (second2 == 59) {
        second2 = 0;
        minute2++;
      } else {
        second2++;
      }
    } else {
      tenth2++;
    }
  }
}
Samozřejmě stím souvisí i úprava funkce pro update displeje (jinak ti to tam nebude vkládat tu 0 při méně jak 10 setin). A v setupu si doplň tu nulu pro první výpis na displej.

PS: Je hloupost změnit obsah displeje a potom změnit hodnoty které se na něm vypisují. Nejprve změň hodnoty a pak teprve přepiš displej. A není nutno to dělat ve dvou oddělených funkcích ... stačí jedna která přepíše oba řádky vždy na konci funkce tick().

Odpovědět

Kdo je online

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