• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
jak wykonać kilka razy pętlę IF i zakończyć ją
#1
Na wstępie witam szanownych forumowiczów.

Jestem na etapie budowy zintegrowanego czujnika opadów deszczu, światła i temperatury zewnętrznej pod system alarmowy. Kwestia pomiarów światła i temperatury oraz wysyłka danych do centrali alarmowej w postaci danych dzień/noc oraz temperatura dodatnia/ujemna nie stanowi większego problemu.

Do budowy czujnika opadów deszczu wykorzystałem LC7555, który pod wpływem zmiany rezystancji wejściowej generuje częstotliwość na wyjściu. Temat związany z poprawnym odczytem tej częstotliwości przez Arduino oraz wysyłki danych deszcz/sucho do centrali alarmowej, również nie stanowił większego problemu. Problemem jest jednak kwestia sterowania grzałką w zależności od 3-4 różnych scenariuszy, zależnych od częstotliwości zmierzonej na wejściu Arduino:


Kod:
1. jeśli 200 < frequency < 2000
  - włączyć przekaźnik Out na pierwszy czas (np. 10 sek), po czym go wyłączyć na drugi czas (np. 20 sek)
  - wykonać pętlę 5 razy i wyjść
2. jeśli 2000 < frequency < 4000
 - włączyć przekaźnik Out na pierwszy czas (np. 10 sek), po czym go wyłączyć na drugi czas (np. 20 sek)
 - wykonać pętlę 10 razy i wyjść
3. jeśli frequency > 4000
 - zostaw wyłączony przekaźnik Out


Częściowo udało mnie się zrealizować pierwszy scenariusz, jak w przykładzie poniżej
tzn. jeśli częstotliwość jest większa niż 200 a mniejsza niż 2000 Hz przekaźnik jest włączany na czas1 i wyłączany na czas2 i tak w kółko, do momentu gdy częstotliwość nie spadnie poniżej 200Hz lub przekroczy 2kHz, gdzie:
- frequency - obliczona częstotliwość sygnału wchodzącego na wejście;
- Out - wyjście przekaźnika
Kod:
#define czas1 10000    // Czas włączenia przekaźnika
#define czas2 20000   // Czas wyłączenia przekaźnika
float frequency;          // Przeliczona częstotliwość
unsigned long czas
.
.
.
.
.
void Grzalka()
{
 if ((frequency>200)&&(frequency<2000)
 {
   if (millis()<(czas+czas1))
   {
     digitalWrite(Out, HIGH);
   }
   if (millis()>(czas+czas1)&&(millis()<(czas+czas2)))
   {
     digitalWrite(Out, LOW);
   }
   if (millis()>(czas+czas1+czas2)) czas=millis();
 }
 else
 {
   digitalWrite(Out, LOW);
   czas=millis();
 }
 delay(500);
}
}

... jednak nie potrafię skutecznie dodać warunku, który tylko np. 5 razy by wykonał główną pętlę "if". Dodawałem przed pierwszą "if" pętlę "for (k1=0; k1<6; k1++){pętla if}", jednak cały czas działała funkcja "if", jakby "for" w ogóle nie działało. Cały czas przekaźnik został włączany na okres czas1 i wyłączany na czas2 dopóki
Kod:
if ((frequency>200)&&(frequency<2000)

Nie mam pojęcia gdzie robię błąd lub jak inaczej można poradzić  sobie z tym problemem.

Potrzebuję wykonać przedstawione wyżej scenariusze aby uniknąć zbędnego grzania podczas intensywnych opadów deszczu/śniegu.

Pozdrawiam serdecznie, Rafał
 
Odpowiedź
#2
Twój problem, to nie jest błąd. Błędy zgłaszane są przez kompilator.
Jeżeli w instrukcji if umieścisz pętlę for, to ta pętla na pewno wykona się tyle razy ile określiłeś w argumencie, ani mniej anie więcej.
Podejrzewam, że rzecz polega na tym, że po wyjściu z ifa program wraca do pętli głównej, tam sprawdzane są opady deszczu i znowu wywoływana jest procedura grzalka(). Dzieje się to tak szybko, że myślisz, że "for" nie działa.

Powiedz co się ma dziać, gdy już ta pętla wykona się pięć razy?
Czekasz na następny deszcz? Na zmianę intensywności deszczu? A może jakaś pauza i znowu załączenie grzałki?
Musisz bardziej sprecyzować oczekiwania odnośnie działania programu.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#3
Witam, bardzo dziękuję za odpowiedź.
Faktycznie, tak jak pisałeś, pętla for i zastępczo if, która miała odliczyć ilość uruchomień, za szybko powodowała inkrementację. Problem z 5-krotnym wykonaniem pętli rozwiązałem w poniższy sposób:

 
Kod:
if ((frequency>200)&&(frequency<2000)&&(k1<6))
  {
    if (millis()<(czas+czas1))
    {
      digitalWrite(Out, HIGH);
      k1++;
    }
    if (millis()>(czas+czas1)&&(millis()<(czas+czas2)))
    {
      digitalWrite(Out, LOW);
    }
    if (millis()>(czas+czas1+czas2)) czas=millis();
  }
  else
  {
    digitalWrite(Out, LOW);
    czas=millis();
  }


Jednak zdaję sobie sprawę, że nie jest to do końca dobre rozwiązanie i tylko częściowo spełniające moje założenia.

Najlepszym rozwiązaniem dla mnie byłoby aby program sprawdzał częstotliwość na wejściu i na jej podstawie sterował grzałką, i tak:
 - jeśli częstotliwość jest mniejsza niż 200 Hz, program nie włącza grzałki
 - jeśli częstotliwość jest w granicach 200 -15000 Hz wtedy program włącza grzałkę według scenariuszy 1-3. W każdym ze scenariuszy można przyjąć na stałe, iż grzałka jest 5-krotnie włączana na okres czas1 (docelowo na 5 min) po czym wyłączana na okres czas2 (docelowo 10 min) i jeśli w tym czasie nie zmniejszy się częstotliwość o próg niżej (np. z 3->2) czeka godzinę i ponownie uruchamia 5-krotne powtórzenie włącz/wyłącz. Natomiast jeśli w międzyczasie spadnie do progu niżej, program wchodzi do założeń niższego progu i dalej 5-krotnie wykonuje włączenie i wyłączenie grzałki... itd.

Mam nadzieję, że nie namieszałem za bardzo
 
Odpowiedź
#4
Zasadniczo to co napisałeś jest O.K.
Można to podzielić na dwie funkcje, gdzie włączana lub wyłączana była by grzałka w zależności od jej stanu.

Kod:
jeśli inkrementacja <5 {
czas = millis

jeśli grzałka wyłączona oraz czas - czas1 > 10min {
  czas1=czas;
  włącz grzałkę;
}

jeśli grzałka włączona oraz czas - czas1 > 5min {
  czas1=czas;
  wyłącz grzałkę;
  inkrementacja++;
}
}

//jeśli wykonaliśmy pętle 5 razy, to nie włączamy grzałki przez godzinę.

jeśli inkrementacja = 5 oraz czas - czas 1 > 1godz {
czas1=czas;
inkrementacja=0;
}


To masz w takim pseudokodzie, ale ja tak piszę konspekty, bo są lepiej przyswajalne podczas burzy mózgów.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#5
Bardzo dziękuję za podpowiedź. Spróbuję podziałać według Twoich wskazówek. Odezwę się po wypocinach.
 
Odpowiedź
#6
Na podstawie Twoich wskazówek zrobiłem coś takiego:
Kod:
const int Grzalka = 3;           // Wyjscie przekaznika grzalki
unsigned long time1 = 0;
boolean d1 = 0;
int k1;
void setup(void)
{
  pinMode(Grzalka, OUTPUT);
  digitalWrite(Grzalka, LOW);
  Serial.begin(9600);
  k1=0;
}
void Relay(void)
{
  if (k1<5)
  {
    if ((d1)&&(millis() - time1 > 2000))
    {
      time1 = millis();
      digitalWrite(Grzalka, HIGH);
      d1 = !d1;
    }
 
    if ((!d1)&&(millis() - time1 > 1000))
    {
      time1 = millis();
      digitalWrite(Grzalka, LOW);
      d1 = !d1;
      k1++;
    }
  }
 
  if ((k1==5)&&(millis() - time1 > 10000))
  {
    time1=millis();
    digitalWrite(Grzalka, LOW);
    k1=0;
  }
}
void loop(void)
{
  Relay();
  Serial.println(k1);
}

Wszystko działa jak należy, grzałka jest włączana na okres 1000ms, wyłączana na 2000ms i po wykonaniu 5 razy tej pętli czeka 10000ms ale + 2000ms, czyli wyłącza grzałkę na czas 10000 i odlicza 2000ms z pętli "if ((d1)&&(millis() - time1 > 2000))". Nie mam pomysłu, jak się tego pozbyć. Dodawałem w pętli "if ((k1==5)&&(millis() - time1 > 10000))" d1 = !d1; co pomagało ale wycinało znowu jedno powtórzenie całej głównej pętli. Można by zamiast warunku k1<5 zrobić k1<6 ale będzie się za pierwszym razem uruchamiać znowu 6 razy.

Miałbyś jakąś sugestię?
 
Odpowiedź
#7
Myślałem o tym, gdy pisałem kod i mam na to rozwiązanie, ale pewnie napiszę wieczorem bo jestem na urlopie i nie bardzo mam czas.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#8
aaaa.. to spokojnie, nie śpieszy się. Spokojnego wypoczynku
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości