Relé - časovač (tlačítka, displej)

Nedaří se vám s projektem a nenašli jste vhodné místo, kde se zeptat? Napište sem.
Pravidla fóra
Tohle subfórum je určeno pro konzultaci ucelených nápadů, popřípadě řešení komplexnějších projektů, které opravdu není možné rozdělit na menší části.
Většinu problémů jde rozdělit na menší a ptát se na ně v konkrétních subfórech.
Uživatelský avatar
pavel1tu
Příspěvky: 2054
Registrován: 26 říj 2017, 08:28
Reputation: 0
Bydliště: Trutnov
Kontaktovat uživatele:

Re: Relé - časovač (tlačítka, displej)

Příspěvek od pavel1tu » 09 bře 2020, 06:45

Už z principu s tím budeš mít problémy,
když ve funkci sleduješ stav tlačítek a další - jsi hodně ovlivněn dalšími funkcemi, které zde nevidíme.
Více věcí, které ve funkci děláš bych dělal v hlavním programu LOOP - ale můj názor.

Ale psal jsi že to funguje, jen to přičítání po chvilce ne,
na což jsem ti napsal - čím to je (vynuluješ znovu čítač a časuješ od začátku) - i jak to vyřešit.

Kód: Vybrat vše

  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);

        // zde se pridava cas
        interval += 5000;
        
        
        previousMillis = currentMillis;
        digitalWrite(greenLED, LOW);
        relayOn = true;


        Serial.println(interval);
        Serial.println(currentMillis);
        Serial.println(previousMillis);
Tuto část kódu tam musíš mít 2x, nebo uvnitř udělat další podmínku:
- po prvním stisku tlačítka a přičtení času nahodit proměnnou že časovač běží
- pokud časovač běží, už nedělat to "previousMillis = currentMillis;" ale jen interval += 5000;
- když časovač doběhne, vynulovat tu pomocnou proměnnou že časuješ

Ale já bych to celé psal jinak, což je věc názoru - pokud ti to funguje.


Já bych si to musel sestavit, nechci tu řešit dokola nějaké drobné niance co nejde,
a na to nemám čas, sorry.
UNO, NANO, Mikro, PRO mini, DUE, ESP32S2, RPi PICO
Pavel1TU
"Správně napsaný kod lze číst jako knihu"

ondyy
Příspěvky: 23
Registrován: 29 úno 2020, 23:32
Reputation: 0

Re: Relé - časovač (tlačítka, displej)

Příspěvek od ondyy » 12 bře 2020, 16:56

Zdravím,

pavel1tu - děkuji za poslední příspěvek - upravil jsem podle něj kód, a časovač skutečně funguje tak, jak potřebuji. Přikládám se tedy současný kompletní kód (nově se taky stiskem tlačítka přidávají 3 min - 180000 ms).

Dále bych potřeboval zobrazovat zbýající čas na segmentovém dispeji - jak jsem zmínil, používám hodinový displej s TM1637 (https://www.gme.cz/hodinovy-led-displej). Lze do něj poslat přímo číselnou hodnotu (zatím na něm zobrauji hodnotu proměnné interval v minutách), ale potřeboval bych na něm zobrazovat odpočítávání zbývajícího času nejlépe ve formátu MM:SS.

Takže bych potřeboval nějakou proměnnou zbývající čas (a možná i uběhlý čas). Přidávám sem výpis ze sériového monitoru, kde se vypisuje: počet stisknutí tlačítka, interval, currentMillis a previousMillis.

Konkrétně na tomto příkladu jsem:
- stiskl tlačítko poprvé
- po uplynytí 1 min (60000 ms) stiskl tlačítko podruhé
- po uplynutí další 1 min stiskl tlačítko potřetí

Možná by z těchto vypisovaných hodnot bylo možné sestavit ty proměnné zbývající a uběhlý čas a připravit data do displeje, o což bych Vás chtěl poprosit.


Děkuji



Kód: Vybrat vše

// připojení potřebných knihoven

#include <Arduino.h>
#include <TM1637Display.h>


#define CLK 11
#define DIO 12

// Konstanty
const int BUTTON_PIN = 2; // Tlacitko pro pridani casu
const int RESET_PIN = 3; // Reset tlacitko
const int SWITCH_PIN = 4; // Prepinac modu (casovac/trvale zapnuto)


const int relayPIN = 9; // PIN pro ovladani rele
const int redLED = 13; // LED signalizujici blizke vypnuti rele


// Promenne
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int resetState = 0;         // current state of the button

int switchState = 0;

int lastButtonState = 0;     // previous state of the button

int lastSwicthState = 0;     // previous state of the switch


// promenna pro stav rele
bool relayOn = false;

// promenna pro stav casovace
bool casovacBezi = false;



TM1637Display displej(CLK, DIO);



//MILLIS
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

unsigned long interval = 0;

const unsigned long redLedInterval = 2000;


void setup()
{
  Serial.begin(9600);
  
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH); // pull-up

  pinMode(RESET_PIN, INPUT);
  digitalWrite(RESET_PIN, HIGH); // pull-up

  pinMode(SWITCH_PIN, INPUT);
  digitalWrite(SWITCH_PIN, LOW); // pull-up
  
  

  pinMode(relayPIN, OUTPUT);
  pinMode(redLED, OUTPUT);

  //SWITCH HANDLERS

  digitalWrite(relayPIN, HIGH);

  displej.setBrightness(12);
}


void loop(){

    // Prepinac modu (casovac/trvale zapnuto)
    switchState = digitalRead(SWITCH_PIN);

    // if button is pressed, turn relay on (if it wasn't already on), and reset the timer
    if( switchState==HIGH ) // no need to check for previous state, in this specific case
    {
        {
          digitalWrite(relayPIN, LOW);
          digitalWrite(redLED, LOW);
        }
        
         lastSwicthState = 1;
           
    }
    else if( switchState==LOW )
    {
        
        if(lastSwicthState == 1)
        {
          casovac();
        }
          
        casovac();
    }
}


void casovac()
{
    if( relayOn == false )
    {
        digitalWrite(relayPIN, HIGH);

        displej.showNumberDec(0, true);
    }


     // read the pushbutton input pin:
    buttonState = digitalRead(BUTTON_PIN);

    resetState = digitalRead(RESET_PIN);    
    currentMillis = millis();



  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {

      if(casovacBezi == false)
      {
        
        // if the current state is HIGH then the button went from off to on:
        buttonPushCounter++;
        Serial.print("Pocet stisknuti: "); 
          Serial.println(buttonPushCounter);
          


        interval += 180000;


        Serial.print("interval: "); 
          Serial.println(interval);
          
        Serial.print("currentMillis: "); 
          Serial.println(currentMillis);
          
        Serial.print("previousMillis: "); 
          Serial.println(previousMillis);
          Serial.println("");

        
        previousMillis = currentMillis;
        

        digitalWrite(relayPIN, LOW);
        digitalWrite(redLED, LOW);

        casovacBezi = true;
        relayOn = true;


        displej.showNumberDec(((interval/1000)/60), true);
      }
      
      else if (casovacBezi == true)
      {
          // if the current state is HIGH then the button went from off to on:
        buttonPushCounter++;
        Serial.print("Pocet stisknuti: "); 
          Serial.println(buttonPushCounter);
          
          
        
        interval += 180000;


        Serial.print("interval: "); 
          Serial.println(interval);
          
        Serial.print("currentMillis: "); 
          Serial.println(currentMillis);
          
        Serial.print("previousMillis: "); 
          Serial.println(previousMillis);
          Serial.println("");

        

        digitalWrite(relayPIN, LOW);
        digitalWrite(redLED, LOW);
        relayOn = true;


        displej.showNumberDec(((interval/1000)/60), true);
      }    
        
    }

    
    // Delay a little bit to avoid bouncing
    delay(20);
  }

  
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;



    // if relay is currently on...
    if( relayOn == true )
    {
        
        // BLIKANI LED 13 PRED KONCEM
        // turn red led on, if close to turning off the relay
        
        if (currentMillis - previousMillis >= interval-redLedInterval )
        {
            digitalWrite(redLED, (millis()/300)%2);//blink red led; 300ms on; 300ms off
        }
            

            

        // if enough time has elapsed, turn of the relay
        if (currentMillis - previousMillis >= interval) 
        {

            // .. turn of relay

            digitalWrite(relayPIN, HIGH);
            digitalWrite(redLED, LOW);

            casovacBezi = false;
            relayOn = false;
            interval = 0;
        }
    }


    // RESET - vypnuti rele
    if( resetState==HIGH ) // no need to check for previous state, in this specific case
    {
        
        // .. turn of relay

        digitalWrite(relayPIN, HIGH);
        digitalWrite(redLED, LOW);

        casovacBezi = false;
        relayOn = false;
        interval = 0;
    }

}

Výpis ze sériového monitoru:
serial_cas.PNG
serial_cas.PNG (6.1 KiB) Zobrazeno 1995 x

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

Re: Relé - časovač (tlačítka, displej)

Příspěvek od pavel1tu » 12 bře 2020, 22:36

No a to je o tom, že jsi docela naprd sem dával jen tu funkci "časovač"
Dle mne to bude s delším kodem nespolehlivé,
ty tlačítka "RESET" a "přičítání času" se měly dát na přerušení.

Display zatím ponechám, tohle ti nemůže měřit dobře dle mne,
ve funkci casovac ...
až po prvním stisku tlačítka musíš (a já to tam nevidím na těch správných místech):
- previousMillis = milis(); // uložíš čas od kdy časuješ
- uložit že se časuje casovacbezi, rele ON
- interval + daný čas
po stisku tlačítka kdy už "casovacbezi":
- interval + dany cas
konec casovani ja když:
- casovac bezi
- currentMillis - previousMillis >= ulozeny interval, pak konec casovabezi, konec rele ON
kazdy cyklus mimo stisk tlacitka:
- currentMillis = millis();

většinu máš dobře, ale já se v tom nevyznám,
dle mne na blbým místě ukládáš kdy se startuje měření - previousMillis
a s tím currentMillis = millis(); to jsem nenašel ?

výpis času je v českým návodu - první řádek u google při hledání názvu displeje + návod

Kód: Vybrat vše

// vytvoření proměnné vypis pro uložení
  // informací o jednotlivých znacích
  uint8_t vypis[] = { 0, 0, 0, 0 };
  // vytvoření proměnné cas a uložení
  // čas co zbývá do dočasování currentMillis-previousMillis-ulozeny interval
  // v sekundách
  long cas = ((previousMillis + interval) - currentMillis) /1000;  //zavorky abys pochopil co se jak scita a odcita
  // výpočet číslic pro jednotlivé pozice
  // na displeji pro zobrazení času
  // např. první pozice udává desítky minut
  // pro 1000 vteřin: 1000s/60=16min/10=1
  // druhá pozice udává jednotky minut
  // pro 1000 vteřin: 1000s/60=16min%10=6
  // znaménko / je dělení, které vrací celou číslici
  // znaménko % je zbytek po dělení
  vypis[0] = displej.encodeDigit((cas/60)/10);
  vypis[1] = displej.encodeDigit((cas/60)%10);
  vypis[2] = displej.encodeDigit((cas%60)/10);
  vypis[3] = displej.encodeDigit((cas%60)%10);
  // pro zobrazení dvojtečky mezi číslicemi
  // je nutné k pozici 1 přičíst hodnotu 128
  vypis[1] = vypis[1]+128;  
  // výpis informací na displej
  displej.setSegments(vypis);
  
a moc mě to nebaví, nevidím minimální snahu cokoliv si dohledat ... takže končím

PS: za mne, program je špatně strukturovaný, chybí využití přerušení
UNO, NANO, Mikro, PRO mini, DUE, ESP32S2, RPi PICO
Pavel1TU
"Správně napsaný kod lze číst jako knihu"

ondyy
Příspěvky: 23
Registrován: 29 úno 2020, 23:32
Reputation: 0

Re: Relé - časovač (tlačítka, displej)

Příspěvek od ondyy » 12 bře 2020, 23:27

Ano, určitě by bylo možné napsat kód přehledněji a lépe struktorovaně, ale bohužel např. s tím přerušením nemám zkušenosti, proto jsem rád, že i takto program funguje tak, jak potřebuji, což je důležité.

Návod k displeji jsem si už dříve našel, ale šlo mi hlavně o to, jak složit ten vzorec pro proměnnou 'cas', to mi pomohlo.

Díky

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Google [Bot] a 3 hosti