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

[ATmega][C] Sterowanie serwem + buzzer

modrzej1988 28 Maj 2011 10:04 6098 25
  • #1 9551976
    modrzej1988
    Poziom 13  
    Mam mały projekt do zrobienia, którego głównym celem jest po naciśnięciu przycisku uruchomić sekwencję sterującą serwomechanizmem, a na koniec włączyć buzzer. Wygooglowałem tutoriala z gotowym już kodem, który zacząłem dostosowywać do moich wymogów, lecz napotkałem małe przeszkody. Może na początek kod, który już mam:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    A teraz w czym mam problemy:
    1. Po wciśnięciu przycisku sekwencja ładnie się uruchamia, lecz ogólne założenie jest takie, że ten przycisk będzie cały czas wciśnięty co powoduje, że sekwencja się zapętla. Jak zatrzymać wykonywanie się tej pętli po jednokrotnym wykonaniu? Próbowałem ze zwykłym break; ale bezskutecznie.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    2. Chciałem po wykonaniu się całej tej sekwencji włączyć buzzer (w ogólnym zamyśle ma on sygnalizować położenie modelu w wysokiej trawie). Są jednak z tym problemy. W obecnej postaci kodu, w momencie zasilenia całego układu buzzer już zaczyna "piszczeć", a kiedy zakończy sekwencję i wchodzi na linię włączającą buzzer piszczy głośniej. Jest tak, jak by jakieś napięcie już wcześniej lekko wysterowywało buzzerek. Buzzer powinien być sterowany jedynką logiczną na porcie mikrokontrolera.
    Tutaj jest cały schemat układu EvB (nie mogę wyciąć samej konfiguracji buzzera - nie mam pojęcia dlaczego).
    [ATmega][C] Sterowanie serwem + buzzer

    3. Czy to normalne, że po wciśnięciu przycisku, cała sekwencja uruchamia się z lekkim opóźnieniem, takim ok. 0.5s ?

    4. Jeżeli _delay_ms(1000) to opóźnienie 1s to dlaczego _delay_ms(15000) nie trwa już 15 s. tylko coś ok. 7? Taktowanie 16MHz.


    I takie pytanie pozakonkursowe. Do obsługi tego ustrojstwa ma być menu wyświetlane na LCD + klawiatura. Do obsługi wyświetlacza chcę zastosować bibliotekę ze strony http://radzio.dxp.pl/hd44780/hd44780_avr_4-bit_norw_c.htm
    Rozumiem, że wystarczy ją wrzucić do folderu z projektem, dopisać w załącznikach plik headerowy i żeby np. wyświetlić coś na wyświetlaczu, w programie użyć funkcji
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    gdzie w parametrze będzie podana zmienna typu char z wpisanym tekstem ?


    Na chwilę obecną więcej pytań nie mam.
  • #2 9552038
    polprzewodnikowy
    Poziom 26  
    Cytat:
    W obecnej postaci kodu, w momencie zasilenia całego układu buzzer już zaczyna "piszczeć", a kiedy zakończy sekwencję i wchodzi na linię włączającą buzzer piszczy głośniej.


    Tak wygląda twoja pętla główna.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    W pętli głównej bez przerwy zmieniasz stan pinu PC7, więc dlatego ci piszczy. Gdy wchodzisz w obsługę sekwencji może się zdarzyć że stan pinu PC7 będzie wysoki, buzzer znowu piszczy.
  • #3 9552060
    modrzej1988
    Poziom 13  
    A fakt wystarczyło przenieść tą linijkę w pętlę if... ale ciemna masa ze mnie :P

    EDIT:

    Wrzucenie do pętli if nieskończonej obsługi portu buzzera załatwiło problem z cały czas wciśniętym przyciskiem ;) Nie wiem czy to dobre rozwiązanie, ale łopatologicznie banalne... Buzzer piszczy przerywając aż do resetu programu i nie pozwala przejść do ponownego sprawdzenia stanu przycisku.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Została więc jeszcze kwestia długości opóźnień i opóźnionego startu sekwencji. Obsługę wyświetlacza już mniej więcej ogarnąłem. Inicjacja przechodzi, czyszczenie również, przechodzenie do drugiej linii po współrzędnych śmiga, ale za chiny ludowe nie mogę rozkminić jak wyświetlić wartość jakiejś przykładowej zmiennej?
  • #4 9552383
    dondu
    Moderator na urlopie...
    modrzej1988 napisał:
    4. Jeżeli _delay_ms(1000) to opóźnienie 1s to dlaczego _delay_ms(15000) nie trwa już 15 s. tylko coś ok. 7? Taktowanie 16MHz.

    To niemożliwe, ponieważ makro _delay_ms() działa poprawnie do 65535 sekund.
    Problem musi leżeć gdzieś indziej.
  • #5 9552409
    modrzej1988
    Poziom 13  
    Zrobiłem małą kosmetykę w kodzie

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Problem z opóźnieniem załatwiłem tworząc funkcję, którą wywołuje się n-razy w zależności od potrzeb. Teraz opóźnienia działają jak trzeba.

    Problem teraz z zmianą wartości zmiennej "zero". W ogólnym zamyśle wszystkie wartości ustawień kątów serwa mają być ustawiane z klawiatury (do tego właśnie będzie menu). Jednak nie wiem w czym tkwi problem. Zanim przeniosłem wszystko do osobnych funkcji, zmienna "zero" była możliwa do zmiany przy użyciu przycisku. Teraz kiedy wszystko jest w funkcjach w ogóle się ta zmienna nie zmienia. Swoją drogą to później te ustawienia będą musiały być jeszcze zapisywane w pamięci EEPROM, żeby po resecie układu nie przepadły w niepamięć.

    EDIT:

    Poprawiłem kod, w funkcji Serwo() zabrakło parametru wejściowego, ale nadal są problemy ze zmianą ustawienia kąta. W sensie, że po uruchomieniu programu mogę zmieniać wychylenia serwa (co najciekawsze tylko na plus, nie wiem jakim cudem zero-- nadal inkrementuje mi tą zmienną). Po uruchomienu sekwencji serwa, przechodzi ono na "minus" ale na ponowne "zero" już nie wraca, tak jak by w ogóle nie pobierało wartości ze zmiennej.
  • #6 9552651
    GSM
    Poziom 25  
    Witam,

    dondu napisał:
    modrzej1988 napisał:
    4. Jeżeli _delay_ms(1000) to opóźnienie 1s to dlaczego _delay_ms(15000) nie trwa już 15 s. tylko coś ok. 7? Taktowanie 16MHz.

    To niemożliwe, ponieważ makro _delay_ms() działa poprawnie do 65535 sekund.
    Problem musi leżeć gdzieś indziej.


    Cytat:

    The maximal possible delay is 262.14 ms / F_CPU in MHz.

    When the user request delay which exceed the maximum possible one,
    _delay_ms() provides a decreased resolution functionality. In this
    mode _delay_ms() will work with a resolution of 1/10 ms, providing
    delays up to 6.5535 seconds (independent from CPU frequency). The
    user will not be informed about decreased resolution.


    :wink:

    Pozdrawiam,
    GSM
  • #8 9552764
    modrzej1988
    Poziom 13  
    Nie ma co już się tak roztrząsać nad tymi opóźnieniami... Sprawa już rozwiązana.
    Wyświetlanie zmiennych na wyświetlaczu również. Tylko kompiluje mi się z dwoma warningami:
    ../serwo.c: In function 'main':
    ../serwo.c:81: warning: implicit declaration of function 'itoa'
    ../serwo.c:82: warning: pointer targets in passing argument 1 of 'LCD_WriteText'

    Ale program działa. Co najciekawsze, od momentu kiedy dodałem wyświetlanie zmiennych działała obsługa klawiszy i zmiana wartości zmiennej zero. Jednak po przeniesieniu wszystkiego w zgrabne funkcje, znów przestało :/ Nie wiem... źle chyba przekazuję zmienne między funkcjami, a wskaźniki nigdy nie były moją mocną stroną.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    EDIT:
    Zrobiłem wszystkie funkcje bezargumentowe i wszystko działa. Ale rodzi się kolejne pytanie. Jak sprawić, żeby wyświetlacz mi nie migał z racji tego, że jest w głównej pętli?
  • #9 9552797
    drzasiek
    Specjalista CNC
    Mówisz o wskaźnikach a ich nie zastosowałeś. Jeśli chcesz do funkcji dać argument który ma być przez tą funkcję zmieniany to robisz przykładowo tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #10 9552803
    modrzej1988
    Poziom 13  
    Wiem, że ich nie używałem, ponieważ zawsze mam z tym problemy. Ale już poradziłem sobie bez nich.
    Problem z migającym wyświetlaczem też już rozwiązany... po prostu niepotrzebnie inicjowałem go przy każdej pętli.
  • #11 9553288
    GSM
    Poziom 25  
    modrzej1988 napisał:

    Tylko kompiluje mi się z dwoma warningami:
    ../serwo.c: In function 'main':
    ../serwo.c:81: warning: implicit declaration of function 'itoa'
    ../serwo.c:82: warning: pointer targets in passing argument 1 of 'LCD_WriteText'


    Czasem odnoszę wrażenie, że naukę programowania należałoby rozpocząć od nauki czytania (ze zrozumieniem!).
    Kompilatory C/C++ są dość wylewne jeśli chodzi o rodzaj błędu i w większości przypadków bardzo jasno opisują co jest nie tak.
    Nawiasem mówiąc kolega "zjadł" resztę drugiego warninga, domniemuję, że było tam "differ in signedness"...

    W świetle tych faktów i tego co powiedziałem, proszę kolegę modrzej1988, ażeby przeczytałem raz jeszcze te 2 warningi i powiedział czym są spowodowane.
    Inaczej uznam to za kompletny brak podstawowej wiedzy (regulamin 3.1.17) oraz nie zapoznanie się z innymi podobnymi wątkami na forum (regulamin 3.1.16) - tak się składa, że 4 dni temu identyczny problemem został rozwiązany...

    Pozdrawiam,
    GSM
  • #12 9554043
    modrzej1988
    Poziom 13  
    GSM napisał:

    Inaczej uznam to za kompletny brak podstawowej wiedzy (regulamin 3.1.17) oraz nie zapoznanie się z innymi podobnymi wątkami na forum (regulamin 3.1.16


    Wszyscy są ludźmi i nie wszystko wiedzą, ale to raczej nie powód, żeby od razu stwierdzać o kompletnym braku wiedzy? Nie wszystkich uczyli C na studiach...

    Poza tym problemy warmingów rozwiązane.

    Aż się boję, ale znów zapytam. Jak powinien wyglądać zapis do EEPROM? Prześledziłem i kombinowałem z wszystkim co znalazłem w sieci, lecz nic z tego nie działało:/ obecnie kod wygląda tak:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #13 9554876
    GSM
    Poziom 25  
    modrzej1988 napisał:

    Wszyscy są ludźmi i nie wszystko wiedzą, ale to raczej nie powód, żeby od razu stwierdzać o kompletnym braku wiedzy? Nie wszystkich uczyli C na studiach...


    Studia nie mają nic do tego, szczególnie gdy ktoś się sam za coś zabiera - należy to robić porządnie :wink:

    modrzej1988 napisał:

    Prześledziłem i kombinowałem z wszystkim co znalazłem w sieci, lecz nic z tego nie działało:/ obecnie kod wygląda tak:


    Życie uczy, że informacje napotkane w "sieci" często bywają mało wiarygodne i nierzadko dezinformujące.
    Dla ciebie świętą "księgą" powinna być teraz dokumentacja mikrokontrolera którego używasz.
    W datasheet'cie jest dokładnie opisana procedura zapisu do EEPROM, a nawet jeśli mnie pamięć nie myli są fragmenty kodu w assemblerze i C :roll:
    AVR-GCC ma nawet biblioteki do obsługi eeprom'u (które jak widzę chcesz wykorzystać i to nawet poprawnie), patrz jaka wygoda - wołasz funkcję i gotowe :wink:
  • #15 9567908
    modrzej1988
    Poziom 13  
    Ok. Mam już w zasadzie działający program, wszystko jest tak jak chciałem.
    Jest tylko jeden mankament z którym nie mogę sobie poradzić. Nie ma co opisywać, lepiej to pokażę:





    A tutaj jest kawałek kodu za to odpowiedzialny:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wszelka pomoc w rozwiązaniu problemu mile widziana :) Aha... wyświetlacz jest sterowany przy użyciu bibliotek Radzia.
  • #17 9568223
    modrzej1988
    Poziom 13  
    Fakt, wystarczy. A myślałem, że coś jest nie tak z kodem dlatego takie świństwa się robią.
  • #18 9568253
    GSM
    Poziom 25  
    Świństwa? Bynajmniej, to tylko znowu twoja nieuwaga...
    Jakbyś napisał coś na tablicy szkolnej a potem na niej (w tym samym miejscu) napisał coś nowego nie ścierając poprzednich zapisków to myślisz, że te stare by same magicznie zniknęły?...
    Z wyświetlaczem LCD jest tak samo, sam się automagicznie nie czyści.

    Pozdrawiam,
    GSM
  • #19 9575283
    modrzej1988
    Poziom 13  
    Takie pytanie mi się urodziło... czy da się w jakiś sposób zmienić piny wyjścia dla timera (OC1A, OC1B)?
  • Pomocny post
    #20 9575431
    mirekk36
    Poziom 42  
    modrzej1988 napisał:
    Takie pytanie mi się urodziło... czy da się w jakiś sposób zmienić piny wyjścia dla timera (OC1A, OC1B)?


    Oczywiście................., że się nie da.

    Chyba, że sobie zrobisz programowy PWM to wtedy możesz mieć nie dość, że więcej kanałów to jeszcze na tych pinach, na których ci się żywnie spodoba.
  • #21 9575488
    modrzej1988
    Poziom 13  
    Też prawda... dzięki za odpowiedź ;)
  • #22 9683417
    modrzej1988
    Poziom 13  
    Mój projekt jest już w zasadzie na wykończeniu (w tej wersji która powstała, ale urodziła już się inna). Jest jednak mały problem z którym nie mogę sobie poradzić. Mianowicie przy pierwszym programowaniu "czystego" kontrolera (takiego prosto ze sklepu) jestem zmuszony programować go na dwa razy. Pierwszy przy użyciu wsadu bez włączonej funkcji odczytu z EEPROM-u (żeby przy pierwszym uruchomieniu nie było krzaków), po zaprogramowaniu muszę wybrać opcję zapisu do EEPROM-u, żeby zapisać domyślne "zerowe" ustawienia i po tej czynności muszę znów programować układ wsadem z włączoną już funkcją odczytu z EEPROM-u i dopiero teraz układ jest w pełni funkcjonalny.
    Moje pytanie brzmi. Jak napisać program tak, żeby przy pierwszym i tylko pierwszym uruchomieniu do EEPROM-u automatycznie były zapisywane zerowe ustawienia, a przy następnych uruchomieniach działał tylko odczyt?
    Chciałem wykombinować coś z licznikiem uruchomień, ale tutaj też powstaje martwy punkt...
    Będę wdzięczny za jakieś wskazówki :)
  • #23 9683599
    dondu
    Moderator na urlopie...
    1. Opisałeś ale jednak nie bardzo rozumie na czym polega ten problem. Programować można Flash i EEPROM jednocześnie (w jednym cyklu programowania). Chyba że mówisz o EEPROM zewnętrznym. Coś mi tu nie pasuje.

    2. Jaki program do programowania?
  • #24 9683828
    modrzej1988
    Poziom 13  
    Wiem, że można programować EEPROM, ale nigdzie nie znalazłem odpowiedzi, jak stworzyć wsad do EEPROM-u... dlatego chciałem to zorganizować programowo na kontrolerze, żeby przy pierwszym odpaleniu programu na procesorze do EEPROM-u zapisało domyślne wartości. A później przy kolejnych uruchomieniach procesora nie było już tego zapisu przy uruchomieniu tylko odczyt. Ale coś czuję w kościach, że się tak nie da...
    To może jakaś wskazówka jak stworzyć wsad do EEPROM-u i będzie po kłopocie :)
  • Pomocny post
    #25 9683980
    mirekk36
    Poziom 42  
    modrzej1988 napisał:
    ... dlatego chciałem to zorganizować programowo na kontrolerze, żeby przy pierwszym odpaleniu programu na procesorze do EEPROM-u zapisało domyślne wartości. A później przy kolejnych uruchomieniach procesora nie było już tego zapisu przy uruchomieniu tylko odczyt. Ale coś czuję w kościach, że się tak nie da...


    Jak to się nie da? .... ależ da się i powiem więcej - to jest JEDYNIE SŁUSZNA metoda zamiast właśnie przygotowywać oddzielny wsad do eeproma w mikrokontrolerze. To bywa w ogóle bez sensu często.

    Pomyśl sobie, zrobiłeś urządzenie, wysłałeś je komuś na drugi koniec polski i przypadkowo klient tak sobie poprzestawiał ustawienia zapisane w eepromie (albo się przypadkowo zawartość eeproma zepsuła) i co ???? KLOPS !

    urządzenie musi wrócić do stwórcy, żeby znowu z mozołem wgrał jakiś tam (sorki za określenie) durny wsad do EEPROM'a ????

    po co ???? gdy można dać klientowi możliwość albo programową albo sprzętową (jakiś klawisz wciśnięty przy resecie) żeby przywrócić ustawienia domyślne (fabryczne)..... Nie spotkałeś się z czymś takim np w różnych routerach czy podobnych urządzeniach elektronicznych ????? .... tak to się porządnie robi, i na AVRkach też się da .... ja tak robię zawsze.
  • #26 9686927
    modrzej1988
    Poziom 13  
    No fakt... kurde... najprostsze rozwiązanie jak zwykle okazało się najtrudniejsze... kombinatorstwo jednak czasami niepopłaca...
    Dzięki za podpowiedź... zaraz będzie poprawka w oprogramowaniu :)

    Mam jeszcze pytanie kontrolne... 1 komórka pamięci EEPROM = 1 bajtowi tak?
    Jeżeli tak, to żeby zapisać uint_16 potrzebne mi są 2 komórki... Dobrze prawię?
REKLAMA