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

[C][ATMEGA8] - Przekazywanie przez referencję

Noisy_daddy 21 Cze 2013 13:36 1857 21
  • #1 21 Cze 2013 13:36
    Noisy_daddy
    Poziom 14  

    Mam problem z pewną funkcją. Jest to prosta funkcja zmieniająca wartości OCR1A i OCR2. Służy do sterowania prędkością silników. Oto ona:

    Kod: C
    Zaloguj się, aby zobaczyć kod


    Oczywiście w tej formie mogę przekazywać parametry tylko przez wartość. Chciałbym jednak, żeby możliwe było przekazywanie i przez wartość i przez referencję. Wszelkie kombinacje z "&" i "*" skutkują errorem. Jakieś propozycje?

    0 21
  • Arrow Multisolution Day
  • #2 21 Cze 2013 13:55
    2P
    Poziom 19  

    Przekazywanie parametrów przez referencje to funkcjonalność języka C++ a nie C.
    W jakim celu potrzebne Ci w tak prostym kodzie przekazywanie przez referecje? W tym przypadku nie daje to żadnych zysków. Wyjaśnij co chcesz uzyskać łatwiej będzie nam coś doradzić.

    1
  • #3 21 Cze 2013 14:03
    Noisy_daddy
    Poziom 14  

    Program mam zapisany w atmel studio jako c++ executable project (czy jakoś tak) więc c++ powinno być. To jest tylko funkcja o którą chodzi, która nie działa. Cały program steruje dwoma silnikami w samochodzie zdalnie sterowanym. Można regulować prędkość oraz promień skrętu. Sterowanie odbywa się przez pilota. Funkcja, która korzysta z powyższej oraz kodu pilota (co nie ma związku z tematem) wygląda tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Także chodzi o to, że po wyregulowaniu prędkości/promienia ustawiam wartości odpowiednich zmiennych, które chcę do tejże funkcji pwm_phase_correct przekazać. Ale zależy mi żeby wpisanie konkretnych wartości np. pwm_phase_correct(255,255); też coś dawało.

    0
  • Arrow Multisolution Day
  • #4 21 Cze 2013 14:10
    2P
    Poziom 19  

    Ale twoja funkcja może akceptować zarówno wartość zmiennej jak i wartość stałą. Dalej nie widzę żadnego zysku z zastosowania referencji.

    Może się teraz pomylę, bo to tylko domysły, i lecę z pamięci (nie patrząc do noty atmega8) ale sprawdź jedną rzecz:

    W procesorze ATmega8 licznik1 jest licznikiem 16 bitowym. Licznik 2 jest licznikiem 8 bitowym. Czy wziąłeś to pod uwagę przy pisaniu funkcji? Skonfigurowałeś licznik 1 w tryb pracy PWM 8 bit?

    0
  • #5 21 Cze 2013 14:21
    piotrva
    Moderator na urlopie...

    2P napisał:
    Przekazywanie parametrów przez referencje to funkcjonalność języka C++ a nie C.
    W jakim celu potrzebne Ci w tak prostym kodzie przekazywanie przez referecje? W tym przypadku nie daje to żadnych zysków. Wyjaśnij co chcesz uzyskać łatwiej będzie nam coś doradzić.

    O kurcze, nie wiedziałem, że w C nie można przekazać wskaźnika do zmiennej i robiłem tak przez wiele lat...
    A na serio i do Autora tematu:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #6 21 Cze 2013 14:25
    Noisy_daddy
    Poziom 14  

    Cytat:
    Ale twoja funkcja może akceptować zarówno wartość zmiennej jak i wartość stałą. Dalej nie widzę żadnego zysku z zastosowania referencji.

    Jeżeli sugerujesz, że powinno działać, no to niestety ale nie ;) I patrząc na działanie programu to właśnie z tą funkcją jest problem.

    Wszystkie te pwm-owe rzeczy konfigurowałem dokładnie patrząc w datasheet, ale na wszelki wypadek wrzucam część kodu za to odpowiedzialną:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    Wbrew nazwie tamtej funkcji, jednak jest tryb fast pwm

    0
  • #7 21 Cze 2013 14:29
    2P
    Poziom 19  

    piotrva napisał:
    O kurcze, nie wiedziałem, że w C nie można przekazać wskaźnika do zmiennej i robiłem tak przez wiele lat...

    Przekazanie wskaźnika do parametru a przekazanie parametru przez referencję to zupełnie inne rzeczy.

    -------------
    Czy chodzi Ci o to, że chcesz raz wysłać zmienną a później zmiany jej wartości powinny powodować natychmiastową reakcję? Bo zaczyna mi się wydawać, że o to Ci chodzi.

    Jak ja to widzę aktualnie, jak program działa:
    Na przykład, zmieniamy prędkość:
    Wysyłam kod 52530, następnie full naprzód: 3570, następnie jedź naprzód: 34170 i dopiero w tym momencie prędkość się zmienia. Czy też chcesz aby po wydaniu instrukcji 3570 autko natychmiast ruszyło z pełną prędkością w aktualnym kierunku?

    1
  • #8 21 Cze 2013 14:35
    Noisy_daddy
    Poziom 14  

    To teraz jest tak:

    Kod: C
    Zaloguj się, aby zobaczyć kod


    Takie wywołanie:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    Daje taki error: "Invalid conversion from 'int' to 'uint16_t* {aka unsigned int*}' [-fpermissive]"
    A przy samej funkcji: "initializing argument 1 of 'void pwm_phase_correct(uint16_t*, uint16_t*)' [-fpermissive]" i to samo z argument 2
    A takie:
    Kod: C
    Zaloguj się, aby zobaczyć kod


    daje error: "cannot convert 'uint8_t* {aka unsigned char*}' to 'uint16_t* {aka unsigned int*}' for argument '1' to 'void pwm_phase_correct(uint16_t*, uint16_t*)' "

    0
  • #10 21 Cze 2013 14:38
    2P
    Poziom 19  

    Zapomnij przez chwilę o referencjach i odnieś się proszę do tego co napisałem wyżej - zmodyfikowałem swój post zanim napisałeś Twoją wypowiedź. Wciąż wydaje mi się, że coś jest nie tak w założeniach i referencja nic tutaj nie pomoże.

    piotrva napisał:
    Jeśli skupimy się na szczegółach to owszem, ale zasada działania jest bardzo podobna, stąd skrót myślowy.

    Niestety wciąż zimno. Jeśli chodzi o techniczne działanie referencji, na poziomie assemblera to zupełnie coś innego. Referenacja wykorzysta po prostu ten sam rejestr na daną zmienną. Wskaźnik wymaga aby zmienna była umieszczona w pamięci programu i odnosi się do określonej komórki pamięci, wskazywanej przez wskaźnik.

    0
  • #12 21 Cze 2013 14:44
    Noisy_daddy
    Poziom 14  

    Cytat:
    Czy chodzi Ci o to, że chcesz raz wysłać zmienną a później zmiany jej wartości powinny powodować natychmiastową reakcję? Bo zaczyna mi się wydawać, że o to Ci chodzi.

    Nie.
    Cytat:
    Wysyłam kod 52530, następnie full naprzód: 3570, następnie jedź naprzód: 34170 i dopiero w tym momencie prędkość się zmienia. Czy też chcesz aby po wydaniu instrukcji 3570 autko natychmiast ruszyło z pełną prędkością w aktualnym kierunku?

    Dokładnie tak działa. Po wysłaniu 3570 zmienia się zmienna odpowiadająca za prędkość i jest przechowywana w pamięci. Dopiero po wysłaniu jednego z kodów odpowiadającego za kierunek się coś dzieje np. właśnie naprzód- 34170- ze zdefiniowaną wcześniej prędkością

    0
  • #14 21 Cze 2013 14:50
    Noisy_daddy
    Poziom 14  

    Cytat:
    Pierwszy przypadek to to, że przez wskaźniki (czy też referencje w C++) nie możesz przekazać stałej.
    Drugi przepadek to to, że musi się zgadzać typ wskaźnika.

    To da się w ogóle tak zrobić, żebym mógł przekazywać i stałą i zmienną? Zmienne które przekazuję są typu (zmieniłem) uint8_t i wskaźniki też są takie. Mógłbym prosić o jakąś dokładniejszą wskazówkę? Gdybym miał kiedykolwiek zrozumieć wskaźniki to naprawdę stałoby się to już kilka lat temu ;)

    0
  • #15 21 Cze 2013 14:53
    2P
    Poziom 19  

    Da się tak zrobić - wszystko będzie działać i sama funkcja działa prawidłowo. Będę się upierał, że problem leży gdzie indziej a programuję już w C ładnych naście lat. Przyjrzyj się dokładnie jak działają zmienne automatyczne - one są niszczone za każdym razem gdy funkcja się kończy. Są tylko dwa sposoby aby zachować ich stan pomiędzy wywołaniami funkcji:

    1. Zdefiniować je jako zmienne globalne.
    2. Nadać im atrybut "static".

    0
  • #16 21 Cze 2013 14:57
    Noisy_daddy
    Poziom 14  

    Cytat:
    Wszystkie zmienne, które mają zachować swoją wartośc między wywołaniami funkcji zmień na typ static

    Nic się nie zmieniło ;/

    Dodano po 2 [minuty]:

    Cytat:
    Będę się upierał, że problem leży gdzie indziej

    Tzn gdzie może leżeć?

    0
  • #17 21 Cze 2013 15:06
    2P
    Poziom 19  

    Zrozum - w tym przypadku zastosowanie referencji nie ma żadnego sensu. Referencje stosuje się głównie w przypadku gdy chcemy aby funkcja zwróciła nam jakąś wartość do argumentu. Znaczy - wysyłamy do niej coś w argumencie i dostajemy inną wartość spowrotem, którą jakoś wykorzystujemy w funkcji głównej.

    Stosować można je także w celach optymalizacji kodu, ale to już sprawa bardzo zależna od konkretnej maszyny i zwykle niewarta zachodu - tam gdzie taka optymalizacja jest dla nas ważna zwykle i tak użyjemy assemblera.

    Jakie masz możliwości debugowania tego kodu. W jaki sposób sprawdziłeś, że odpowiednie funkcje są wywoływane? Spróbuj chociaż mrugnąć diodą we wnętrzu funkcji ustawiania prędkości. Idealnie byłoby jakbyś mial debugger jtag. Można sobie też poradzić wypisując w odpowidnich miejscach kodu informację przez port RS.

    Drobiazg jaki udało mi się jeszcze zauważyć przyglądając się na kod: w ostatnich case'ach brakuje Ci break'ów.

    0
  • #18 21 Cze 2013 15:17
    Noisy_daddy
    Poziom 14  

    Hmm no to spróbuję bez referencji. Możliwości debugowania czysto diodowe ;p tzn mam płytkę drukowaną z odbiornikiem ir, mostkiem itp i silniki, ale brak jtaga, wejścia rs na płytce, oscyloskopu. Ale coś popróbuję porzeźbić.
    Hmm zaraz zaraz jednak ta funkcja musi działać tylko, że czasami tak a czasami nie. Bo do przodu i do tyłu jedzie, z tymi zmianami musi być coś nie tak

    0
  • Pomocny post
    #19 21 Cze 2013 15:30
    2P
    Poziom 19  

    Jeszcze jedno:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Nie zadziała tak jak się chyba powinno. Funkcja się skończy i nowy kod nie zostanie wykorzystany. Jeśli rzeczywiście chcesz aby to działało, spróbuj takiej konstrukcji:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #20 21 Cze 2013 17:27
    Noisy_daddy
    Poziom 14  

    W sumie nie wiem za bardzo czym się różni mój program w tym momencie od tego co było wcześniej, ale wygląda na to, że działa!! Z tym whilem to akurat średnio bo jak puszczę to silniki bez końca się kręcą ;p Jeszcze tylko muszę zrobić tą regulację żeby była możliwa w czasie pracy silników, bo na razie to muszę zatrzymać, żeby działało

    Dodano po 1 [godziny] 26 [minuty]:

    Teraz tak wygląda ta funkcja:

    Kod: C
    Zaloguj się, aby zobaczyć kod

    I problem tak jak napisałem polega na tym, że jak nacisnę jeden z klawiszy odpowiadający za zmianę prędkości podczas gdy silniki pracują, nic się nie dzieję. Muszę zatrzymać, zmienić i puścić jeszcze raz. A wydaje mi się, że teraz powinno być dobrze. W każdym casie odnoszącym się do kodu zmieniającego wartość prędkości/promienia skrętu dopisałem to:

    Kod: C
    Zaloguj się, aby zobaczyć kod

    Więc moim zdaniem powinno działać tak, że jedzie sobie np do przodu wtedy lastdir ma wartość 34170. Zmieniam wartość prędkości więc wchodzi w jednego z tych casów, zmienia wartość odpowiedniej zmiennej, wchodzi do tego if'a i ustawia kod na 34170. W następnej pętli o ile nic nie nacisnęliśmy (a zapewne nie nacisnęliśmy bo trzebaby to zrobić b. szybko) już wejdzie w case'a odpowiadającego za jechanie do przodu i uruchomi pwm_phase_correct ze zmienionymi wartościami. Czy gdzieś w tym rozumowaniu popełniam błąd?
    Na wszelki wypadek załączam funkcję odpowiadająca za dekodowanie:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    Bo skoro nie działa to może tu ta wartość się jakoś zmienia i tego nie zauważyłem...

    0
  • Pomocny post
    #21 21 Cze 2013 18:22
    2P
    Poziom 19  

    W twoim rozumowaniu jest jeden błąd. Warunek case jest testowany w miejscu pojawienia się instrukcji switch. Późniejsza zmiana testowanej zmiennej nie ma wpływu na przebieg programu.

    Może źle zrozumiałeś tą proponowaną przeze mnie pętlę. Zauważ dwie ważne rzeczy:
    1. Na końcu tego while jest break. To znaczy, że gdy skończy się testowanie warunku case i skończy się ono przez break, to funkcja zostanie zakończona.
    2. Tylko jeśli chcesz ponownie testować warunek, kończysz case przez continue. Mamy więc:
    a/. Koniec przez break - kończymy analizę.
    b/. Koniec przez continue - sprawdź ponownie warunek.

    0
  • #22 21 Cze 2013 18:48
    Noisy_daddy
    Poziom 14  

    Trochę inaczej zrobiłem, ale wszystko już działa!! Z tym whilem i breakiem dobry pomysł. Dzięki wielkie za pomoc!! Zamykam

    0