Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[Atmega8][C] Odbieranie sygnału IR wewnątrz przerwania ICP

14 Maj 2019 22:47 459 18

  • Poziom 18  
    Podłączyłem pod PORTB.0 (ICP) odbiornik podczerwieni TSOP31236 i próbuję rozkodować sygnał:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Problem jest taki, że układ zachowuje się tak, jakby na PINB.0 był cały czas 1. W capturedIR ląduje cały czas 0xFFF8. Ma ktoś pomysł, dlaczego? Kod jest prosty jak budowa cepa
  • Poziom 39  
    Ten kod nie ma prawa działać poprawnie z wielu powodów. Jeszcze raz przemyśl całą koncepcję i zacznij od nowa.

  • Poziom 18  
    To żeś pomógł :D. Dlaczego nie ma prawa działać? Podaj przynajmniej jeden, abym zrozumiał błędność koncepcji
  • Poziom 39  
    - ponieważ ignorujesz ostrzeżenia kompilatora
    - ponieważ nie rozumiesz po co są i jak działają przerwania oraz flagi
    - ponieważ zablokowałeś całe przerwanie jakąś pętlą z delayem
    - ponieważ sprawdzanie co 1780us czy pin jest w stanie niskim czy wysokim obierające za punkt synchronizacji jakieś przypadkowe zbocze na ICP nie ma nic wspólnego z dekodowaniem sygnału IR

  • Poziom 18  
    1. Nie mam żadnych warningów
    2. ??? Nie jest to bynajmniej moje pierwsze przerwanie, ani tym bardziej flaga. Po czym wnosisz, że nie wiem jak działają?
    3. Owszem, zablokowałem całe przerwanie odpowiadające za ICP w momencie, gdy zaczął się sygnał. Zamierzone działanie, co w nim złego?
    4. ??? "Podłączyłem pod PORTB.0 (ICP) odbiornik podczerwieni TSOP31236" - nie przypadkowe zbocze, a odbiór pierwszego sygnału z odbiornika IR (bit START). Kolejne bity odbieram co 1780us, bo tyle trwa czas bitu (zobacz protokół RC-5). Kolejne zbocza są olewane, bo - jak słusznie zauważyłeś - przerwanie jest zablokowane i dopiero jak się skończy można proces zacząć od początku

    W momencie, gdy pojawi się sygnał na ICP (szczerze mówiąc traktuję go jako zwykłego INT-a, bo ICR-a nie potrzebuję) wchodzi w przerwanie i teraz odbiór sygnału RC-5 jest absolutnie priorytetowy, więc wszystko blokuję (może nawet i dałbym cli() aby globalnie wyłączyć przerwania, a sei() po zakończeniu przerwania ICP, aby nie tracić taktów na np. OVERFLOW zliczający czas rzeczywisty - jest wysoce priorytetowy, ale nie aż tak). Synchronizacja zaczęła się od bitu START. Fakt, że zamiast robić ifa !IR::capturingIR do blokowania dekodowania sygnału, gdy proces już się rozpoczął mógłbym wewnątrz przerwania wyłączyć go po prostu via TIMSK &= ~(1<<TICIE1); a po zakończeniu odbioru z powrotem go włączyć, jednak to kwestia optymalizacji. Następnie kolejne 13 bitów sczytuję co 2x 889us, wartość zapisuję i odblokowuję przerwanie aż do następnego początku pakietu, gdzie cała zabawa się zaczyna od początku
  • Specjalista - Mikrokontrolery
    mikmas napisał:
    W momencie, gdy pojawi się sygnał na ICP (szczerze mówiąc traktuję go jako zwykłego INT-a, bo ICR-a nie potrzebuję) wchodzi w przerwanie i teraz odbiór sygnału RC-5 jest absolutnie priorytetowy, więc wszystko blokuję (może nawet i dałbym cli() aby globalnie wyłączyć przerwania, a sei() po zakończeniu przerwania ICP, aby nie tracić taktów na np. OVERFLOW zliczający czas rzeczywisty - jest wysoce priorytetowy, ale nie aż tak).

    Więc jednak nie do końca rozumiesz, jak działają przerwania na AVR - po przyjęciu przerwania wszystkie przerwania pozostają zablokowane aż do zakończenia obsługi, chyba że jawnie je odblokujesz. Wiec to co napisałeś za bardzo nie ma sensu.
    Pomijajac więc samą ideę pętli w przerwaniu (nie chcę mi się dyskutować o tym, dlaczego to jest złe podejście) to widzę takie problemy z realizacją Twojej idei:
    - Dokładność liczenia opóźnień funkcją delay może nie być wystarczająca.
    - Nigdzie nie upewniasz się, że odebrane zbocze jest faktycznie początkiem bitu start a nie środkiem transmisji (tzn. że od poprzedniego zbocza minęło wystarczająco dużo czasu).
    - Jeżeli chcesz faktycznie robić uproszczony odbiór a'la UART, to powinieneś próbkować sygnał w środku okresu ważności, czyli idealnie po 444,5 us od pierwszego zbocza, bo na wyjściu TSOP występują przesunięcia fazy w zależności od siły sygnału itp. Twoje 5us jest zdecydowanie nie wystarczające, poza tym nie uwzględniasz czasu wejścia w obsługę przerwania.
    - Nie pokazałeś gdzie ustawiasz flagę IR::capturingIR, ale nie wydaje się ona mieć żadnego sensu.
    - Nie pokazałeś jak czytasz wynik odbioru, więc trudno ocenić, czy prawidłowo.
  • Poziom 21  
    To co piszą Koledzy Twoim kodzie to sensowne konkrety. Podzielam ich zdanie na temat potrzeby zmiany koncepcji obsługi przerwania.
    Do Twojego przykładu idealnie pasują główne założenia "programowania przerwań" a szczególnie ta, że powinno być możliwie krótkie czasowo.
    Wg mnie, po obejrzeniu kodu, tkwisz mocno głęboko w programowaniu całkowicie liniowym - stąd te kłujące w oczy delay'e.
    Dawno temu mając podobne zadanie do Twojego napisałem to co poniżej.
    Obsługa ramek SIRC. Oczywiście to żadne super programowanie, ale zgodne z powyższą zasadą czyli wchodzisz do przerwania "zostawiasz ślad" i wychodzisz.

    Kod się wydaje długi i skomplikowany, ale czasowo daje radę, choć na pewno nie jest optymalny.

    mikmas napisał:

    RC-5 jest absolutnie priorytetowy, więc wszystko blokuję (może nawet i dałbym cli() aby globalnie wyłączyć przerwania, a sei()

    Czy to aż tak ważne? Przecież czasy między zboczami dla takiego mikrokontrolera i RC-5 są całkiem duże, a sam protokół ma tez spore możliwe odchyłki".
    Co do używania w przerwaniu cli() i sli() to nie powinieneś tego robić ot tak. Powinieneś ewentualnie zrzucać rejestr SREG, żeby nie nadpisywać innych flag przerwań, bo takowe mogą się w momencie obsługi również zmieniać

    Kod: c
    Zaloguj się, aby zobaczyć kod

  • Poziom 18  
    Cytat:
    - Nigdzie nie upewniasz się, że odebrane zbocze jest faktycznie początkiem bitu start a nie środkiem transmisji (tzn. że od poprzedniego zbocza minęło wystarczająco dużo czasu).

    Czasy pomiędzy ponownymi strzałami z pilota to kilka ms ARAIR. Jakbym mógł się więc wstrzelić w środek transmisji?
    Cytat:
    - Jeżeli chcesz faktycznie robić uproszczony odbiór a'la UART, to powinieneś próbkować sygnał w środku okresu ważności, czyli idealnie po 444,5 us od pierwszego zbocza, bo na wyjściu TSOP występują przesunięcia fazy w zależności od siły sygnału itp. Twoje 5us jest zdecydowanie nie wystarczające, poza tym nie uwzględniasz czasu wejścia w obsługę przerwania.

    Właśnie uwzględniając czas wejścia etc. ustaliłem, że 5us będzie OK. Mogę zwiększyć. Na środek nie chcę wypływać, bo wykonywanie pętli też swoje trwa, a więc ostateczny delay może być większy. Jak już to ustawię się mniej więcej w 1/4 długości
    Cytat:
    - Nie pokazałeś gdzie ustawiasz flagę IR::capturingIR, ale nie wydaje się ona mieć żadnego sensu.

    Jeżeli przerwanie nie może się wykonać podczas wykonywania przerwania to faktycznie nie ma ona sensu. Nadmiarowa, jednak nie wpływająca na działanie. Kiedyś miałem taki efekt, że układ się zachował tak jakby (!) przed końcem OVERFLOW wszedł w siebie samego ponownie. Stąd od tamtej pory zakładałem, że jest to możliwe. Jak nie - nawet lepiej.
    Cytat:
    - Nie pokazałeś jak czytasz wynik odbioru, więc trudno ocenić, czy prawidłowo.

    W pętli while programu głównego sprawdza, czy wartość capturedIR się zmieniła. Jeżeli tak - wyrzuca ją na LCD

    @simw
    Wcześniej robiłem to na krótko trwających przerwaniach (ten kod jest wyjątkiem, jeżeli chodzi o budowę i jest wynikiem wielu prób. W końcu postanowiłem zrobić go tak, aby był możliwie najmniej skomplikowany).
  • Specjalista - Mikrokontrolery
    A jesteś pewien, że Twój pilot wysyła RC5?

  • Poziom 18  
    W sumie pewności nie mam. W pilotach IR jestem nowy i myślałem, że wiodącym protokołem jest RC-5?
  • Specjalista - Mikrokontrolery
    Ja też się nie czuję specjalistą od pilotów, ale moim zdaniem RC5 to mniejszość, głównie urządzenia Philipsa. Przy czym Wikipedia twierdzi, że w nowych urządzeniach Philips przeszedł na RC6.
    Domyślam się, że analizatora/oscyloskopu nie masz?
    Gdybyś mierzył odległość zboczy, to można by było coś wnioskować...
    Jaki to pilot?

  • Poziom 18  
    Mam taki oscyloskop kieszonkowy pożyczony, ale średnio umiem się nim obsługiwać. Dokładnego przebiegu nie widzę, ale przypomina trochę protokół od NEC (dłuższy impuls startowy, później krótka przerwa i takie jakby bity od addr,~addr,cmd i ~cmd, jednak tu już oscyloskop jasno nie wskazuje. Dość krótki przebieg jak na te 4B. Pilot jest od telewizora Manta. Modelu pilota brak

  • Poziom 18  
    simw napisał:
    Zrób sobie detektor kodów. Użyj dobrej biblioteki:
    https://www.mikrocontroller.net/articles/IRMP_-_english
    Implementacja jest bardzo prosta. Od czasu gdy zacząłem stosować to już się nie bawię wpisanie tego od podstaw.

    Brzmi fajnie, tylko boję się czy nie spuchnie mi kod. Aktualnie mam 75% zapełnienia pamięci flash (wiadomości tekstowe i tak już są przerzucone do wew. eeproma także nie za bardzo jest z czego odchudzać), a jeszcze trochę kodu przede mną jest.

    Ogólnie ta funkcjonalność odpowiada za "nagranie" kodu przycisku i w odpowiednich momentach ma strzelić na diodę IR. Myślałem, czy by wykorzystując właśnie ICP+ICR nagrać kolejne długości 0 i 1 (zapisuję je w zewnętrznym eepromie), jednak wygenerowałoby to za dużo danych (praktycznie 1b to 2B danych - długość stanu wysokiego+długość stanu niskiego). Zaletą niewątpliwie byłaby niezależność od użytego protokołu. Ta biblioteka by sądzę rozwiązała problem nadmiaru danych (przechowywałbym wtedy info o protokole+adres+komenda czyli nie więcej jak 3B per przycisk, co jest w pełni akceptowalne), ale później mogę mieć problem z dopchnięciem kolanem kolejnych funkcjonalności

    @dondu
    zakładając, że to RC-5, a powoli zaczynam szczerze wątpić
  • Poziom 21  
    mikmas napisał:
    simw napisał:
    Zrób sobie detektor kodów. Użyj dobrej biblioteki:
    https://www.mikrocontroller.net/articles/IRMP_-_english
    Implementacja jest bardzo prosta. Od czasu gdy zacząłem stosować to już się nie bawię wpisanie tego od podstaw.

    Brzmi fajnie, tylko boję się czy nie spuchnie mi kod. Aktualnie mam 75% zapełnienia pamięci flash (wiadomości tekstowe i tak już są przerzucone do wew. eeproma także nie za bardzo jest z czego odchudzać), a jeszcze trochę kodu przede mną jest.

    No tak kod trochę weźmie. Z drugiej strony to Atmege 8 można łatwo wymienić na Atmega328 czy 168. Może to dobra pora ( 75%), żeby pomyśleć o zmianie.
    Warto rozważyć czy czas poświęcony na optymalizację i upychanie kodu nie zwróci się pomimo konieczności migracji. Oba procki są bardzo podobne jeśli chodzi o obsługę.

  • Poziom 18  
    Nadal mi się <<dziwne>> rzeczy dzieją. Diodę odbiorczą mam TSOP31236 czyli 36kHz, natomiast częstotliwość używana w pilotach NEC to 38kHz. Może mieć to wpływ na przekłamanie odbioru?
  • Poziom 21  
    mikmas napisał:
    Nadal mi się <<dziwne>> rzeczy dzieją. Diodę odbiorczą mam TSOP31236 czyli 36kHz, natomiast częstotliwość używana w pilotach NEC to 38kHz. Może mieć to wpływ na przekłamanie odbioru?

    Wg mnie nie.
    Jeden odbiornik np 36KHz powinien poprawnie działać z sygnałami 38 czy 40 KHz.
    Sam używam zwykle 38 KHz i to działa poprawnie z różnymi częstotliwościami nośnej.
    A jak u Ciebie z filtrowaniem. Masz zgodnie z notą odbiornika?
    Chyba najwyższa pora żebyś pokazał co zrobiłeś. Schemat, płytka zdjęcia itp. W przeciwnym razie szkoda czasu na wróżenie z fusów...

    Ewentualnie zobacz sobie tutaj:
    http://zealota74.blogspot.com/2017/10/uniwersalny-odbiornik-podczerwieni-do.html

    Różne procki, różne technologie a wszystko działa jak należy.

  • Poziom 18  
    OK, już coś stabilnie wyświetla. Modyfikowałem w przerwaniu do liczenia czasu rzeczywistego TCNT1, aby czas wyliczać, stąd miałem później błędny ICR1.Napisałem poniższy kod:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    dla testów. Stabilnie wyświetla te same wartości dla tych samych przycisków, ALE same kody są dość... dziwne. Mianowicie na wyświetlaczu pokazuje mi się 0 A0 5F 1A, gdzie pierwsze 3B są zawsze takie same, a zmienia się czwarty. Wg protokołu pierwszy to adres (wartość stała), negacja bitów adresu, komenda (tu powinno być zmienne) i jej negacja (to jedynie się zmienia)