Wątek przeniesiony 2018-11-08 12:49 z C/C++ przez Marooned.

Sterowanie przyciskami, instrukcja warunkowa IF ELSE

Odpowiedz Nowy wątek
2018-10-30 23:02
0

Witam

Pracuję nad projektem symulującym magistralę CAN-BUS w samochodzie.

Jako że kierunkowskazy są sterowane po magistrali, postanowiłem napisać program, który na podstawie odpowiednio wciśniętego przycisku podłączonego do konkretnego wyjścia cyfrowego będzie podstawiał we wskazane miejsce daną wartość w czasie rzeczywistym.

Pomysł OK, dla trzech kierunkowskazów działa, tj. Prawy, Lewy, i Awaryjne. Natomiast problem jest taki, że jeśli instrukcję IF rozbuduję o np. kolejne 4 opcje program tak jakby się zapętla, czy coś w tym stylu i na wejściu podstawia wartość z trzeciego warunku,więc cały czas miga kierunkowskaz lewy przykładowo.

Natomiast jeżeli wcisnę button od kierunkowskazu prawego to działa, ale jeśli wcisnę kolejną wartość to już nie działa. Wniosek ==> program działa dla pierwszych trzech wejść cyfrowych 0, 1 i 2, dla reszty nie działa. Próbowałem z instrukcją switch case, jak i różnymi wariantami IF ELSE, problem wciąż ten sam. Nie wiem gdzie popełniam błąd. Będę bardzo wdzięczny za udzielenie porady.

Użyte piny cyfrowe:

//#################wejscia cyfrowe#################
int st0 = 0;
int st1 = 1;
int st2 = 2;
int st3 = 3;
int st4 = 4;
int st5 = 5;
int st6 = 6;
....
void setup()
{
    pinMode(st0, INPUT_PULLUP);
    pinMode(st1, INPUT_PULLUP);
    pinMode(st2, INPUT_PULLUP);
    pinMode(st3, INPUT_PULLUP);
    pinMode(st4, INPUT_PULLUP);
    pinMode(st5, INPUT_PULLUP);
    pinMode(st6, INPUT_PULLUP);
......

Pętla wstawiająca wartość konkretnego bitu sygnału CAN-BUS:

if (digitalRead(st0) == LOW)
    {
      program1();
    }else if (digitalRead(st1) == LOW)
    {
      program2();
    }else if (digitalRead(st2) == LOW)
    {
      program3();
    }else if (digitalRead(st3) == LOW)
    {
      program4();
    }else if (digitalRead(st5) == LOW)
    {
      program6();
    }else if (digitalRead(st4) == LOW)
    {
      program5();
    }else
    {
      program0();
    }

Ja "wyrzuciłem" wszystkie warianty poza główną pętlę, tworząc podprogramy:

//###############podprogramy###############
void program0()
{
        turning_light = 0;
        c_1 = 0;
        c_2 = 0;
        c_3 = 0;
        c_4 = 0;
        c_5 = 0;
        c_6 = 0;
}
//############### kierunkowskaz lewy###############
void program1()
{     
      if(c_1 == 7)
      {
        turning_light = 1;
        c_1 = c_1 + 1;
      }else if(c_1 == 14)
      {
        turning_light = 0;
        c_1 = 0;
      }else{
        c_1 = c_1 + 1;
      }
}
//###############kierunkowskaz prawy###############
void program2()
{
      if(c_2 == 7)
      {
        turning_light = 2;
        c_2 = c_2 + 1;
      }else if(c_2 == 14)
      {
        turning_light = 0;
        c_2 = 0;
      }else{
        c_2 = c_2 + 1;
      }
}
//###############swiatła awaryjne###############
void program3()
{ 
      if(c_3 == 7)
      {
        turning_light = 3;
        c_3 = c_3 + 1;
      }else if(c_3 == 14)
      {
        turning_light = 0;
        c_3 = 0;
      }else{
        c_3 = c_3 + 1;
      }
}
//###############kierunkowskaz lewy przyczepy###############
void program4()
{ 
      if(c_4 == 7)
      {
        turning_light = 6;
        c_4 = c_4 + 1;
      }else if(c_4 == 14)
      {
        turning_light = 0;
        c_4 = 0;
      }else{
        c_4 = c_4 + 1;
      }
}
//###############kierunkowskaz prawy przyczepy###############
void program5()
{ 
      if(c_5 == 7)
      {
        turning_light = 7;
        c_5 = c_5 + 1;
      }else if(c_5 == 14)
      {
        turning_light = 0;
        c_5 = 0;
      }else{
        c_5 = c_5 + 1;
      }
}
//############### światła awaryjne przyczepy###############
void program6()
{ 
      if(c_6 == 7)
      {
        turning_light = 8;
        c_6 = c_6 + 1;
      }else if(c_6 == 14)
      {
        turning_light = 0;
        c_6 = 0;
      }else{
        c_6 = c_6 + 1;
      }
}

Zmienna turning_lights ma właśnie przybierać zakodowane prze zemnie wartości.

edytowany 1x, ostatnio: furious programming, 2018-10-30 23:42
Formatowanie treści – przeczytaj. Kod wstawiamy w odpowiednie znaczniki kolorujące składnię. - furious programming 2018-10-30 23:43

Pozostało 580 znaków

2018-10-31 11:06
1

1. Sama konstrukcja if...else wygląda w porządku. Dlatego podejrzewam, że problem leży bardziej w ustawieniach pinów/portów lub w samym podłączeniu diod.

2. Jeśli chodzi o konfigurację pinów ciężko cokolwiek sprawdzić, bo nie jestem w stanie zweryfikować takich magicznych zapisów jak c_5 == 14, czy też turning_light = 8. Zbyt dużo w Twoim kodzie powielonej logiki, magicznych liczb i dziwnych kombinacji, dlatego nie mam możliwości sprawdzenia poprawności.

3. Jeśli chodzi o warstwę sprzętową Twojego projektu to sprawdziłbym prawidłowe podłączenie przycisków odczytywanych stanem niskim i podłączenie diod. Możliwe, że sam warunek by się wykonał, gdyby niżej wszystko było OK.

4. Nie pamiętam czy środowisko Arduino ma jakiś debugger, ale jeśli tak to warto byłoby ustawić pułapki na pierwszym warunku i na tych, które rzekomo są pomijane.

Pozostało 580 znaków

2018-10-31 11:15
4
Adam Brzeziński napisał(a):
//############### kierunkowskaz lewy###############
void program1()
{     
    ....
}
//###############kierunkowskaz prawy###############
void program2()
{
    ....
}

Mały offtopic: czemu sobie utrudniasz życie? Nie lepiej tak:

void kierunkowskazWlaczLewy()
// albo: turnSignalsLeftOn()
{     
    ....
}
 
void kierunkowskazWlaczPrawy()
// albo: turnSignalsRightOn()
{
    ....
}

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22, 2018-10-31 11:17

Pozostało 580 znaków

2018-10-31 11:56
0

@Bartosz36:

Dziękuję kolego za odpowiedź :)
Już wyjaśniam.
c_1, c_2 itd. są to liczniki, które służą to tego aby kierunkowskazy migały ==> tutaj jest wszystko ok.
turning_light, jest to zmienna która ma przybierać wartości, które następnie będą miały odzwierciedlenie w działaniu układu,
Jak mam ramkę sygnału CAN-BUS, to na pierwszym bicie są wartości od 1 do 8 oraz liczba 200
1 kierunek lewy
2 kierunek prawy
...
200 sygnalizacja braku ładowania akumulatora

Podłączyłem 7 wyjśc cyfrowych od D0 do D6
D0 lewy
D1 prawy
D2 awaryjne
D3 lewy przyczepy
D4 prawy przyczepy
D5 awaryjne przyczepy
D6 brak ładowania

Podłączałem wg zaleceń, z wyjścia cyfrowego, przez button potem do masy.

Czyli jest tak jak piszesz, ze albo mam problem z wyjściami, albo jest problem w instrukcją IF :/

@MarekR22:

No Twój zapis jest o wiele bardziej klarowny :)
Dziękuję za uwagę :)

edytowany 3x, ostatnio: furious programming, 2018-10-31 13:50

Pozostało 580 znaków

2018-10-31 12:00
2

Jakbym to ja zrobił.
Po pierwsze oddzieliłbym UI od logiki.
Skoro przyciski używasz jak radio buttony to napisałbym coś takiego:

class IButtonsFunctions {
public:
      virtual ~ButtonsFunctions() {}
      virtual bool digitalRead(int buttonId) = 0;
};
 
class HardwareButtonsFunctions : public IButtonsFunctions 
{
public:
    bool digitalRead(int buttonId) override
    {
        ::digitalRead(buttonId);
    }
};
HardwareButtonsFunctions hardwareButtonsFunctions;
 
class RadioButtons
{
public:
    using Action = std::function<void(bool)>;
 
    explicit RadioButtons(int firstButtonId, std::initialization_list<Action> actions)
        : RadioButtons(firstButtonId, std::move(actions), hardwareButtonsFunctions)
    {
    }
 
    explicit RadioButtons(int firstButtonId, std::initialization_list<Action> actions, IButtonsFunctions &buttons)
        : mFirstButton(firstButtonId)
        , mActions(std::move(actions))
        , mLastAction{ -1 }
        , mButtons(buttons)
    {
    }
 
    void checkButtons()
    {
          for (int i = 0; i < mActions.size(); ++i) {
               if (mButtons.digitalRead(i + mFirstButton)) {
                     activateAction(i);
                     break;
               }
          }
    }
 
    void activateAction(int actionId) {
        if (mLastAction != actionId) {
            if (mLastAction >= 0) {
                mActions[mLastAction](false);
            }
            mActions[actionId](true);
            mLastAction = actionId;
        }
    }
 
private:
    const int mFirstButton;
    std::vector<std::function<void(bool)> mActions;
    int mLastAction;
    IButtonsFunctions &mButtons;
};

W testach (gtest + gmock) po prostu wystarczy coś takiego:

class MockButtons : public IButtonsFunctions
{
public:
     MOCK_METHOD1(digitalRead, bool(int buttonId));
};
 
TEST(RadioButtonstTest, initDoNotInvokeAnything)
{
     MockButtons mockButtons;
     EXPECT_CALL(mockButtons, digitalRead(_)).Times(0);
     RadioButtons testRadioButton{ 3, { [](bool a) {} }, mockButtons};
}

W kodzie wyglądało by to tak:

RadioButtons radioButton { 
    0,
    {
         [](bool active) { if (active) program0(); },
         [](bool active) { if (active) program1(); },
         ....
    }
};
 
while (1)
{
      ....
      radioButton.checkButtons();
      ....
};

Pewnie przekombinowałem z tym, by akcja była wywoływana z wartością bool, ale chodzi mi bardziej o koncept jak lepiej pisać takie rzeczy.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 4x, ostatnio: MarekR22, 2018-10-31 13:51
@MarekR22: Ale wiesz, że ten kod z pierwszego posta to na prawdopodobnie na Arduino jest? - Sparrow-hawk 2018-11-10 19:48
Tak wiem. No i co z tego. Czy coś to zmienia? - MarekR22 2018-11-10 20:10
No po za brakiem std::vector, std::initialization_list, std::function, std::move to żadna różnica. - Sparrow-hawk 2018-11-11 14:51
ok jakaś jest to różnica, ale nie jest ona istotna dla tej odpowiedzi. W tej odpowiedzi chodzi o to by pisać testy do kodu i pisać kod używając uogólnień i właściwego podziału na klasy. Może przepiszę to na wersję z szronową, która powinna być "lżejsza", ale jest trudniejsza w zrozumieniu. - MarekR22 2018-11-13 10:39

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0