Cykliczna zmiana nie stałych zmiennych w funkcji

0

Cześć.
Robię projekt polegający na podzieleniu trasy kolejki piko na odcinki punktami pomiarowymi w celu zliczania ilości osi pociągów znajdujących się na poszczególnych odcinków. Każdy punkt pomiarowy składa się z dwóch czujników odbiciowych (CNY70), podłączonych do Mikrokontrolera Atmega88.
Napisałem program, który liczy osie przejeżdżające pomiędzy dwoma sąsiednimi odcinkami:

void LicznikOsi_AB (void)                                             //funkcja liczy osie przejeżdżające między odcinkami A oraz B (w obydwu kierunkach) - w funkcji main                         //zagnieżdzona w pętli nieskończonej while
{
    PP_AB_poprzedni = PP_AB;                                      //PP_AB - stan punktu pomiarowego AB, PP_AB_poprzedni - stan PP_AB w poprzednim cyklu
    StanPP_AB();
    if ((PP_AB_poprzedni == 0) && (PP_AB == 1))
    {
        Odc_B++;                                                         // zwiększ ilość osi na odcinku B
    }
    else if ((PP_AB_poprzedni == 1) && (PP_AB == 0))
    {
        if (Odc_B == 0)
            Odc_B = 0;
        else
            Odc_B--;
    }
    if ((PP_AB_poprzedni == 0) && (PP_AB == 3))
    {
        Odc_A++;
    }
    else if ((PP_AB_poprzedni == 3) && (PP_AB == 0))
    {
        if (Odc_A == 0)
            Odc_A = 0;
        else
            Odc_A--;
    }
    zn1 = Odc_A;                                                             // wyświetl ilość osi na odcinku A na pozycji I wyświetlacza 7 segmentowego
    zn2 = Odc_B;
}

Tak napisany program działa prawidłowo, jednak kolejne punkty pomiarowe wymagają zastosowania kolejnych funkcji, cyklicznie wywoływanych w pętli while, właściwie identycznych, wymagających tylko zmiany zmiennych (np. PP_AB na PP_BC, Odc_A na Odc_B, Odc_B na Odc_C itd.). Jest to jednak rozwiązanie pracochłonne (konieczność ręcznej zmiany zmiennych we wszystkich liniach programu), mało funkcjonalne (przy zmianie układu odcinków ponownie konieczność ręcznej zmiany zmiennych w całym programie) i do tego mało ekonomiczne (powstaje spora ilość kodu, zajmująca sporą ilość pamięci.
Podjąłem nieudaną próbę stworzenia uniwersalnej funkcji, w której cyklicznie, w odpowiednie miejsca programu, wprowadzane by były zmienne dotyczące kolejnych punktów pomiarowych:

void LicznikOsi (void)
{
    if (i == 2)                   //cykliczna zmiana wartości i
        i = 0;
    else i++;
    
    int8_t PP_PIN[]         = {PINAB, PINBC, PINBD};                            // określa piny którego portu mikrokontrolera mają być odczytane przy sprawdzaniu stanu czujników //kolejnych Punktów pomiarowych - - wykorzystane w funkcji StanPP()
    int8_t PP_CiN_PIN[]     = {AB_CA_PIN, BC_CB_PIN, BD_CB_PIN};     //piny mikrokontrolera, do których podłączone są czujniki punktów pomiarowych po stronie odcinka o //niższym indeksie - wykorzystane w funkcji StanPP()
    int8_t PP_CiW_PIN[]     = {AB_CB_PIN, BC_CC_PIN, BD_CD_PIN};    // -||- wyższym indeksie
    int8_t PP_CiN[]         = {AB_CA, BC_CB, BD_CB};                         // stan czujnika po stronie odcinka o niższym indeksie - wykorzystane w funkcji StanPP()
    int8_t PP_CiW[]         = {AB_CB, BC_CC, BD_CD};                        // -|- wyższym indeksie
    int8_t PP_Stan[]        = {PP_AB, PP_BC, PP_BD};                         // stan punktu pomiarowego
    int8_t PP_Poprzedni[]   = {PP_AB_Poprzedni, PP_BC_Poprzedni, PP_BD_Poprzedni};      //stan punktu pomiarowego w poprzednim cyklu
    int8_t Odc_iN[]         = {Odc_A, Odc_B, Odc_B};                         //odcinek sąsiadujący z punktem pomiarowym o niższym indeksie
    int8_t Odc_iW[]         = {Odc_B, Odc_C, Odc_D};                        //-|- wyższym indeksie
    

    PP_Poprzedni[i] = PP_Stan[i];
    StanPP();       //funkcja wyznacza stan PP(punktu pomiarowego) na podstawie stanu dwóch czujników należących do tego PP
    if ((PP_Poprzedni[i] == 0) && (PP_Stan[i] == 1))
    {
        Odc_iW[i]++;
    }
    else if ((PP_Poprzedni[i] == 1) && (PP_Stan[i] == 0))
    {
        if (Odc_iW[i] == 0)
            Odc_iW[i] = 0;
        else
            Odc_iW[i]--;
    }
    if ((PP_Poprzedni[i] == 0) && (PP_Stan[i] == 3))
    {
        Odc_iN[i]++;
    }
    else if ((PP_Poprzedni == 3) && (PP_Stan == 0))
    {
        if (Odc_iN[i] == 0)
            Odc_iN[i] = 0;
        else
            Odc_iN[i]--;
    }
    zn1 = Odc_A;
    zn2 = Odc_B;
    zn3 = Odc_C;
    zn4 = Odc_D;
}

Szybko stało się jasne, że metoda z wprowadzeniem tablic nie ma szans powodzenia, jednak wstawiłem tutaj nieudany kod, aby było bardziej jasne jaki efekt chciałbym osiągnąć.
Proszę o informacje, podpowiedzi, sugestie od bardziej doświadczonych programistów jak (jakimi narzędziami) napisać uniwersalną funkcję dla opisanego wyżej programu (i czy gra jest warto świeczki - tzn. czy napisanie uniwersalnej funkcji nie skomplikuje bardziej programu niż da korzyści).

Ponieważ do tej pory nie otrzymałem żadnej odpowiedzi obawiam się, czy moja wypowiedź jest zrozumiała i czy zawiera wystarczającą ilość informacji.
Ponieważ jestem na początku mojej przygody z programowaniem, a powyższy post to pierwszy mój post na forum programistycznym, jeżeli mój post został napisany w sposób, który zniechęca do odpowiadania na niego, proszę o komentarz wyjaśniający, co należy w nim zmienić, aby była szansa uzyskania konstruktywnej odpowiedzi.

0

Skróć kod do kilku linijek związanych z problemem, napisz co chcesz zrobić, a nie jak to próbujesz rozwiązać.

Nie pisz detali do czego i po co Ci to ani żadnych historii życiowych. Napisz co jest na wejściu i co ma być na wyjściu, odpuść nam część techniczną, chyba że jest związana z problemem. Jeśli masz więcej niż jeden problem to stwórz dwa wątki.

Generalnie jeśli w ciągu pierwszych dwóch zdań nie jestem w stanie zrozumieć o co chodzi to nie czytam dalej.

Swoją drogą to temat to masło maślane: nie stała zmienna?

3
  1. Bez przesady, napisałeś temat o 1 w nocy (!), jest raptem 9 rano a ty już lamentujesz że nie ma odpowiedzi. Serio, ludzie śpią i chodzą do pracy...
  2. Ja zupełnie nie rozumiem o co pytasz, bo przedstawiłeś to w bardzo skomplikowany sposób. Czy w zrozumieniu twojego problemu ma w ogóle znaczenie że masz tam jakieś mikrokontrolery i czujniki? Wydaje mi sie że nie, a mimo to piszesz o tym co tylko komplikuje całą sprawę.
  3. Wstawiasz kod który miesza wszystkie możliwe poziomy abstrakcji (od poziomu sprzętu do poziomu algorytmu który coś liczy). Mam wątpliwości czy sam rozumiesz ten kod na pierwszy rzut oka ale nie mam wątpliwości że nikt poza tobą go nie zrozumie. Pokaż ten kod swojej mamie albo młodszej siostrze i spytaj czy rozumieją co się tam dzieje. Jeśli nie rozumieją to jest nieczytelny.
  4. Piszesz tu o jakichś osiach i punktach pomiarowych jakbyśmy mieli taką samą wiedzę dziedzinową jak ty. Nie mamy. Rzecz w tym że na 99% wcale nie musimy, wystarczy że opiszesz swój problem w sposób bardziej abstrakcyjny a najlepiej w sposób matematyczny.

Co mówi mi moja szklana kula na temat twojego problemu:

  • Masz pewien graf po którym poruszają się obiekty. Napisałeś funkcję która potrafi wykryć kiedy obiekt wjechał na daną krawędź grafu oraz kiedy z niej zjechał.
  • Twoja funkcja nie jest uniwerslna, tzn ma zajhardkodowany wierzchołek początkowy oraz końcowy.
  • Chcesz przepisać ją na wersję uniwersalną, która będzie wyliczać wynik dla całego grafu.
    Czy tak?

Pierwszy błąd jest taki że mieszasz poziomy abstrakcji. Na poziomie algorytmu NIE MA MIEJSCA na żadne piny. Algorytm powinien w ogóle nie wiedzieś skąd płyną dane, bo jest to dla niego zupełnie nie istotne.
Drugi błąd jest taki, że wyłączyłeś myślenie bo masz tylko 3 odcinki. A gdyby odcinków było 1000? Albo w ogóle N które jest nieznane? Albo gdyby graf połączeń był czytany na wejsciu programu? To też byś kombinował tak samo jak teraz? Wątpię.

  1. Podziel to ładnie na poziomy abstrakcji.
  2. Zrób ładny abstrakcyjny model danych, w tym przypadku jakiś graf.
  3. Napisz funkcję która dla danej krawędzi grafu sprawdza czy ktoś z niej zjechał / na nią wjechał.
  4. Wywołaj ta funkcje dla wszystkich krawędzi.
0

Dziękuję za odpowiedzi.
Ad 2. Zrób ładny abstrakcyjny model danych, w tym przypadku jakiś graf
Na rysunku model danych
75a5b0a26a.png

Ad 3. 3. Napisz funkcję która dla danej krawędzi grafu sprawdza czy ktoś z niej zjechał / na nią wjechał.
Napisałem funkcję, która, w zależności od odpowiedniej sekwencji wartości zmiennej PP_AB (która może przyjmować wartości od 0 do 3), może powodować: wzrost o 1 wartości zmiennej Odc_A, spadek o 1 wartości zmiennej Odc_A, wzrost o 1 wartości zmiennej Odc_B, spadek o 1 wartości zmiennej Odc_B.
Poniżej wklejam kod tej funkcji:

 void LicznikOsi_AB (void)                                            //funkcja liczy osie przejeżdżające między odcinkami A oraz B (w obydwu kierunkach). W programie funkcja umieszczona jest w funkcji głównej main, w pętli nieskończonej while
{
    PP_AB_poprzedni = PP_AB;                                      //PP_AB - stan punktu pomiarowego AB, PP_AB_poprzedni - stan PP_AB w poprzednim cyklu
    StanPP_AB();
    if ((PP_AB_poprzedni == 0) && (PP_AB == 1))
    {
        Odc_B++;                                                         //zwiększ ilość osi na odcinku B
    }
    else if ((PP_AB_poprzedni == 1) && (PP_AB == 0))
    {
        if (Odc_B == 0)
            Odc_B = 0;
        else
            Odc_B--;
    }
    if ((PP_AB_poprzedni == 0) && (PP_AB == 3))
    {
        Odc_A++;
    }
    else if ((PP_AB_poprzedni == 3) && (PP_AB == 0))
    {
        if (Odc_A == 0)
            Odc_A = 0;
        else
            Odc_A--;
    }
} 

Ad 4.Wywołaj ta funkcje dla wszystkich krawędzi.
To jest punkt, którego nie wiem jak zrealizować (w moim przypadku -4. Wywołaj tę funkcje dla wszystkich punktów pomiarowych)
Jedyne co mi się udało zrobić, to stworzenie oddzielnych funkcji dla każdego punktu pomiarowego i ręczna zmiana nazw zmiennych w całym kodzie dla kolejnych punktów pomiarowych (PP_AB na PP_BC itd.)
Proszę o podpowiedzi jak stworzyć uniwersalną funkcję, która potrafiłaby obsłużyć po kolei wszystkie punkty pomiarowe.

0

Czemu argumentami tej funkcji nie są te twoje miejsca pomiaru i aktualne liczby pojazdów na danym odcinku? Najlepiej gdyby w ogóle dane odcinka były strukturą...

0

Takie małe spostrzeżenie

if (Odc_B == 0)
            Odc_B = 0;
        else
            Odc_B--; 

Czemu nie:

if (Odc_B != 0) Odc_B--;

Stan zmiennej nie zmienia się przecież od czasu porównania do czasu przypisania, no a skoro ma już wartość zerową to po co nadpisywać zero zerem?

Ja bym też wszystko wrzucił w switch(PP_AB) dla uproszecznia kodu.

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