• 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
Arduino Nano + HC05 - problem z funkcją "millis"
#1
Cześć,

Od kilku dni pracuje nad swoim pierwszym projektem.
W projekcie mamy do czynienia z trzema diodami led z funkcją on / off. Dwie z nich działają w trybie ciągłym, trzeci ma działać w trybie przerywanym (migotanie). Sterowanie odbywa się za pośrednictwem modułu BT (HC05).

Problem dotyczy działania funkcji millis (migotanie LED - 0,5s) w przypadku gdy jej wykonanie znajduje się w funkcji sprawdzającej dostępność modułu BT - dioda włącza się i działa w trybie ciągłym lub nie włącza się zupełnie (najprawdopodobniej zależy to od tego czy "wstrzelę się" w ustawione 0,5s).
Gdy wyciągam "migotanie LED" poza "Bluetooth.available" dioda się włącza i migoce zgodnie z założeniem. 
Komunikacja BT i reszta kodu działa poprawnie.
Proszę o pomoc.
Kod poniżej (linijki mające wpływ na działanie migotania LED zakomentowane są "migająca led"):

#include <SoftwareSerial.h>
#define SWGlowne 5
#define SWDodatkowe 6
#define SWAwaryjne 7 // migająca led

int stanLED1 = LOW; // migająca led
unsigned long aktualnyCzas = 0; // migająca led
unsigned long zapamietanyCzasLED1 = 0; // migająca led

SoftwareSerial Bluetooth(0, 1);
char Data;
void sendData(String transmitData){
Bluetooth.println(transmitData);}

void setup(){
    Bluetooth.begin(9600);
    pinMode(SWGlowne,OUTPUT);
    pinMode(SWDodatkowe,OUTPUT);
    pinMode(SWAwaryjne,OUTPUT);
}

void loop(){
    aktualnyCzas = millis(); // migająca led / Pobierz liczbe milisekund od startu
   
    if(Bluetooth.available()){
        Data=Bluetooth.read();
        if(Data==('4')){
            digitalWrite(SWGlowne,1);
            sendData("SwiataGlowne ON");
        }
        if(Data==('1')){
            digitalWrite(SWGlowne,0);
            sendData("SwiataGlowne OFF");
        }
        if(Data==('5')){
            digitalWrite(SWDodatkowe,1);
            sendData("SWDodatkowe ON");
        }
        if(Data==('2')){
            digitalWrite(SWDodatkowe,0);
            sendData("SWDodatkowe OFF");
        }
        if(Data==('6')){
          if (aktualnyCzas - zapamietanyCzasLED1 >= 500UL) {
            zapamietanyCzasLED1 = aktualnyCzas; // migająca led / Zapamietaj aktualny czas
            if (stanLED1 == LOW) { // migająca led / Zmieniamy stan diody na przeciwny
            stanLED1 = HIGH;
            } else {
            stanLED1 = LOW;
            }
            digitalWrite(SWAwaryjne, stanLED1); // migająca led / ustawiamy nowy stan na diodzie
          }
        }
        if(Data==('3')){
            digitalWrite(SWAwaryjne,0);
            sendData("SWAwaryjne OFF");
        }
        if(Data==('9')){
            digitalWrite(SWGlowne,1);
            digitalWrite(SWDodatkowe,1);
            digitalWrite(SWAwaryjne,1);
            sendData("ALL LIGHTS ON");
        }
        if(Data==('0')){
            digitalWrite(SWGlowne,0);
            digitalWrite(SWDodatkowe,0);
            digitalWrite(SWAwaryjne,0);
            sendData("ALL LIGHTS OFF");
        }
    }
}
 
Odpowiedź
#2
Napisz więcej jak chcesz by te ledy świeciły. Ale lepiej to rozdzielić.
loop
{
{ //sprawdzeniepolecenBT
nowedanezBT=1;//jesli sa nowe dane z BT
}
{//ustawienie LED

nowedanezBT=0;
}
}
Teraz w sekcji ustawienie LED możesz dać nowy stan do led, które mają się zmienić gdy przylecą nowe dane z BT łącząc dwa warunki, które muszą być jednocześnie:
if(Data==('3') and nowedanezBT) - czyli jeśli wartość do wykonania jest 3 i jest to nowo otrzymana wartość w tym obiegu loop to się ten if wykona, a jeśli ostatnia wartość była 3, ale polecenie z tym związane zostało już wykonane w poprzednim obiegu loop to w tym już nie.
nowedanezBT z BT to "flaga", zmienna sterująca, możesz dodać inne flagi i łączyć warunki logiczne w if, or II, and &&, not !.
A miganie led nie związane z danymi BT może sobie dalej migać co 500ms niezależnie od danych z BT, albo dodając kolejną flagę do środka if ze sprawdzeniem upływu czasu, gdy led ma być off, to nie zmieniasz jej stanu tylko wyłączasz.
Zmiana stanu led może być też zrobiona takim poleceniem digitalWrite(SWAwaryjne, ! digitalRead(SWAwaryjne)); - ustaw stan odwrotny do aktualnie odczytanego.
Albo zamiast if (stanLED1 == LOW) zrób if(stanLED) tylko potem odwrotnie,albo if(! stanLED) i potem tak samo. Tylko stanLED1 (i inne "flagi") powinny być typu bool, czyli 0 i 1, nie ma potrzeby by był to int przybierający 2^16 różnych wartości, skoro i tak ma to być albo 0 albo 1.
Zmianę wartości można zapisać też tak: stanLED1 = (stanLED1) ? 0 : 1; czyli (sprawdzany warunek) ? jeślitak:jeślinie.
Albo jeśli już jest typu bool stanLED1 ^=1; gdzie z 1 robi 0, a z 0 jedynkę i przypisuje tą wartość do stanLED1.
https://pl.wikibooks.org/wiki/C warto poczytać.
 
