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

[C][AT90CAN128]Obsługa przerwania i zliczenie czasu

kasprzak 20 Maj 2011 22:01 2419 25
REKLAMA
  • #1 9528083
    kasprzak
    Poziom 10  
    Witam,
    Zabieram się do oprogramowania czujnika ultradźwiękowego SRF04 podpiętego do avr'ka AT90CAN128. Czujnik dokładnie taki: http://www.robot-electronics.co.uk/htm/srf04tech.htm

    Muszę zwrócić wartość w centymetrach od przeszkody. Zatem potrzebne będzie wg mnie użycie zewnętrznego przerwania i użycie timera.

    Koncepcję mam na razie taką, że pulsuję w pętli co 12uS pin nadający. Na drugi pin przychodzi echo (stan 1) z odpowiednio długim czasem w zależności od odległości i wraca do zera. Czyli muszę napisać obsługę przerwania tak aby w przypadku wykrycia stanu 1 na pinie echo włączyć timer (albo wywoływać timer już po wywołaniu funkcji pulsującej?) i gdy przerwanie wykryje stan niski zatrzyma timer zwracając aktualną jego wartość. Potem jedynie obróbka w postaci odpowiednich obliczeń, żeby dostać drogę w cm.

    Jaką Wy obralibyście metodę w takim przypadku. Wszelkie inne spostrzeżenia również mile widziane.
  • REKLAMA
  • Pomocny post
    #2 9528257
    GSM
    Poziom 25  
    Witam,

    drobna uwaga, sugerowałbym użycie któregoś z pinów ICP (Input Capture Trigger).
    Precyzyjniejszy pomiar, parę bajtów mniej kodu no i jest bardziej eleganckie.
    To kiedy uruchomisz timer to już od ciebie zależy, ja bym go uruchomił bezpośrednio przed wysłaniem serii impulsów do modułu. Obliczenia oczywiście banalne znając prędkość dźwięku, pokusiłbym się jedynie o kalibrację całości już uruchomionej aby uzyskać maksymalnie dokładne wyniki.

    Pozdrawiam,
    GSM
  • #3 9528303
    kasprzak
    Poziom 10  
    Właśnie z tymi pinami jest problem, bo na płytce prototypowej DVK90CAN1 mam głównie PORTF wolny (gniazdo J20 ANA CON), a nie mogę pin headów dolutować do niej :(

    Szukałem różnych sampli i już na starcie coś nie śmiga,
    bo dałem prosty warunek, że jeżeli na porcie przyjdzie jakiekolwiek echo, to ma zapalić diodę, a dioda ni cholery nie zapala się. Z przerwaniami też mi coś nie idzie.



    Kod: text
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #4 9528502
    GSM
    Poziom 25  
    Wykluczyłeś problemy sprzętowe? (niedziałający moduł, etc...)

    Pozdrawiam,
    GSM
  • #5 9528512
    kasprzak
    Poziom 10  
    Sprzęt jest ok. Wczoraj był badany na oscyloskopie pod tą płytką, ładnie zmienia się czas odpowiedzi echa. Słychać jak pyka sobie pulsy. Błąd był w linii z TIMSK0 (skoro używam TIMERA1)
    Tylko problem jest bo nie odświeża. Obecnie coś tam zwraca (bo wysyłam zmienną time po RS232), ale dopiero po naciśnięciu resetu. Nie przeliczyłem jeszcze na jednostki [cm], ale to na tym poziomie nie jest ważne. Jak zmieniam odległość i reset to zwraca jakąś wartość time. np. 184 i cały czas wysyła 184, nacisnę reset i przybliżę przeszkodę 052, ale nie zmienia się dopóki nie nacisnę ponownie resetu. Tak jakby jeszcze te przerwania nie funkcjonowały dobrze :(

    Kurcze siedzę cały wieczór i pewnie noc posiedzę, a na razie pod górkę :(

    Wygląda to teraz tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #6 9528552
    GSM
    Poziom 25  
    Przestaje działać po jednym pomiarze ponieważ brakuje sei(); na końcu obsługi przerwania :wink:
    Poza tym, czemu wysyłasz UARTem wartość pomiaru od razu po wywołaniu pulse()? Wartość zmiennej 'time' może jeszcze nie być ustalona, bezpieczniej po tym 20ms delayu wysyłać.

    Pozdrawiam,
    GSM
  • #7 9528557
    dondu
    Moderator na urlopie...
    GSM napisał:
    Przestaje działać po jednym pomiarze ponieważ brakuje sei(); na końcu obsługi przerwania

    To chyba jednak nieprawidłowa sugestia.
    Inną sprawą jest że cli() na początku przerwania jest niepotrzebne.

    No chyba, że się mylę.
  • REKLAMA
  • Pomocny post
    #8 9528564
    GSM
    Poziom 25  
    dondu napisał:
    GSM napisał:
    Przestaje działać po jednym pomiarze ponieważ brakuje sei(); na końcu obsługi przerwania

    To chyba jednak nieprawidłowa sugestia.
    Inną sprawą jest że cli() na początku przerwania jest niepotrzebne.

    No chyba, że się mylę.


    Czemu tak uważasz? :roll:
    W obsłudze przerwania, na samym początku blokowane są wszystkie przerwania i nigdzie już nie są odblokowywane, więc po jednym jego wystąpieniu nie ma prawa wystąpić już żadne inne... Należy wstawić sei(); na końcu procedury przerwania i tyle.

    Pozdrawiam,
    GSM
  • Pomocny post
    #9 9528574
    dondu
    Moderator na urlopie...
    Dlatego, że domyślnie ustawione jest dodawanie prologu i epilogu, które te sprawy załatwiają. Gdyby przerwanie było w trybie ISR_NAKED wtedy jak najbardziej miałbyś rację. Ale tutaj procedura obsługi ma standardową wersję.

    http://www.nongnu.org/avr-libc/user-manual/gr...rupts.html#ga8b4c7e44627db0a60d676213add42d64

    Ale mogę się mylić :)
  • REKLAMA
  • #10 9528584
    kasprzak
    Poziom 10  
    ehh, oczywiście, że zapomniałem uruchomić przerwania, ale niewiele to pomogło. Wywaliłem cli() i zostawiłem samo sei() w mainie.

    Teraz jak wrzuciłem za delay'a to wyrzuca same 000. Pewnie wysłane wartości sprzed były tak jak pisaleś GSM, przed ustaleniem wartości.
  • Pomocny post
    #11 9528587
    GSM
    Poziom 25  
    dondu napisał:
    Dlatego, że domyślnie ustawione jest dodawanie prologu i epilogu, które te sprawy załatwiają. Gdyby przerwanie było w trybie ISR_NAKED wtedy jak najbardziej miałbyś rację. Ale tutaj procedura obsługi ma standardową wersję.

    http://www.nongnu.org/avr-libc/user-manual/gr...rupts.html#ga8b4c7e44627db0a60d676213add42d64

    Ale mogę się mylić :)


    Hmm, w sumie racja, późnawo się robi i ciężko mi się myśli i błędy popełniam, ale napisałem o tym ponieważ kojarzyłem, że raz miałem taki przypadek. Może po prostu coś mi się ubzdurało :roll:

    Pozdrawiam,
    GSM
  • #13 9528599
    GSM
    Poziom 25  
    Moment... coś mi tu nie pasuje, może znowu bredzę.. ale...
    ICP1 w tym mikrokontrolerze jest na pinie PD4, a ja w kodzie kolegi widzę, że coś tu przy porcie F jest majstrowane, skoro słychać, że moduł działa wnioskuje, iż faktycznie pod F jest on podpięty, więc nie ma możliwości aby wystąpiło przerwanie ICP1...

    Pozdrawiam,
    GSM
  • #14 9528606
    kasprzak
    Poziom 10  
    Wydaje mi się, że to ciągle problem z mierzeniem czasu. Tzn. nie wykrywa któregoś ze zbocz i różnica nie jest liczona, jednak nie potrafię tego znaleźć. Dodałem też wyświetlanie na diodach, które są na płycie i też się nic nie dzieje.
    Obecnie kod wygląda tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #16 9528615
    GSM
    Poziom 25  
    Poza tym, to co opisujesz w komentarzach do kodu jest niespójne ze stanem faktycznym:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    PF0 jest ustawiony w tym przypadku jako wyjście a PF1 jako wejście.

    Pozdrawiam,
    GSM
  • #17 9528617
    kasprzak
    Poziom 10  
    GSM napisał:
    Poza tym, to co opisujesz w komentarzach do kodu jest niespójne ze stanem faktycznym:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    PF0 jest ustawiony w tym przypadku jako wyjście a PF1 jako wejście.

    Pozdrawiam,
    GSM

    Niedopatrzenie z mojej strony. Błędny komentarz. Zamieniłem piny. Wklejam poprawny kod.


    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #18 9528627
    GSM
    Poziom 25  
    Kolego kasprzak, ustosunkuj się proszę porządnie do:
    Link
    oraz
    Link

    Bo ja wciąż nie wyobrażam sobie jak mogłoby to działać jeśli moduł nie jest podpięty do pinu ICP1 (PD4) tylko gdzieś indziej (w tym wypadku wejście ADC).

    Pozdrawiam,
    GSM
  • #19 9528630
    kasprzak
    Poziom 10  
    Faktycznie sam chyba kuku sobie zrobiłem, bo nie wpiąłem pod dobre piny. Myślałem, że obsłużę PORTF, bo nie musiałbym dolutowywać pin head'ów do płyty eval. Czyli trzeba wyciągnąć piny z portu D. Tak to jest jak się walczy przez parę godzin i robi inne rzeczy dookoła :) Dziękuję za cierpliwość nad moimi postami i odpowiedz na nie.

    Pliki ze schematami itd:
    PDF AT90CAN128:
    http://www.atmel.com/dyn/resources/prod_documents/doc7679.pdf

    PDF od płyty eval na której jest procek:
    http://www.atmel.com/dyn/resources/prod_documents/doc4381.pdf

    Zmontowany obecnie układ:
    [C][AT90CAN128]Obsługa przerwania i zliczenie czasu

    Dodano po 25 [minuty]:

    Działa :!: :!:. Teraz powalczę, żeby mi zrobił średnią z pomiarów i wysyłał co sekundę i sprawdzę czy jest dobrze.

    Podpiąłem pod PD4 echo, a triggera zostawiłem pod portem F.
  • #20 9533575
    kasprzak
    Poziom 10  
    Jest jeszcze problem z kalibracją, bo dzielę czas falling-rising / 58 (zgodnie z opisem w pdfie wyżej) i wynik powinien być w cm, a nie jest. Zwraca wtedy 0. Jak nie dzielę to wywala wartości takie jak poniżej

    Tutaj akurat się udało, że 122mm i wygląda jakby tyle było, ale niestety nie jest to poprawne. Na pewno ta metoda przedstawiona wyżej w kodzie jest ok?

    [C][AT90CAN128]Obsługa przerwania i zliczenie czasu
  • #21 9534661
    GSM
    Poziom 25  
    Martwi mnie jedna sprawa, mianowicie, jeśli pierwsze przerwanie ICP nastąpi przed przepełnieniem licznika a drugie po, to wynik odejmowania będzie nieprawidłowy :roll:
    Więc powinieneś się przed tym zabezpieczyć if'em albo po prostu resetować licznik przed każdym pomiarem.

    A co do twojego ostatniego posta.
    Skąd wartość 58? Dzieląc czas w taktach procesora (bo w takiej jednostce otrzymujemy pomiar z licznika) przez 58 nie dostaniemy poprawnej odpowiedzi, moim zdaniem powinieneś dzielić przez 484, wtedy otrzymasz wynik pomiaru w centymetrach (od przedmiotu do modułu).

    Pozdrawiam,
    GSM
  • #22 9534754
    kasprzak
    Poziom 10  
    GSM napisał:
    Martwi mnie jedna sprawa, mianowicie, jeśli pierwsze przerwanie ICP nastąpi przed przepełnieniem licznika a drugie po, to wynik odejmowania będzie nieprawidłowy :roll:
    Więc powinieneś się przed tym zabezpieczyć if'em albo po prostu resetować licznik przed każdym pomiarem.

    A co do twojego ostatniego posta.
    Skąd wartość 58? Dzieląc czas w taktach procesora (bo w takiej jednostce otrzymujemy pomiar z licznika) przez 58 nie dostaniemy poprawnej odpowiedzi, moim zdaniem powinieneś dzielić przez 484, wtedy otrzymasz wynik pomiaru w centymetrach (od przedmiotu do modułu).

    Pozdrawiam,
    GSM

    Czytałem dokumentację i sugerowałem się tym :
    Cytat:
    Calculating the Distance
    The SRF04 provides an echo pulse proportional to distance. If the width of the pulse is measured in uS, then dividing by 58 will give you the distance in cm, or dividing by 148 will give the distance in inches. uS/58=cm or uS/148=inches.


    Odległość jest mierzona już ok, tzn. na 8-bitach, czyli jak mam na PORT A diody od 0-8, to jak zamieniam na decymalną wartość to pokazuje dobrze w cm.
    Niestety wyświetlana (w ASCII) po RS232 nie. Pewnie chodzi o poprawny typ zmiennej. Jutro spróbuję to zmienić.
  • REKLAMA
  • #23 9534769
    GSM
    Poziom 25  
    Cytat:
    Calculating the Distance
    The SRF04 provides an echo pulse proportional to distance. If the width of the pulse is measured in uS, then dividing by 58 will give you the distance in cm, or dividing by 148 will give the distance in inches. uS/58=cm or uS/148=inches.


    No właśnie, a ty mierzysz w 0,125uS - takt zegara 1/8000000 sekundy (uS to 1/1000000 sekundy), więc musisz wziąć to pod uwagę

    Pozdrawiam,
    GSM
  • #24 9534797
    kasprzak
    Poziom 10  
    GSM napisał:
    Cytat:
    Calculating the Distance
    The SRF04 provides an echo pulse proportional to distance. If the width of the pulse is measured in uS, then dividing by 58 will give you the distance in cm, or dividing by 148 will give the distance in inches. uS/58=cm or uS/148=inches.


    No właśnie, a ty mierzysz w 0,125uS - tak zegara 1/8000000 sekundy (uS to 1/1000000 sekundy), więc musisz wziąć to pod uwagę

    Pozdrawiam,
    GSM


    ehhh, faktycznie :|
    Najgorzej jak się nie zwraca na takie rzeczy szczegółów, a okazują się tak banalne. Pewnie mój następny problem leży również u podnóża banałów.

    Problem mam z wysyłaniem tej zmiennej, bo funkcja wysyłająca po uarcie wygląda tak:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    czyli musi dostać char'a.
    Przed wysłaniem zmienna jest typu uint8.

    Zamieniam (tylko nie jest to w ASCII zapewne, dlatego przesyła błędnie jak wyświetlam w docklighcie w zakładce ASCII) stosując:
    Kod: text
    Zaloguj się, aby zobaczyć kod
  • #25 9534809
    GSM
    Poziom 25  
    Trzeci parametr funkcji itoa() to nie długość bufora
    (o to żeby go nie przepełnić musisz zadbać sam alokując odpowiednio duży bufor, zakładając, że zmienna 'distance' jest typu uint8 to potrzebujesz 4 bajtów bufora, bo największa wartość to 255 więc 3 znaki + \0),
    tylko podstawa systemu liczbowego do jakiego ma zostać przekonwertowana liczba, więc powinno tam być 10 (bo interesuje cię przecież dziesiętny :wink:).

    Pozdrawiam,
    GSM
  • #26 9534817
    kasprzak
    Poziom 10  
    Kolejna niedoczytana rzecz :/
    Ile się człowiek nauczył przez taki wątek.
    Dzięki raz jeszcze za pomoc. Szkoda, że więcej niż 3x "Pomógł" dać nie mogę :)
REKLAMA