Arduino Polska Forum

Pełna wersja: Program działa tylko w połowie.
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Witam wszystkich, chciałbym się zapytać czy jest mi ktoś w stanie pomóc z kodem, który według mnie powinien działać, lecz niestety w połowie wykonania case'ów program przestaje działać do momentu funkcji resetującej. Chodzi o to, aby po uruchomieniu programu moduł pomiaru prądu ACS712 30A mierzył dany prąd i wyświetlał wartość na wyświetlaczu LCD 4x20 (ta część kodu działa) oraz przy wykorzystaniu przekaźnika 6 kanałowego po odpowiednim czasie zapalał parami żarówki (przez 10 sekund - zapalona 1 i 2 żarówka, wyłączenie żarówek, na następne 10 sekund zapalać kolejne dwie czyli 3 i 4, wyłączyć je oraz zapalić 5 i 6 i wyłączyć. Ostatnim krokiem programu jest zapalenie wszystkich zarówek i analogicznie zgaszenie ich po 10 sekundach. Program na delay działa, lecz niestety pomiary występują tylko po wykonaniu całej pętli loop. Program napisany na case zmienia to działanie i resetuje program po 51s, lecz niestety w momencie zapalenia 5 i 6 żarówki w serial monitorze występują tylko pomiary prądu i brakuje kroku wyłącz 5 i 6 zarowke oraz calego dotyczącego wszystkich żarówek, po czym resetuje sie zgodnie po 51 sekundach. Czy ktos jest w stanie mi pomoc i podpowiedziec dlaczego program nie działa w 100% dobrze? Kod załączam w załączniku oraz na samym końcu postu.

Działanie wg. serial monitora:

Zarowki wylaczone

Amps = 1.406

Zarowki 1 i 2 zapalone.



Amps = 1.258

Amps = 1.258

Amps = 1.184

Amps = 1.184

Amps = 1.184

Zarowki 1 i 2 zgaszone.

Amps = 1.332

Zarowki 3 i 4 zapalone.

Amps = 1.184

Amps = 1.258

Amps = 1.184

Amps = 1.184

Amps = 1.110

Zarowki 3 i 4 zgaszone.

Amps = 1.258

Zarowki 5 i 6 zapalone.

Amps = 1.184

Amps = 1.258

Amps = 1.258

Amps = 1.184

Amps = 1.110

Amps = 1.258

Amps = 1.258

Amps = 1.332

Amps = 1.258

Amps = 1.184

Amps = 1.258

Amps = 1.258

Czas zresetowany.



KOD:
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);

const int zarowka1 = 7;
const int zarowka2 = 6;
const int zarowka3 = 5;
const int zarowka4 = 4;
const int zarowka5 = 3;
const int zarowka6 = 2;
const int analogIn = A0;
int mVperAmp = 66;
int RawValue = 0;
int ACSoffset = 2500;
double Voltage = 0;
double Amps = 0;
unsigned long ostatniPomiar = 0;
const int czasPomiarowy = 2000;
unsigned long zapamietanyCzas = 0;
unsigned long aktualnyCzas = 0;
const int wylacz = 2000;
const int wlacz12 = 3000;
const int wylacz12 = 13000;
const int wlacz34 = 15000;
const int wylacz34 = 25000;
const int wlacz56 = 27000;
const int wylacz56 = 37000;
const int wlacz123456 = 39000;
const int wylacz123456 = 49000;
unsigned long resetInterval = 51000;
unsigned long startTime = 0;

enum StanZarowek {
  WYLACZONE,
  WLACZ_ZAROWKI_12,
  WYLACZ_ZAROWKI_12,
  WLACZ_ZAROWKI_34,
  WYLACZ_ZAROWKI_34,
  WLACZ_ZAROWKI_56,
  WYLACZ_ZAROWKI_56,
  WLACZ_ZAROWKI_123456,
  WYLACZ_ZAROWKI_123456
};

StanZarowek aktualnyStan = WYLACZONE;

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.begin(20, 4);
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Pomiar prądu i napięcia!");
  startTime = millis();
  pinMode(zarowka1, OUTPUT);
  pinMode(zarowka2, OUTPUT);
  pinMode(zarowka3, OUTPUT);
  pinMode(zarowka4, OUTPUT);
  pinMode(zarowka5, OUTPUT);
  pinMode(zarowka6, OUTPUT);
}

void loop() {
  aktualnyCzas = millis();
  unsigned long elapsedTime = aktualnyCzas - startTime;

  // POMIAR PRĄDU:
  if (aktualnyCzas - ostatniPomiar >= czasPomiarowy) {
    ostatniPomiar = aktualnyCzas;
    RawValue = analogRead(analogIn);
    Voltage = (RawValue / 1024.0) * 5000;
    Amps = ((Voltage - ACSoffset) / mVperAmp);
    Serial.print("\t Amps = ");
    Serial.println(Amps, 3);
    displayCurrent(Amps);
  }

 // ZAPALANIE ŻARÓWEK:
  switch (aktualnyStan) {
    case WYLACZONE:
      if (elapsedTime >= WYLACZONE) {
        digitalWrite(zarowka1, HIGH);
        digitalWrite(zarowka2, HIGH);
        digitalWrite(zarowka3, HIGH);
        digitalWrite(zarowka4, HIGH);
        digitalWrite(zarowka5, HIGH);
        digitalWrite(zarowka6, HIGH);
        Serial.println("Zarowki wylaczone");
        aktualnyStan = WLACZ_ZAROWKI_12;
      }
      break;
    case WLACZ_ZAROWKI_12:
      if (elapsedTime >= wlacz12) {
        digitalWrite(zarowka1, LOW);
        digitalWrite(zarowka2, LOW);
        Serial.println("Zarowki 1 i 2 zapalone.");
        aktualnyStan = WYLACZ_ZAROWKI_12;
      }
      break;

    case WYLACZ_ZAROWKI_12:
      if (elapsedTime >= wylacz12) {
        digitalWrite(zarowka1, HIGH);
        digitalWrite(zarowka2, HIGH);
        Serial.println("Zarowki 1 i 2 zgaszone.");
        aktualnyStan = WLACZ_ZAROWKI_34;
      }
      break;

    case WLACZ_ZAROWKI_34:
      if (elapsedTime >= wlacz34) {
        digitalWrite(zarowka3, LOW);
        digitalWrite(zarowka4, LOW);
        Serial.println("Zarowki 3 i 4 zapalone.");
        aktualnyStan = WYLACZ_ZAROWKI_34;
      }
      break;

    case WYLACZ_ZAROWKI_34:
      if (elapsedTime >= wylacz34) {
        digitalWrite(zarowka3, HIGH);
        digitalWrite(zarowka4, HIGH);
        Serial.println("Zarowki 3 i 4 zgaszone.");
        aktualnyStan = WLACZ_ZAROWKI_56;
      }
      break;

    case WLACZ_ZAROWKI_56:
      if (elapsedTime >= wlacz56) {
        digitalWrite(zarowka5, LOW);
        digitalWrite(zarowka6, LOW);
        Serial.println("Zarowki 5 i 6 zapalone.");
        aktualnyStan = WYLACZ_ZAROWKI_56;
      }
      break;

    case WYLACZ_ZAROWKI_56:
      if (elapsedTime >= wylacz56) {
        digitalWrite(zarowka5, HIGH);
        digitalWrite(zarowka6, HIGH);
        Serial.println("Zarowki 5 i 6 zgaszone.");
        aktualnyStan = WLACZ_ZAROWKI_123456;
      }
      break;

    case WLACZ_ZAROWKI_123456:
      if (elapsedTime >= wlacz123456) {
        digitalWrite(zarowka1, LOW);
        digitalWrite(zarowka2, LOW);
        digitalWrite(zarowka3, LOW);
        digitalWrite(zarowka4, LOW);
        digitalWrite(zarowka5, LOW);
        digitalWrite(zarowka6, LOW);
        Serial.println("Wszystkie zarowki zapalone.");
        aktualnyStan = WYLACZ_ZAROWKI_123456;
      }
      break;

    case WYLACZ_ZAROWKI_123456:
      if (elapsedTime >= wylacz123456) {
        digitalWrite(zarowka1, HIGH);
        digitalWrite(zarowka2, HIGH);
        digitalWrite(zarowka3, HIGH);
        digitalWrite(zarowka4, HIGH);
        digitalWrite(zarowka5, HIGH);
        digitalWrite(zarowka6, HIGH);
        Serial.println("Wszystkie zarowki zgaszone.");
        aktualnyStan = WYLACZONE;
      }
      break;
  }

  // RESET MILLIS CO 51 SEKUND:
  if (elapsedTime >= resetInterval) {
    startTime = aktualnyCzas;
    Serial.println("Czas zresetowany.");
    aktualnyStan = WYLACZONE;
  }

  delay(10); // Dodaj krótką pauzę dla stabilności
}

// WYŚWIETLANIE PRĄDU NA LCD 4x20:
void displayCurrent(float Amps) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Prad: ");
  lcd.print(Amps);
  lcd.print(" A");
}
Nie wiem po co mieszasz switch case i ify, przecież po to jest jedno by nie robić drugiego.
Po prostu w pętli zliczasz sobie do zmiennej sekundy, tak jak masz w przykładzie BlinkWithoutDelay, co 1s zmieniasz stan led, to Ty sobie robisz w to miejsce sekundy++, co 10s przełączasz na kolejny case, czyli zmienną sterującą aktualnyStan++.
Dałbyś radę pomóc mi w napisaniu tego kodu według instrukcji jaką napisałeś?
(06-01-2024, 17:55)Helsinki napisał(a): [ -> ]KOD:
 // ZAPALANIE ŻARÓWEK:
  switch (aktualnyStan) {
    case WYLACZONE:
      if (elapsedTime >= WYLACZONE) {

Przejrzałem kod i niestety nie zauważyłem czegoś, co mogło by spowodować opisane rezultaty. Znalazłem taką jedną niejasność - w przedstawion fragmencie chyba powynno być wylacz (małymi literkami - taki zdefiniowany int) niż WYLACZONE (wielkimi - to wartość enum).
Ale to tylko włacza odpowienią sekcje w innym momencie.
Taka porada - skoro tyle piszesz to wypisuj też w pętli aktualną wartość tej zmiennej stanu aktualnyStan i ten elapsedTime. Masz tam longi więc teoretycznie nic się powinno przepełniać przez 50 dni, ale ja bym sprawdził.

O, chyba znalazłem:
Te stałe (momenty czasu) przekraczające 32768 daj unsigned int (wystarczy do 65536) albo long. Najlepiej zrób wszystkie long - dla jednorodności kodu.


No i jeszcze można by dać wszystko w tabelkach przejść i wyjść zamiast takiego kodu copy-paste.
Jak się ulongi przepełnią po 54 dniach, ale gdy operację są robione na uint32_t to zliczanie i porównanie będzie dalej działać prawidłowo, tylko mają to być ulongi/uint32_t.
Złe działanie programu pewnie wynika z tego resetu, jest niepotrzebny, zmienisz czasy poszczególnych casów to musisz sobie tu wyliczyć ile trwa pełny obieg i zmienić ten czas, nie chce mi się go zliczać, ale mogłeś to zrobić używanymi zmiennymi w casach sumując je, a nie wpisując 51, potem musisz pamiętać, że jak zmienisz jakiś czas to jeszcze tam wrócić i poprawić.
Z opisu wynikało, że chcesz każdy stan zmienić co 10s, wtedy wystarczyłoby wywołać case co 10s i po jednokrotnym ustawieniu stanów led przełączyć na kolejny. Ale chcesz mieć inne czasy, to wybierasz sobie wymaganą rozdzielczość, widzę że masz 1s choć niepotrzebnie zapisywaną w ms, wywołujesz część z case co 1s, zliczasz wywołania w każdym case i po spełnieniu warunku, tu faktycznie ify są potrzebne, przełaczasz na kolejny case.
Jak masz mieć większą rozdzielczość to można tak samo zliczać co 10 czy 100ms, zrobić sobie kolejną flagę/znacznik nowego okresu 10ms czy 100ms.
Możesz sobie zobaczyć jak to działa, podstawić swoje czasy w caseTime, tylko w sekundach.
https://wokwi.com/projects/386245628558953473
Dziękuję bardzo za pomoc Big Grin, w razie co mam dwa kody. Wczoraj jeszcze udało mi się napisać jeden z nich. We wtorek test, bo potrzebuję to do swojej pracy dyplomowej.
Strasznie was męczą w tych szkołach, to jest temat co najmniej na pracę doktorską Big Grin.