Odpowiedź
#3
Wychodzi na to, że program działa tak jak go napisałeś:

Kod:
if(Data==('6')){
          if (aktualnyCzas - zapamietanyCzasLED1 >= 500UL) {
            zapamietanyCzasLED1 = aktualnyCzas; // migająca led / Zapamietaj aktualny czas
            if (stanLED1 == LOW) { // migająca led / Zmieniamy stan diody na przeciwny
            stanLED1 = HIGH;
            } else {
            stanLED1 = LOW;
            }
            digitalWrite(SWAwaryjne, stanLED1); // migająca led / ustawiamy nowy stan na diodzie
          }
        }
Działa to w tym momencie tak, że jak mikrokontroler odbierze z bluetooth '6' to zmieni stan diody na przeciwną. Więc żeby dioda migała co 0,5sek musiałoby na bluetooth pojawiać się cyklicznie '6'.

Rozwiązanie podał Ci kolega kaczakat - tworzysz flagę
Kod:
boolean miganie = false;
po odebraniu '6' z bluetooth zmienia się flaga na true, a po odebraniu '3' na false.

Potem w loop() dajesz:
Kod:
         if (miganie && aktualnyCzas - zapamietanyCzasLED1 >= 500UL) {
            zapamietanyCzasLED1 = aktualnyCzas; // migająca led / Zapamietaj aktualny czas
            if (stanLED1 == LOW) { // migająca led / Zmieniamy stan diody na przeciwny
            stanLED1 = HIGH;
            } else {
            stanLED1 = LOW;
            }
            digitalWrite(SWAwaryjne, stanLED1); // migająca led / ustawiamy nowy stan na diodzie
          }
wg. tego, co już masz albo:
Kod:
          if (miganie && aktualnyCzas - zapamietanyCzasLED1 >= 500UL) {
            zapamietanyCzasLED1 = aktualnyCzas; // migająca led / Zapamietaj aktualny czas
            digitalWrite(SWAwaryjne, !digitalRead(SWAwaryjne)); // migająca led / ustawiamy nowy stan na diodzie
          }
zgodnie z tym, co pisał kolega powyżej.

Brakuje mi ewidentnie 
Kod:
sendData("SWAwaryjne ON");

Na pewno w tym wypadku przerostem formy nad treścią jest zmienna stanLED1 jako int. Zajmuje za dużo miejsca tylko po to, żeby sygnalizować stan włącz - wyłącz. Tu masz rozwiązanie z zastosowaniem boolean, czyli 8 bitów. Możesz również jedną zmienną np. byte(8-bitów) spożytkować na 8 różnych stanów reprezentowanych przez 0 i 1. Czyli stanLED1 = 0/1 to 1 bit "zajętego miejsca" i w takiej zmiennej byte możesz takich ledów "zmieścić" 8.

Warto już na samym początku poczytać i zrozumieć o co chodzi w typach zmiennych i ich doborze.
 
Odpowiedź
#4
Bardzo dziękuję za sugestie.
Zrezygnowałem ze stanu diody (nawyki z frontendu).
Dodałem flagę:
boolean miganie = false;
oraz kod (koniecznie na początku pętli loop i poza if "Bluetooth.available"):
if (miganie && aktualnyCzas - zapamietanyCzasLED1 >= 500UL) {
zapamietanyCzasLED1 = aktualnyCzas; // migająca led / Zapamietaj aktualny czas
digitalWrite(SWAwaryjne, !digitalRead(SWAwaryjne)); // migająca led / ustawiamy nowy stan na diodzie
}
Zmianę migania zgodnie z podpowiedzią umieściłem w:
(...)
if(Data==('6')){
miganie = true;
sendData("SWAwaryjne ON");
}
if(Data==('3')){
miganie = false;
digitalWrite(SWAwaryjne,0);
sendData("SWAwaryjne OFF");
}
(...)
i wszystko pięknie śmiga.
Przy if(Data==('3')) musiałem dodać "digitalWrite(SWAwaryjne,0);" ponieważ samo "miganie = false;" zatrzymywało proces migania i miałem 50/50 że diody pozostaną zapalone).

Jeszcze raz dziękuję obu panom za pomoc.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości