Skocz do zawartości

Pomocna odpowiedź

Podoba Ci się ten projekt? Zostaw pozytywny komentarz i daj znać autorowi, że zbudował coś fajnego!

Masz uwagi? Napisz kulturalnie co warto zmienić. Doceń pracę autora nad konstrukcją oraz opisem.

Pomysłowa konstrukcja 🙂 Pytanie tylko, czy machanie serwem nie odbywa się zbyt szybko? SHARPy znane są z dość dużych stałych czasowych. Dobierałeś jakoś doświadczalnie prędkość skanowania?

Zgadza się. Z tego powodu ograniczona jest prędkość całego robota. Machanie dobierałem doświadczalnie ( ciekawa zabawa, by dodatkowo połączyć to z odpowiednim zapalaniem i gaszeniem diod by wprowadzić efekt synchronizacji). W chwili obecnej wygląda to tak:

->komenda, by serwo przesunęło się o jedną jednostkę ( ok. 10-11 stopni)

-> odczekaj 20ms

-> zgaś diodę, pod którą wcześniej był czujnik

-> odczekaj kolejne 15ms

-> zapal kolejną diodę

-> sprawdź stan czujnika na nowej pozycji

Nie omieszkam pobawić się jeszcze tymi parametrami, by uzyskać jeszcze lepszą synchronizację.

Ciekawa konstrukcja, gratuluję! 🙂

W kwestii programu, nie przekazuj do delay'ów zmiennych, bo będą one rzutowane na typ zmiennoprzecinkowy i program urośnie ci w kobyłę. Sam popełniłem już ten błąd i program, który powinien zajmować 300B, zajmował 4kB 😋

Druga sprawa - nie twórz funkcji z możliwością zwrotu danych wyjściowych, skoro tego nie wykorzystujesz. Wykorzystaj wówczas typ "void". We wszystkich funkcjach masz argumenty typu "int", a wcale nie wykorzystujesz całej długości tych zmiennych. Np. timer od PWM'a masz 16-bitowy, to do OCRx przekazuj argumenty typu "uint16_t" (przecież i tak nie używasz liczb ujemnych 😉 ).

Dobrym nawykiem jest używanie dyrektyw "#define" zamiast wpisywania wszędzie wartości binarnych/heksadecymalnych. Za jakiś czas po prostu będzie ci się trudno odnaleźć w kodzie, który sam napisałeś. Twój kod można bardzo łatwo zoptymalizować, więc może warto się tym zająć 🙂

Gratuluję konstrukcji, a przede wszystkim tego rysunku ze Sketchupa 🙂

No właśnie, piotreks-89, mnie ubiegł, najpierw przeanalizowałem kod, później przeczytałem komentarze 😉 .

To:

_delay_ms(czas); 
 _delay_ms(z);

Dobrze by było zamienić na:

void czekaj_ms(uint8_t ms)
{
for (uint8_t i=0; i<ms ; i++) _delay_ms(1);
}

i w programie zamiast:

_delay_ms(czas); 
_delay_ms(z);

używać:

czekaj_ms(czas);
czekaj_ms(z);

Za pomocą zmiennych int LEDx zapychasz niepotrzebnie ram, a skoro i tak nie zmieniasz wartości tych zmiennych możesz to zrobić inaczej, omijając zapychanie ramu:

int LED1=0xFE; 
#define LED1 0xFE

Jestem ciekaw ile to by dało oszczędności RAMu i flasha.

Ale oczywiście ilu programistów, tyle rozwiązań 😉

Już nie mówiąc o tym, że cały wielki kawał kodu - poprzez użycie tablicy - zamienia się w kilka prostych operacji:

uint16_t led_bits[] =
   {
       0x0000, 0x0200, 0x0400, 0x0800, 0x1000, 0x0100, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001
   };

void zapal_diode(uint8_t numer_diody)
{
   uint16_t
       mask = (numer_diody < sizeof(led_bits)) ? led_bits[numer_diody] : 0x0000;

   PORTD &= ~(mask >> 8);
   PORTC &= ~mask;
}

Pamiętaj, że programy piszesz dla siebie, nie dla procesora. Inaczej wstukiwałbyś binarne kody instrukcji. Jeżeli diodki są na pewnych bitach portów, w tablicy używaj jedynek na tej pozycji bo to jest dużo bardziej czytelne. Niech procesor sobie to odwróci, szybki jest. Po co odwalasz robotę za niego?

Moja tablica ma słowa 16-bitowe i pobieram maskę od razu dla dwóch portów. Przekazanie argumentu numer_diody=0 powoduje pobranie z indeksu [0] i brak jakiejkolwiek zmiany. Przy zbyt dużym numerku diody ograniczeniem jest porównanie z wielkością tablicy. Wtedy także mask dostaje wartość 0x0000.

Jeżeli chcesz oszczędzić RAM i przechowywać tablicę w pamięci FLASH, przy deklaracji musisz użyć atrybutu PROGMEM a odczyt wykonywać przy pomocy funkcji pgm_read_word().

A ja bym się programu nie czepiał. Najważniejsze że działa, a z czasem można go udoskonalać na wiele sposobów.

Natomiast oszczędzanie pamięci, czy sprytne tablice to nie najlepszy pomysł dla kogoś kto zaczyna. Po pierwsze, to co zaoszczędzimy i tak nie będzie używane... Po drugie łatwo o błąd.

Kod który podał marek1707, zawiera poważny błąd.

sizeof() w języku C zwraca liczbę bajtów zajmowaną przez dany typ lub zmienną. Więc wyrażenie

sizeof(led_bits)

zwróci ile bajtów zajmuje ta tablica. Nie jest to liczba elementów, ale w przypadku typu uint16_t dokładnie dwa razy więcej. Mamy więc przykład programu, w którym nawet ktoś z doświadczeniem może łatwo zrobić błąd.

Przy okazji, kod powinien wyglądać:

    uint16_t 
       mask = (numer_diody < (sizeof(led_bits)/sizeof(led_bits[0])) ? led_bits[numer_diody] : 0x0000; 

Dzięki wszystkim. Nie spodziewałem się aż takiego odzewu.

Niezaprzeczalne, że kod jest do poprawy. Jutro na pewno do tego przysiądę.

Niemniej jednak pierwszorzędną sprawą było dla mnie dostarczenie w pierwszej kolejności działającego kodu, który ( w chwili jego pisania 😃 ) rozumiałem i mogłem łatwo modyfikować. Przypominam, to moje pierwsze połączenie Uc i C.

Za niektóre " błędy " jest mi wstyd już teraz , z niektórych będę się śmiał jutro, a część pewnie będę jeszcze przez długi czas popełniał.

Na tym etapie mikrokontroler jeszcze wiele wybacza, ale macie rację, że to nie powód by robić to byle jak.

Tak czy inaczej nie żałuję, że wstawiłem ten kod. Byłem gotowy na konstruktywną krytykę i jeszcze raz wielkie dzięki za nią.

Jeśli jacyś inni początkujący chcieliby coś zaczerpnąć z takiej konstrukcji to dobrze, by zastali jak najładniejszy kod.

Pozdrawiam

edit: Do czasu poprawy kodu dodałem w pierwszym poście ostrzeżenie o nie-perfekcyjności kodu 🙂

Absolutnie nie traktuj naszych uwag jako czepiania się. Przecież po to jest Forum, by dyskutować. Program, który pierwszego dnia wydaje się fajny, po miesiącu okazuje się żenująco prymitywny nawet dla autora - każdy przez to przechodzi. Dobrze jest wiedzieć, że można go poprawić w wielu miejscach a niektóre konstrukcje nie przyjdą do głowy same - trzeba je zobaczyć. I po to są nasze propozycje. Ja, dzięki czytaniu postów na Forum chyba nauczyłem się BASCOMa "przez dyfuzję", choć (na szczęście) nigdy nie musiałem go używać w praktyce.

Elvis - masz mnie 😥 Na usprawiedliwienie (i auto-pocieszenie) mogę powiedzieć tylko tyle, że nie popełnia błędów ten kto nic nie robi. Pisałem z głowy bardziej zwracając uwagę na bity diodek. Swoją drogą zawsze mnie irytowała ta semantyka sizeof'a choć rozumiem, że autorzy języka musieli wybrać jakiś uniwersalną jednostkę długości niezależną od struktury pamięci komputera ani od wielkości typów podstawowych.

Jestem ciekaw ile to by dało oszczędności RAMu i flasha.

Proszę bardzo, już informuję 🙂

( Zamiast "(uint8_t ms) " użyłem "(uint16_t ms)" ponieważ niektóre delaye są dłuższe.

Stara wersja (info przy kompilacji):


Program:    2362 bytes (28.8% Full)
(.text + .data + .bootloader)

Data:         24 bytes (2.3% Full)
(.data + .bss + .noinit)

Nowa wersja:

Program:    1170 bytes (14.3% Full)
(.text + .data + .bootloader)

Data:          2 bytes (0.2% Full)
(.data + .bss + .noinit)

A zmian przecież tak dużo nie ma 🙂

Wstrzymałem się jeszcze z przebudową funkcji do zapalania diod ( ale faktycznie pomysł Marka1707 jest sprytny 🙂 )

Absolutnie nie traktuj naszych uwag jako czepiania się

Nie jesteśmy w piaskownicy 🙂 Jestem szalenie wdzięczny za wasze uwagi.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...