logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

ANSI C - 3 wywolania tej samej funkcji-3 zestawy parametrow

Bigfoot 11 Kwi 2008 16:01 1581 8
REKLAMA
  • #1 5018792
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    Napisalem sobie funkcje, ktorej zadaniem jest wystawienie na PIN_OUT ustalonego sygnalu wejscioweo (w przykladzie ponizej jest to pin 3 portu A ustalony przez 100ms).
    
    while(1){
    ...
    PIN_OUT = debounce(&PORTA,3, 100);
    ...
    }

    Funkcja jest wywolywana w glownej petli programu co 1ms, zwraca stabilny stan (0 lub 1) jezeli wewnetrzny licznik (zmienna static) zliczy zadana wartosc, np. 100). Wszystko dziala tak jak powinno, pytanie moje brzmi: czy jest mozliwe w ANSI C aby jedna funkcja - ta wlasnie debounce() - byla wywolywana w programie kilka razy z roznymi argumentami i zeby dzialala na trzech osobnych zestawach zestawach parametrow wewnetrznych. Inaczej mowiac: chce ta funkcja sprawdzac 3 rozne piny wejsciowe i wystawiac stabilny stan na 3 innych pinach wyjsciowych, czyli:
    PIN_OUT_1 = debounce(&PORTA,3, 100);
    PIN_OUT_2 = debounce(&PORTA,4, 100);
    PIN_OUT_3 = debounce(&PORTA,5, 100);

    Poniewaz funkcje te wywolywane sa co milisekunde i kazde z tych wywolan zmienia wewnetrzne liczniki funkcji, sposob ten nie bedzie dzialal prawidlowo, Czy jedynym sposobem jest stworzenie trzech identycznych, lecz osobnych funkcji robiacych tak naprawde to samo, czyli powiedzmy debounce1(), debounce2() i debounce3()? Czy istnieje jakis sposob by powiedziec kompilatorowi, ze moje 3 wywolania maja odnosic sie do trzech roznych zestawow zmiennych wewnetrznych funkcji?

    Sama funkcja wyglada tak:
    unsigned char debounce2(volatile unsigned char *PORT, unsigned char pin, unsigned int cycles){
    static unsigned int cnt;
    static unsigned char OUT;	
    
    if (OUT==0){
    	cnt = check_bit(*PORT, pin) ? (cnt + 1) : 0 ;
    	if (cnt > cycles) { cnt = 0; OUT = 1;}
    }
    else {
    	cnt = check_bit(*PORT, pin) ? 0 : (cnt + 1);
    	if (cnt > cycles) { cnt = 0; OUT = 0; }
    }
    return OUT;
    }


    BF
  • REKLAMA
  • #2 5018905
    szelus
    Poziom 34  
    Posty: 1508
    Pomógł: 315
    Ocena: 53
    Chyba najprościej będzie dodać jeszcze jeden argument - wskaźnik na używany licznik.
    Poprawka - oczywiście mam na myśli cały zetaw parametrów (struktura).
  • REKLAMA
  • #3 5019798
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    Tak jak mowisz robilem dotychczas z podobnymi funkcjami - jedna funkcja i iles tam wskaznikow do struktur. Piszac ten post mialem po prostu nadzieje, ze moze jest jakis sprytny sposob na zrzucenie tego na kompilator.

    BF
  • #4 5019874
    szelus
    Poziom 34  
    Posty: 1508
    Pomógł: 315
    Ocena: 53
    W C++ bez problemu, ale w C to ciężko. Można, co najwyżej, próbować wykorzystać sprytnie makra i generować nazwy zmiennych z kombinacji argumentów. Ale to trochę hardcore.
  • REKLAMA
  • #5 5020050
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Bigfoot napisał:
    ... Inaczej mowiac: chce ta funkcja sprawdzac 3 rozne piny wejsciowe i wystawiac stabilny stan na 3 innych pinach wyjsciowych...

    Po pierwsze , niepotrzebnie komplikujesz proste zadanie, a po wtóre , jak chcesz "sprawdzac 3 rozne piny wejsciowe " , to odczytuj właściwy rejestr portu , czyli PINA , a nie PORTA.

    Piotrek
  • REKLAMA
  • #6 5020665
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    Zumek,
    po pierwsze: skoro skomplikowalem to jezeli mozesz pokaz prosze prostszy sposob, po wtore: czy wszyscy na tym forum musza domyslnie przyjmowac, ze kazdy mikrokontroler to AVR? Ja akurat zajmuje sie PICami i odczytuje prawidlowy rejestr.

    BF
  • #7 5020942
    MarasK
    Poziom 18  
    Posty: 231
    Pomógł: 19
    Ocena: 4
    mm, a to nie jest tak, że jak wewnątrz funkcji używasz zmiennych 'zwykłych' to przy każdym wywołaniu tworzone są nowe zmienne, a jak 'volatile' (nie wiem czy w Twoim środowisku są takie) to są one globalne - wspólne dla każdego wywołania?
  • #8 5020968
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Bigfoot napisał:
    Zumek,
    po pierwsze: skoro skomplikowalem to jezeli mozesz pokaz prosze prostszy sposob,

    Nie pokazałeś funkcji check_bit - a szkoda.
    U mnie , tak by to mogło wyglądać
    
    unsigned char debounce(volatile unsigned char *PORT, unsigned char pin, unsigned int cycles)
    {
    static unsigned int cnt=0;
    static unsigned char OUT=0;   
    
    /* gdy check_bit() zwraca "0" lub "!0" */
    cnt+=( (!OUT && check_bit(*PORT, pin)) || (OUT && !check_bit(*PORT, pin)) ) ? 1:0;
    
    /* gdy check_bit() zwraca "0" lub "1" */
    cnt+= (OUT + check_bit(*PORT, pin)) & 1
    
    /* a to juz normalnie */
    if (cnt > cycles) { cnt = 0; OUT ^= 0x01;}
    
    return OUT;
    }
    

    Jednakże , by nie powielac funkcji x-krotnie , to można wykorzystać tablice
    
    unsigned char debounce(unsigned char num, unsigned int cycles)
    {
    static unsigned int cnt[3]={0,0,0};
    static unsigned char OUT[3]={0,0,0};
    static char *PORT[3]={(char*)&PORTA,(char*)&PORTA,(char*)&PORTA};
    static unsigned char PINPORT[3]={3,4,5};
    
    //cnt[num]+=( (!OUT[num] && check_bit(*PORT, pin[num])) || (OUT[num] && !check_bit(*PORT, pin[num])) ) ? 1:0;
    
    //cnt[num]+=(OUT[num] + check_bit(*PORT[num], PINPORT[num])) & 1;
    
    if (cnt[num] > cycles) { cnt[num] = 0; OUT[num] ^= 0x01;}
    
    return OUT[num];
    /* ... main() */
    
    PIN_OUT_1 = debounce( 0, 3);
    PIN_OUT_2 = debounce( 1, 6);
    PIN_OUT_3 = debounce( 2, 9);
    
    

    Albo jeszcze te PIN_OUT-y wsadzić w tablice w funkci debounce , cycles-y :D w tablicę globalną i "przelecieć" to wszystko 3 krotnie , wywołując debounce raz , co 1ms.

    Myślę - a nawet jestem pewien , że rozwiązań jest więcej.


    Bigfoot napisał:
    po wtore: czy wszyscy na tym forum musza domyslnie
    przyjmowac, ze kazdy mikrokontroler to AVR? Ja akurat zajmuje sie PICami i odczytuje prawidlowy rejestr.BF

    Nie pisnąłeś , że chodzi o PICusia ;)
    W moim Firefox-ie , przy zakładce elektroda.pl stoi:
    DEFAULT=AVR OR ARM7TDMI :twisted:

    Piotrek
  • #9 5022232
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    Marask: Nie 'volatile' a 'static'.

    Zumek: rzeczywiscie, Twoj zapis jest bardziej kompaktowy, zaoszczedza troche bajtow kodu i jest zgrabniejszy - za to dziekuje. Niestety jest w nim blad: tak skonstruowany jak podales wcale nie bedzie powodowal wystawiania stabilnego stanu - bedzie po prostu zliczal impulsy i gdy zliczy ich odpowienia liczbe zasygnalizuje to. Jezeli co sekunde na powiedzmy 4ms pojawial bedzie sie na sprawdzanym pinie krotki impuls to po 25 sekundach Twoja funkcja stwierdzi, ze stan na wejsciu jest stabilny mimo, ze nie jest. Funkcja powinna stwierdzic, ze stan jest stabilny tylko wtedy, jezeli przez zadany czas (w przykladzie 100ms) stan sprawdzanego pinu jest niezmienny. Funkcja powinna wiec wygladac tak:
    cnt = ((!OUT && check_bit(*PORT, pin)) || (OUT && !check_bit(*PORT, pin))) ? (cnt + 1) : 0;
    if (cnt > cycles) { cnt = 0; OUT=!OUT; }
    return OUT;

    Oczywiscie zakladam, ze probkowanie co 1ms mnie zadowala.
    Dla scislosci: moje check_bit nie jest funkcja a makrem i daje 0 lub !0
    #define check_bit(X, n) (X & (1 << n)) 

    A wracajac do samego pytania zadanego na poczatku, idea dotyczyla tego czy w czystym C mozna zrzucic na kompilator "opiekowanie" sie wewnetrznymi zmiennymi funkcji wywolanej kilka razy - widze, ze trzeba zrobic to samemu (jak do tej pory robilem). A nie wspomnialem, ze chodzi o PICusie bo pytanie dotyczylo ANSI C :)

    BF

Podsumowanie tematu

✨ Dyskusja dotyczy implementacji funkcji debounce w ANSI C, która ma być wywoływana wielokrotnie z różnymi zestawami parametrów, aby stabilizować sygnały z trzech różnych pinów wejściowych i wystawiać je na trzech pinach wyjściowych. Problemem jest obsługa niezależnych liczników i stanów wewnętrznych funkcji przy wielokrotnych wywołaniach. Proponowane rozwiązania obejmują przekazywanie wskaźnika do struktury przechowującej stan licznika i wyjścia, co pozwala na utrzymanie osobnych zestawów parametrów dla każdego pinu. Wskazano, że w czystym C nie ma prostego mechanizmu automatycznego rozdzielenia stanów funkcji, jak w C++, a ewentualne użycie makr do generowania unikalnych nazw zmiennych jest skomplikowane. Zaproponowano także implementację z tablicami statycznych liczników i stanów, indeksowanych numerem pinu, co umożliwia obsługę wielu wejść w jednej funkcji. Podkreślono, że funkcja powinna liczyć czas niezmienności stanu pinu, a nie sumować impulsy, aby prawidłowo wykrywać stabilny sygnał. W dyskusji pojawiła się uwaga dotycząca poprawnego odczytu rejestru portu (PINA zamiast PORTA) w zależności od mikrokontrolera, z zaznaczeniem, że autor używa PIC, a nie AVR. Poruszono także różnicę między zmiennymi static a volatile w kontekście ich zakresu i trwałości w funkcji.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA