• 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ć.
Miło być decenianym https://buycoffee.to/kaczakat
 
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ź
#5
Hej, postanowiłem odkopać temat, tym razem nie chodzi o blink a o fade.
Miganie (blink) działa bez problemu, jednak schody zaczynają się gdy chcę "migać" z poziomu 50 mocy diody na 255 (pin PWM).
Kod wygląda w skrócie następująco:

int SWKierunkiLeweT = 5;
unsigned long aktualnyCzas = 0;
unsigned long aktualnyCzas2 = 0;
unsigned long zapamietanyCzasLED1 = 0;
unsigned long zapamietanyCzasLED2 = 0;

boolean miganieLeweT = false;

void setup(){
pinMode(SWKierunkiLeweT,OUTPUT);
}

void loop(){

//KOD MIGANIA
aktualnyCzas = millis(); // Pobierz liczbe milisekund od startu
aktualnyCzas2 = millis();
//Migacze TYLNE
if (miganieLeweT && aktualnyCzas - zapamietanyCzasLED1 >= 300UL) {
zapamietanyCzasLED1 = aktualnyCzas; // migająca led / Zapamietaj aktualny czas
digitalWrite(SWKierunkiLeweT, !digitalRead(SWKierunkiLeweT)); // migająca led / ustawiamy nowy stan na diodzie
}

if(Data==('g')){ // Lewy ON
miganieLeweT = true;
sendData("Kierunkowskaz Lewy: ON");
}
if(Data==('h')){ // Lewy OFF
miganieLeweT = false;
analogWrite(SWKierunkiLeweT,50);
sendData("Kierunkowskaz Lewy: OFF");
}
}

Jak wcześniej napisałem, kod jest bardzo okrojony ale sam sens zawarty jest w ww. skrócie.
Po wciśnięciu "g" włącza się miganie diody (działa w zakresie 0-255), po wyłączeniu (przycisk "h") dioda przyjmuje wartość 50 (bardzo istotne).
Problem polega na tym, że chcę uzyskać efekt migania, który zaczyna się przy stanie diody 50 i leci do 255 (max), Działanie nie musi być płynne, chodzi o kierunkowskaz, który używa część diod z tylnego reflektora który z kolei gdy jest włączony ma wartość 50.
Z racji tego, że przednie kierunkowskazy są podpięte pod piny nie PWM oraz że w ich przypadku powinny działać na zasadzie 0% - 100% chciałbym zachować te same odstępy migania (synchronizację).
Proszę o pomoc.
 
Odpowiedź
#6
Użyj switch case 0 swiecenie, 1 miganie, w każdym case opisz co chcesz robić, wywołuj tą funkcję tak często jak chcesz zmieniać jasność, ledy świecą w logarytmach, możesz wybrać np. 20 wartości zapisanych w tablice by rozjaśnianie było proporcjonalne do kroku w odczuciu ludzkiego oka..
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#7
Hej, dziękuje za odpowiedź.
Kod zmiany stanu migania na stan świecenia (50) działa bez zarzutu.
Problemem jest jedynie miganie, które rozpoczyna się od 0 i leci do 255 a powinno zaczynać się od 50.
 
Odpowiedź
#8
Niezbyt jestem w temacie, kojarzę, że jak lampa jest wykorzystana do migania wskazując kierunek skrętu to jednak się wyłącza, a nie pulsuje od średniej do max.
W Twoim kodzie tutaj nie widzę w ogóle tego fragmentu gdzie PWM włączasz coś od 0-255, masz tu tylko digitalWrite.
Pokaż kod z problemem.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#9
Na oficjalnym forum arduino dostałem rozwiązanie odnośnie migania z 50 na 100%
Jednak pojawił się kolejny problem, a w zasadzie dwa:
1) Podczas "migania" prawymi lub lewymi kierunkowskazami przednie migają od 0 do 100% natomiast tylne od 50 do 100%, przy wyłączeniu migacza często ten przedni pozostaje włączony (50/50)
Kod odpowiedzialny za miganie:
Kod:
    //Left ON
    if(Data==('g')){
      turnSignalStateRearR = false;
      turnSignalStateFrontR = false;
      analogWrite(turnSignalRearR,constStateLed);
      turnSignalStateRearL = true;
      turnSignalStateFrontL = true;
      sendData("turn signal left ON");
    }
    //Left OFF
    if(Data==('h')){
      turnSignalStateRearL = false;
      turnSignalStateFrontL = false;
      analogWrite(turnSignalRearL,constStateLed);
      digitalWrite(turnSignalStateFrontL,0);
      sendData("turn signal left ON");
    }

    //Right ON
    if(Data==('i')){
      turnSignalStateRearL = false;
      turnSignalStateFrontL = false;
      analogWrite(turnSignalRearL,constStateLed);
      turnSignalStateRearR = true;
      turnSignalStateFrontR = true;
      sendData("turn signal right ON");
    }
    //Right OFF
    if(Data==('j')){
      turnSignalStateRearR = false;
      turnSignalStateFrontR = false;
      analogWrite(turnSignalRearR,constStateLed);
      digitalWrite(turnSignalStateFrontR,0);
      sendData("turn signal right OFF");
    }


2) podczas używania świateł awaryjnych występuje podobna sytuacja + jeżeli przejdę bezpośrednio z migacza na awaryjne te drugie nie są zsynchronizowane.

Kod na światła awaryjne:
Kod:
if(Data==('9')){
      turnSignalStateRearL = true;
      turnSignalStateRearR = true;
      turnSignalStateFrontL = true;
      turnSignalStateFrontR = true;
     
      sendData("HAZARD lights ON");
    }
    //Hazzard lights OFF
    if(Data==('0')){
      turnSignalStateRearL = false;
      turnSignalStateRearR = false;
      turnSignalStateFrontL = false;
      turnSignalStateFrontR = false;
      analogWrite(turnSignalRearL,constStateLed);
      analogWrite(turnSignalRearR,constStateLed);
      sendData("HAZARD lights OFF");
    }

Poniżej zamieszczam pełny kod odpowiedzialny za obsługę świateł w samochodzie:
Kod:
#include <SoftwareSerial.h>
int mainLights = 2; // 2x diode front + 6x diode rear + 3x diode inside
int rearLights = 3; //PWM 2x diode rear 
int reversingLight = 4; //2x diode reversing light
int turnSignalRearL = 5; //PWM 2x diode turn signal rear-left
int turnSignalRearR = 6; //PWM 2x diode turn signal rear-right
int turnSignalFrontL = 7; //2x diode turn signal front-left
int turnSignalFrontR = 8; //2x diode turn signal front-right
int frontLights = 9; //2x diode front lights


const int constStateLed = 50;
int stateLed = 50;
int stateLed2 = 50;


//BLINK / FADE
unsigned long currentTime1 = 0;
unsigned long currentTime2 = 0;
unsigned long currentTime3 = 0;
unsigned long currentTime4 = 0;
unsigned long savedTime1 = 0;
unsigned long savedTime2 = 0;
unsigned long savedTime3 = 0;
unsigned long savedTime4 = 0;
boolean turnSignalStateRearL = false; //turn signal rear left state
boolean turnSignalStateRearR = false; //turn signal rear right state
boolean turnSignalStateFrontL = false;//turn signal front left state
boolean turnSignalStateFrontR = false;//turn signal front right state
boolean hazardLights = false;         //hazard lights

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

void setup(){
  Bluetooth.begin(9600);
  pinMode(mainLights,OUTPUT);
  pinMode(rearLights,OUTPUT);   
  pinMode(reversingLight,OUTPUT);
  pinMode(turnSignalRearL,OUTPUT);
  pinMode(turnSignalRearR,OUTPUT);   
  pinMode(turnSignalFrontL,OUTPUT);
  pinMode(turnSignalFrontR,OUTPUT);
  pinMode(frontLights,OUTPUT);
}

