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

[atmega8][c] funkcja oczekiwania na naciśnięcie przycisków

Piotr Kania 08 Lut 2009 23:36 2066 27
REKLAMA
  • #1 6123828
    Piotr Kania
    Poziom 15  
    Robię manu do zegara używam funkcji

    #define WAIT_P1_LOW() while(PIND&(1<<0))
    #define WAIT_P1_SET() while(!(PIND&(1<<0)))

    program zatrzymuje się i czeka na przycisk. Moje pytanie jest następujące jak tą funkcje zmodyfikować żeby czekała naciśnięcie jakiegokolwiek przycisku jednego z np dwóch . Próbowałem zrobić to tak

    #define WAIT_P1LUBP2() while((PIND&(1<<0))&(PIND&(1<<1)))

    program nie zatrzymuje się tylko sprawdza i leci dalej. Prosze o pomoc

    Dodaje że w kśiążce Dolińskiego jest to zrobione tak while(sw1&sw4);
  • REKLAMA
  • #2 6124170
    Freddie Chopin
    Specjalista - Mikrokontrolery
    odczytac port, ocjonalnie odwrocic stan, jesli nacisniecie przycisku daje zera, zamaskowac bity ktore cie nie interesuja, jesli otrzymana wartosc jest rozna od 0, to zostal nacisniety jakis przycisk

    btw. to skoro tworzysz makro, to warto zadbac o to zeby ladnie wygladalo. przeciwienstwem LOW jest HIGH, a przeciwienstwem SET jest CLEAR (albo reset).

    4\/3!!
  • #3 6124369
    zumek
    Poziom 39  
    Freddie Chopin napisał:
    odczytac port, ocjonalnie odwrocic stan...

    Rozwiązań jest co najmniej kilka, tylko autor tematu powinien się zastanowić , dlaczego warunek while() "nie działa".
    W ramach "samopomocy" podpowiem, że
    
    while((PIND&(1<<0))&(PIND&(1<<1)))

    jest tożsame z

    Proponuję "prześledzić " tę operację, krok po kroku.
  • Pomocny post
    #4 6124474
    pubus
    Poziom 30  
    
    #define WAIT_P while( !(PIND & 0x01) && !(PIND & 0x02) ) {}
    


    Wypadało by pamiętać o klamrach...
    Jeżeli nie będzie klamer pierwsza instrukcja która znajdzie się zaraz za tym zostanie potraktowana jako wnętrze pętli...
  • #6 6124699
    pubus
    Poziom 30  
    Tak oczywiście może być i średnik...
    Jednak ja się tak przyzwyczaiłem...
    Zapis z klamrami wydaje się bardziej logiczny i przejrzysty...
  • #7 6125043
    bobbyAIR
    Poziom 20  
    To ja do postu zumka dodam że warto prześledzić nazwę makra i kod który został napisany
    
    #define WAIT_P1LUBP2() while((PIND&(1<<0))&(PIND&(1<<1))) 

    mamy:
    
    #define WAIT_P1_LOW() while(PIND&(1<<0)) 
    

    więc analogicznie
    
    #define WAIT_P2_LOW() while(PIND&(1<<1)) 
    

    Mamy LUB a wstawiamy ?
  • #8 6127183
    Piotr Kania
    Poziom 15  
    Panowie dziękuje za odpowiedzi. Działa takie coś

    #define WAIT_P1LUBP2() while((PIND&(1<<0)) && (PIND&(1<<1)))

    wystarczyło napisać że trzeba wstawić && zamiast &. Dziękuje pubus za pomoc

    Dodano po 1 [minuty]:

    bobbyAIR próbowałem na OR ale też nie latało, pozdrawiam
  • REKLAMA
  • #9 6127466
    pubus
    Poziom 30  
    & to iloczyn bitowy...
    && to logiczne AND...
  • #10 6127633
    Piotr Kania
    Poziom 15  
    od dziś będę to wiedział dziękuje za pomoc, program działa. Pubus czy mógłbyś mi polecić jakąś literaturę na temat avr i c?
  • #11 6128894
    bobbyAIR
    Poziom 20  
    Latać by latało jakby jeszcze logika była poprawna (jaki sygnał daje przycisk naciśnięty)
    
    #define WAIT_P1LUBP2() while((!(PIND&(1<<0))) || (!(PIND&(1<<1)))) 
    

    Który zapis wolisz to rzecz gustu
  • #13 6129191
    bobbyAIR
    Poziom 20  
    Zgadza się tylko jeśli program czeka to raczej nie ma nic ważnego do roboty i może sobie ten port czytać do bólu. Natomiast w aplikacjach krytycznych czasowo rzeczywiście twoje rozwiązanie ma większy sens
  • REKLAMA
  • #14 6130062
    maly_elektronik
    Poziom 23  
    Jest dość duża różnica pomiędzy && a || :)
    Jeżeli da
    while((!(PIND&_BV(0))) && (!(PIND&_BV(1)))

    To będzie musiał nacisnąć oba przyciski aby program zakończył pętle :)
    A jeżeli da z || to wystarczy ze naciśnie jeden z przycisków :)
    Pozdrawiam maly_elektronik
  • #15 6130157
    Freddie Chopin
    Specjalista - Mikrokontrolery
    bobbyAIR napisał:
    Zgadza się tylko jeśli program czeka to raczej nie ma nic ważnego do roboty i może sobie ten port czytać do bólu. Natomiast w aplikacjach krytycznych czasowo rzeczywiście twoje rozwiązanie ma większy sens

    jesli program czeka, to w istocie nie ma znaczeni czas, ale dwa odczyty z portu, dwie operacje AND, ewentualna negacja logiczna x 2, polaczenie tego w jedno to na moje oko 2-3x tyle kodu niz jeden odczyt, jeden AND i jedno odwrocenie (ewentualne)

    poza 'czasem' liczy sie tez rozmiar kodu i styl w jakim zostal napisany. niby nic, w koncu to tylko oczekiwanie na przycisk, dajmy na to, ze niewydajne zajmuje 10 instrukcji wiecej (czyli 20B). ale 10 takich oczekiwan to juz 200B. dodajac do tego kolejne 10 kiepskich fragmentow kodu (bo procek i tak nic nie robi i czas jest niewazny) moze sie okazac, ze 'gdzies' zginelo 0.5kB kodu. mozna wziasc atmege16, albo 32, albo najlepiej 128, tylko po co, skoro mozna to od razu napisac porzadnie, optymalnie i przy okazji wyrobic sobie dobry nawyk?

    4\/3!!
  • #16 6130837
    Piotr Kania
    Poziom 15  
    Zegar działa na przerwanie zewnętrzne (pcf8583) więc może sobie czekać na przycisk ewjścia do menu w nieskończoność. Freddie Chopin czy mógłbyś swój pomysł wyrazić w kodzie ? Ja szlify graficzne kodu robie dopiero kiedy mi zadziała.
  • Pomocny post
    #17 6131679
    Freddie Chopin
    Specjalista - Mikrokontrolery
    teraz masz:

    while((PIND&(1<<0)) && (PIND&(1<<1)))

    zwroc jednak uwage na to, ze DOKLADNIE to samo osiagniesz piszac:

    while(!( (~PIND) & ((1<<0) | (1<<1)) ))

    poniewasz wszystkie porty (wszystkie rejestry peryferyjne) zadeklarowane sa jako volatile, to w twoim kodzie MUSZA byc dwa odczyty, 2x AND, polaczenie tego w jedno i sprawdzenie warunku (!= 0).

    dla mojej wersji jest to jeden odczyt, odwrocenie, jeden AND, sprawdzenie warunku (tutaj akurat odwrotnego -> == 0).

    4\/3!!
  • #18 6132405
    pubus
    Poziom 30  
    Pewnie, równie dobrze można napisać...
    
    while(!(PIND&0x03))
    

    ...krótko i zwięźle...

    Co do postu mały_elektronik...
    Popracuj nad podstawami działań logicznych bo głupoty chłopie piszesz...!.!.!
  • REKLAMA
  • #19 6132423
    Freddie Chopin
    Specjalista - Mikrokontrolery
    nie, nie mozna, bo twoj kod wymaga podlaczenia w ktorym przycisk wcisniety to 1, a puszczony to 0. w tym temacie (jak i zreszta w wiekszosci przypadkow AVRowych ze wzgledu na pullupy wewnetrzne) jest dokladnie odwrotnie. z tego wzgledu potrzebne jest odwrocenie stanu portu (~) PRZED operacja AND.

    pozatym - krotko i zwiezle, a za tydzien nie bedziesz wiedzial po co tak napisales. zlota zasada - nigdy nie pisac rzeczy typu PORT = 0x29; jesli nie ma to konkretnego uzasadnienia.

    4\/3!!
  • #20 6132647
    Piotr Kania
    Poziom 15  
    while(!( (~PIND) & ((1<<0) | (1<<1)) ))

    to jest interesujące sprawdzę to.

    a to while(!(PIND&0x03)) jest też u Dolińskiego ale nic z tego nie czaje dlatego użyłem
    while((PIND&(1<<0)) && (PIND&(1<<1))) a czy to jest równowazne z while( (~PIND) & ((1<<0) & (1<<1)) )?
  • #21 6132939
    Freddie Chopin
    Specjalista - Mikrokontrolery
    sposob podany przez pubus i moj sa dokladnie tym samym, tyle ze moj ma dodane odwrocenie portu, aby spelniac zalozenia logiki typu active low.

    (1<<0)|(1<<1) = 1|2 = 3 = 0x3

    co do pytania o rownowaznosc - przeanalizuj, przeciez tutaj sa podstawowe operacje logiczne, nic skomplikowanego.

    4\/3!!
  • #22 6134636
    Piotr Kania
    Poziom 15  
    przeanalizowałem to while(!( (~PIND) & ((1<<0) | (1<<1)) ))

    Oto wyniki mojej analizy (przyciski mam podciągnięte)

    a)jak przycisk puszczony
    while(!( (~PIND) & ((1<<0) | (1<<1)) ))
    ! ( (0) & ( 0 | 0 ) ) => 1 czyli pozostaje w pętli while

    b)jak jeden z przycisków naciśnięty
    while(!( (~PIND) & ((1<<0) | (1<<1)) ))
    ! ( (1) & ( 0 | 1 ) ) => 0 czyli omija pętle while

    Dobrze rozumuje ?
  • #23 6134694
    Freddie Chopin
    Specjalista - Mikrokontrolery
    z grubsza tak, choc zapis logiczny jest bledny - (1<<0) to 1, a (1<<1) to 2 - tutaj nic sie nie zmienia.

    po prostu:
    1. odczytujesz port
    2. odwracasz jego stan, dzieki czemu przycisk puszczony to 0, a nacisniety to 1 (jesli przyciski masz podlaczone odwrotnie i maja pull-down'a to ten krok pomijasz)
    3. maskujesz nieistotne bity
    4. poniewaz interesuje cie oczekiwanie gdy przyciski sa puszczone (po odwroceniu 0), to dodatkowo jest negacja logiczna.

    dzieki takim kombinacjom petla zostanie przerwana przez wcisniecie ktoregokolwiek przycisku. niby dwie negacje sie znosza, ale wtedy musialbys nacisnac wszystkie przyciski aby przerwac petle, dlatego sa one konieczne.

    dla dwoch przyciskow jest to zysk niewielki, ale gdy przyciskow bedzie 8, to bedzie juz znaczny [; warto przesledzic jak wygladalby kod ASM dla przypadku z kilkoma odczytami portu - jest to sekwencja kilku identycznych blokow, z ktorych kazdy zakonczony jest warunkowym skokiem - ilosc niepotrzebnego kodu jest naprawde znaczna (procentowo lub przy porownaniu do wersji optymalnej)

    4\/3!!
  • #24 6135144
    Piotr Kania
    Poziom 15  
    czyli skoro (1<<0) to 1, a (1<<1) to 2 to wynik OR daje 3 czyli 0000 0011 jastępnie robimy & z 0000 0000(puszczony) lub 1111 1111(naciśnięty)

    dla puszczonego wynik 0000 0000

    dla naciśniętego wynik 0000 0011


    następnie negacja ! i za bardzo nie wiem co teraz jak zaneguje

    dla puszczonego wynik 1111 1111

    dla naciśniętego wynik 1111 1100

    i bierzemy tylko pierwszy bit ?
  • #25 6136069
    Freddie Chopin
    Specjalista - Mikrokontrolery
    negacja logiczna (!) a odwrocenie bitow (~) to DWIE ODMIENNE SPRAWY!

    warunek jest prawdziwy, jesli wartosc jest rozna od zera. tak wiec prawda jest 1, 12 jak i 5342324. natomiast falsz to tylko i wylacznie 0.

    wynik 0b00000000 to falsz. wynik 0b00000011 to prawda. operacja logicznej negacji sprawi, ze bedzie odwrotnie -> 0 (falsz) zastapione zostanie 1 (prawda), jakakolwiek wartosc rozna od zera (prawda) - zerem (falsz)

    4\/3!!
  • #26 6137224
    Piotr Kania
    Poziom 15  
    czyli while(!(prawda)) => while(fałsz) a to spowoduje pominięcie tej pętli.
    Teraz to czaje moje makro wygląda następująco
    #define WAIT_P1LUBP2() while(!((~PIND)&((1<<0)|(1<<1))));
    #define WAIT_P1_LOW() while(PIND&(1<<0));
    #define WAIT_P1_HI() while(!(PIND&(1<<0)));
    #define WAIT_P2_LOW() while(PIND&(1<<1));
    #define WAIT_P2_HI() while(!(PIND&(1<<1)));

    a oto fragment kodu
    
    WAIT_P1LUBP2();
    if bit_is_clear(PIND,0){a=1;lcd_clr();WAIT_P1_HI();}               //tak
    if bit_is_clear(PIND,1){a=0;lcd_clr();WAIT_P2_HI();sei();}  //nie
    


    załadowałem to do proca i działa
  • #28 6137447
    Piotr Kania
    Poziom 15  
    ok Dziękuje za pomoc sporo się dowiedziałem pozdrawiam
REKLAMA