void loop(){
  currentTime1 = millis();
  currentTime2 = millis();
  currentTime3 = millis();
  currentTime4 = millis();
  //=== REAR turn signal ===

  //REAR Left
  if (turnSignalStateRearL && currentTime1 - savedTime1 >= 300UL) {
    savedTime1 = currentTime1;
    if (stateLed == 50)
      stateLed = 255;
    else
      stateLed = 50;
    analogWrite(turnSignalRearL, stateLed);
  }
  //REAR Right
  if (turnSignalStateRearR && currentTime2 - savedTime2 >= 300UL) {
    savedTime2 = currentTime2;
    if (stateLed2 == 50)
      stateLed2 = 255;
    else
      stateLed2 = 50;
    analogWrite(turnSignalRearR, stateLed2);
  }
 
  //=== FRONT turn signal ===
 
  //FRONT Left
  if (turnSignalStateFrontL && currentTime3 - savedTime3 >= 300UL) {
    savedTime3 = currentTime3;
    digitalWrite(turnSignalFrontL, !digitalRead(turnSignalFrontL));
  }
  //FRONT Right
  if (turnSignalStateFrontR && currentTime4 - savedTime4 >= 300UL) {
    savedTime4 = currentTime4;
    digitalWrite(turnSignalFrontR, !digitalRead(turnSignalFrontR));  
  } 
  //=== HAZARD lights ===
 
  /*I tryed this:
  if (hazardLights && currentTime - savedTime1 >= 300UL) {
    savedTime1 = currentTime;
    if (stateLed == 50)
      stateLed = 255;
    else
      stateLed = 50;
    analogWrite((turnSignalFrontL && turnSignalRearR), stateLed);
  }
  */
 
  //=== BLUETOOTH commands ===
  if(Bluetooth.available()){
    Data=Bluetooth.read();
    if(Data==('a')){
      digitalWrite(mainLights,1);
      analogWrite(rearLights,constStateLed);
      analogWrite(turnSignalRearL,constStateLed);
      analogWrite(turnSignalRearR,constStateLed);
      sendData("main lights ON");
    }
    if(Data==('b')){
      digitalWrite(mainLights,0);
      digitalWrite(rearLights,0);
      digitalWrite(turnSignalRearL,0);
      digitalWrite(turnSignalRearR,0);
      sendData("main lights OFF");
    }
    if(Data==('c')){
      digitalWrite(rearLights,1);
      sendData("frontLights ON");
    }
    if(Data==('d')){
      digitalWrite(rearLights,0);
      sendData("frontLights OFF");
    }
    if(Data==('e')){
      digitalWrite(reversingLight,1);
      sendData("reversingLight ON");
    }
    if(Data==('f')){
      digitalWrite(reversingLight,0);
      sendData("reversingLight OFF");
    }


  //=== BLINKING / FADING ===
    //Left ON
    if(Data==('g')){
      turnSignalStateRearR = false;
      turnSignalStateFrontR = false;
      analogWrite(turnSignalRearR,constStateLed);
      turnSignalStateRearL = true;
      turnSignalStateFrontL = true;
      sendData("turn signal left ON");
    }
    //Left OFF
    if(Data==('h')){
      turnSignalStateRearL = false;
      turnSignalStateFrontL = false;
      analogWrite(turnSignalRearL,constStateLed);
      digitalWrite(turnSignalStateFrontL,0);
      sendData("turn signal left ON");
    }

    //Right ON
    if(Data==('i')){
      turnSignalStateRearL = false;
      turnSignalStateFrontL = false;
      analogWrite(turnSignalRearL,constStateLed);
      turnSignalStateRearR = true;
      turnSignalStateFrontR = true;
      sendData("turn signal right ON");
    }
    //Right OFF
    if(Data==('j')){
      turnSignalStateRearR = false;
      turnSignalStateFrontR = false;
      analogWrite(turnSignalRearR,constStateLed);
      digitalWrite(turnSignalStateFrontR,0);
      sendData("turn signal right OFF");
    }

    //Hazzard lights ON   
    if(Data==('9')){
      turnSignalStateRearL = true;
      turnSignalStateRearR = true;
      turnSignalStateFrontL = true;
      turnSignalStateFrontR = true;
     
      sendData("HAZARD lights ON");
    }
    //Hazzard lights OFF
    if(Data==('0')){
      turnSignalStateRearL = false;
      turnSignalStateRearR = false;
      turnSignalStateFrontL = false;
      turnSignalStateFrontR = false;
      analogWrite(turnSignalRearL,constStateLed);
      analogWrite(turnSignalRearR,constStateLed);
      sendData("HAZARD lights OFF");
    }
  }
}

Edit. Problem z wyłączeniem przednich kierunkowskazów rozwiązany, niestety problem z brakiem synchronizacji pozostaje Sad
 
Odpowiedź
#10
W poprzednim poście napisałeś to tak, jakbyś chciał mieć PWM wysterowany wartościami od 50 do 255.
Z ostatniego wynika, że to ma być od 50 do 100%.
Pisząc w taki sposób sprawiasz, że nie wiem o co Ci chodzi.
Masz za duży bałagan w kodzie by nad tym zapanować. Można tak pisać programy mające 20 linii kodu, a potem trzeba się nauczyć jak się pisze programy, od szczegółu do ogółu.
Budujesz cegiełkę, z cegiełek ściany, ze ścian domek, z domków osiedle, z osiedli miasto.
Jak wpadasz z cegiełkami budować państwo, to się zarypiesz.
Teraz znaleźć tu błąd to praca kopciuszka wybierającego mak z popiołu.
Już sam początek loop, po co 4x sięgasz do millis, zmienne będą miały różne wartości, każde odwołanie do funkcji trwa, przecież przez cały loop wystarcza JEDNO aktualne currentTime. Co więcej nie musisz liczyć każdemu migaczowi indywidualnego czasu, ustal jakiś puls programu, heartbeat, w jego rytmie wykonuj czynności. Człowiek nie zauważy, że miganie zaczęło się 100ms później po naciśnięciu przycisku/wysłaniu komendy, ale zauważy rozbieżność 20ms pomiędzy poszczególnymi ledami.
Jeśli masz operacje logiczne na liczbach 8 bitowych to zajmują 1 cykl zegara, 63ns, jak bawisz się ciągle 32 bitowymi to trwa to już us.
Sprawdź w moich poprzednich postach przykłady z funkcja czas(), raz odczytany millis napędza wszystkie flagi i liczniki upływającego czasu, ale te najczęściej używane są 8 bitowe, potem wystarczy sprawdzenie czy w danym obiegu loop jest nowa dziesiątka ms by robić coś tylko co 10ms, albo nowa i podzielna przez 2 by robić coś tylko co 20ms, ale jeśli coś ma być co 10 i co 20ms to zostanie zrobione dokładnie w tym samym obiegu loop.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości