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

Programowanie w C - Właściwe pisanie programów

30 Lip 2015 10:19 1308 10
  • Poziom 7  
    Witam szanowne forum.
    Borykając się z trudnym początkiem, jeśli chodzi o programowanie mikrokontrolerów w C, postanowiłem założyć niniejszy temat. Myślę, że przyda się nie tylko mnie, ale i innym osobom stawiającym pierwsze kroki w tym temacie.
    Jak zawsze na początku, jest wiele pytań wymagających wyjaśnienia.Oczywiścię w internecie jest wiele pomocnych artykułów, ale są one nie zawsze napisane w sposób łatwy do zrozumienia dla nas laików.
    Ponadto korzystanie z metody "copy and past" czyjegoś fragmentu kodu i uciecha z tego, że zadziałało (ale dlaczego zadziałało, to już nie wiem), chyba nie jest właściwą drogą do osiągnięcia czegokolwiek. Jeśli ktoś ma podobne problemy, to proponuję podpiąć się pod temat.

    Prosiłbym o wyjaśnienie, jak prawidłowo podejść do pisania programu na samym początku.Zastanawiam się, czy ma to znaczenie.
    Zamieszczam kawałek nic nie znaczącego kodu, a żeby łatwiej mi było wyjaśnić, o co mi chodzi.Przepraszam za ten kod, ale myślę, że doświadczeni koledzy mi wybaczą.Chodzi tylko o przekaz.

    Kod: c
    Zaloguj się, aby zobaczyć kod



    Jak czytałem, program zaczyna się wykonywać jakby od góry.
    Są definicje preprocesora,inicjalizacja np. wyświetlacza,przerwań, modułu ADC itd...To wszystko wykonuje się tylko raz przy starcie programu.
    Następnie istnieją sekcje typu void cos_tam(void) i następnie uruchamia się pętla główna, jeśli taka istnieje. Według mojego myślę błędnego myślenia po pętli jest koniec programu. Pętla nieskończona wykonuje, co ma wykonywać.
    To, czego nie rozumiem, to fakt, że często po pętli są kolejne sekcje programu, które np, mówią o starcie konwersji modułu adc(zacznij pomiar,odczekaj itd...). Jeśli wcześniej w pętli jest wysyłany wynik pomiaru do wyświetlacza, a dopiero po pętli rozkaz rozpoczęcia pomiaru, to co ma wyświetlić lcd ?.
    Czy zapis np. void cos_tam(void) mogę zapisać w sekcji int main(void), ale przed pętlą, czy mogę za pisać pod pętlą i czy ma to wogóle znaczenie. Pytam dlatego, ponieważ mamy nieraz dwa, trzy projekty, które trzeba ze sobą powiązać i tak na prawde nie wiem do końca, co gdzie "wcisnąć", a żeby było dobrze.

    Pytania może durne, ale myślę, że nie tylko ja mam podobny dylemat.
    Proszę o jakieś wyjaśnienia w sposób, jak dla "opornych" :D .

    Z góry dziękuję i pozdrawiam.szegerege1
  • Moderator Mikrokontrolery Projektowanie
    szegerege1 napisał:
    Następnie istnieją sekcje typu void cos_tam(void)

    To nie sekcje tylko funkcje realizujące konkretny fragment programu i wywoływane z innego miejsca programu.

    szegerege1 napisał:
    Czy zapis np. void cos_tam(void) mogę zapisać w sekcji int main(void), ale przed pętlą, czy mogę za pisać pod pętlą i czy ma to wogóle znaczenie. Pytam dlatego, ponieważ mamy nieraz dwa, trzy projekty, które trzeba ze sobą powiązać i tak na prawde nie wiem do końca, co gdzie "wcisnąć", a żeby było dobrze.

    funkcja main() to także funkcja a definiowanie funkcji w innej funkcji jest niewskazane choć możliwe.

    Tutaj znajdziesz kurs C z przykładami w kompilatorze CManiak online - możesz je przerabiać i ćwiczyć do woli online:
    http://mikrokontrolery.blogspot.com/2011/02/kurs-jezyka-c-spis-tresci.html

    Sumiennie przejdź przez każdy artykuł w tym kursie i nauczysz się niezbędnych podstaw - zajmie Ci to co najwyżej kilka dni.


    szegerege1 napisał:
    ... następnie uruchamia się pętla główna, jeśli taka istnieje. Według mojego myślę błędnego myślenia po pętli jest koniec programu. Pętla nieskończona wykonuje, co ma wykonywać.

    Pętla taka (nieskończona) musi być w 99,9% przypadków. Program mikrokontrolera nie pracuje w systemie operacyjnym dlatego nie może się skończyć. Jeśli nie będzie nieskończonej pętli głównej, to w zależności od kompilatora dodany zostanie jakiś dodatkowy kod, np. w avr z kompilatorem gcc będzie to pętla nieskończona z zablokowanymi przerwaniami co skutkować będzie pozornym zawieszeniem się mikrokontrolera.


    szegerege1 napisał:
    To, czego nie rozumiem, to fakt, że często po pętli są kolejne sekcje programu, które np, mówią o starcie konwersji modułu adc(zacznij pomiar,odczekaj itd...). Jeśli wcześniej w pętli jest wysyłany wynik pomiaru do wyświetlacza, a dopiero po pętli rozkaz rozpoczęcia pomiaru, to co ma wyświetlić lcd ?.

    Wszystko zależy jak realizujesz program:
    - można tak że po rozpoczęciu pomiaru czeka w pętli do jego zakończenia i dopiero wyświetla wynik, ale to blokuje wykonywanie programu przez mikrokontroler na czas pomiaru,
    - można tak, że po rozpoczęciu pomiaru nie czeka w pętli na jego zakończenie a realizuje dalej pętlę główną, w której między innymi jest if() sprawdzający czy pomiar się zakończył i wtedy wyświetlający wynik - taki sposób nie blokuje wykonywania programu,
    - można wreszcie użyć przerwań ADC (generowane po zakończeniu pomiaru) i wyświetlić wynik gdy takie przerwanie wystąpi.



    szegerege1 napisał:
    Jak zawsze na początku, jest wiele pytań wymagających wyjaśnienia.Oczywiścię w internecie jest wiele pomocnych artykułów, ale są one nie zawsze napisane w sposób łatwy do zrozumienia dla nas laików.

    Najpierw trzeba poznać język C, a dopiero później brać się za mikrokontroler.
    Tutaj masz bardzo dokładnie opisane algorytmy (każda linijka programu) w tym także przypadki dot. ADC: http://mikrokontrolery.blogspot.com/2011/04/atmel-studio-spis-tresci.html

    ... ale najpierw Kurs C. :)

    Edit:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    w pętli głównej nie powinno się znajdować ... zapewne domyślasz się dlaczego.
  • Specjalista - Mikrokontrolery
    Sporo jeszcze musisz się nauczyć. W języku C wykonanie programu polega na wywołaniu jedynie funkcji main(). Ta funkcja może wywoływać inne funkcje, które "same z siebie" nie są w żaden sposób wykonywane "po kolei".

    Funkcja powinna być zadeklarowana powyżej miejsca, w którym jest wywoływana. Niektórzy wolą pisać funkcje poniżej main(), ale wtedy przed main() należy umieścić ich prototypy (czyli deklaracje bez definicji).

    Pętli głównej w przyzwoitych projektach nie ma wcale (np. na ARM lub MSP430) albo jest ona pusta i zawiera jedynie instrukcję uśpienia procesora (np. w AVR). ;)
  • Moderator Mikrokontrolery Projektowanie
    BlueDraco napisał:
    Pętli głównej w przyzwoitych projektach nie ma wcale (np. na ARM lub MSP430) albo jest ona pusta i zawiery jedynie instrukcję uśpienia procesora (np. w AVR). ;)

    Zapomniałem o tym wspomnieć, a to bardzo istotny element, ponieważ w przypadku mikrokontrolerów bardzo często dążymy do maksymalnego wykorzystania przerwań, więc pętla główna często jest pusta, ale są wyjątki (opisał BlueDraco wyżej).

    Tak napisany program z reguły najbardziej optymalnie wykorzystuje zasoby mikrokontrolera i wbrew pozorom często łatwiej go napisać niż program realizowany w całości w pętli głównej. Tutaj niestety należy jednak sporo doświadczenia mieć, by przy dużych programach wszystkie równolegle dziejące się procesy poprawnie realizować i by sobie wzajemnie nie przeszkadzały.
  • Poziom 7  
    Witam i dziękuję szanownym kolegom za odpowiedź.
    Wszelkie informacje są cenne i w mniejszym lub większym stopniu przyczyniają się do lepszego zrozumienia tematu.Oczywiście nauka i jeszcze raz nauka C. Bez tego ani rusz. Dziękuję za linki. Oczywiście jest praca zawodowa, dom itd..., ale nie jestem wyjątkiem. Jak zawsze w zimie jest trochę więcej czasu, a więc zobaczymy.
    Jeśli chodzi o lcd_init();, to myślę, że głupotą byłoby inicjować wyświetlacz miliony razy na sekundę w pętli, kiedy właściwie jest zrobić to raz na początku startu programu. Potem to już tylko same komendy do obsługi, wysyłania, kasowania, odświeżania lcd... w pętli.Podobnie zezwolenie na przerwania , inicjacja adc itp...
    Czy mój tok rozumowania jest prawidłowy ? i czy są jeszcze inne powody ?.
    Dziękuje im pozdrawiam.
  • Moderator Mikrokontrolery Projektowanie
    Prawidłowy :)

    Ale jak to w życiu bywa czasami są wyjątki - np. projekty zasilane z baterii mogą wyłączać zasilanie LCD stąd po wybudzeniu ze snu oszczędzającego baterię trzeba go ponownie zainicjować.

    Dlatego w tej dziedzinie nie ma jednej jedynie słusznej drogi, bo zawsze to samo zadanie można zrealizować na 1000 sposobów ...

    ... a do zimy daleko i sądzę, że nie wytrzymasz i wcześniej się nauczysz :)
    Powodzenia!
  • Poziom 7  
    Witam przemek_bundy.
    Dziękuję za link i chęć pomocy. Poradniki Pana Mirka znam bardzo dobrze.
    Jestem w posiadaniu Jego książki BB, jak równierz zestawu uruchomieniowego ATB.
    Robi On naprawdę wielką robotę i za to Go podziwiam.Ktoś by powiedział " masz już wszystko, co ci potrzebne i powinieneś sobie poradzić ". Tak, to prawda, ale czasami temat wygląda trochę inaczej, niż w książce, czy poradniku. Ponadto nie raz ktoś inny wyłoży ten sam temat w inny sposób. Ponadto różne osoby chwytają w różny sposób, szybciej lub wolniej, itd...
    Rozumiem, że to po prostu brak podstaw C, jak podpowiadali koledzy w poprzednich postach i trzeba się uczyć. Tak też i robię, ale jednocześnie staram się coś uruchomić pomimo braku wiedzy, nie raz trochę po omacku i są efekty.Wiem, że to trochę złe podejście, ale jak każdy początkujący " chciało by się już.....".
    Sądzę, że zdecydowana większość tak zaczyna zabawę z mikrokontrolerami.Mówię o osobach, które tak naprawdę nigdy nie będą prawdziwymi, zaawansowanymi programistami, a są chobbystami elektronikami i chcą się czegoś nauczyć dla własnych skromnych potrzeb.
    W końcu, kto stoi w miejscu, to podobno się cofa :D .Ale dosyć tych wywodów.
    Oglądam poradniki,czytam i wetuję tematy na c maniaku. Bardzo wiele się rozjasnia i faktycznie bez podstaw daleko nie zajedzie nawet chobbysta elektronik.

    Przy okazji chciałem zadać pytanie odnośnie pewnego problemu z zapisem i odczytem RAM, EEPROM i wiceversa. Jeśli trzeba założyć osobny temat, to proszę moderatora o info.

    Utworzyłem dwie tablice: jedna w pamięci ram, a druga w pamięci eeprom. Jest jeden przycisk. Na wyświetlaczu górna linijka, to napis w ram, a dolna linijka to jakiś tam napis w eeprom zawarty w kodzie programu.
    po włączeniu zestawu ładują się oba napisy z obu pamięci do lcd,jak wynika z kodu programu.
    Następnie po naciśnięciu przycisku tekst z górnej linijki ( ram ) zostaje wyświetlony równierz w dolnej linijce ( zawartość eeprom ).Nastąpiło prawidłowe zapisanie do eeprom.Teraz próbuję w drógą stronę, tzn zmieniam napis w tablicy eeprom na inny,zmieniam:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    tzn, aktywuję instrukcję eem_to_ram(); (robię tak, ponieważ oprogramowałem jeden przycisk) i deaktywuję poprzednią.Następnie kompilacja, wgranie do procka i po uruchomieniu zestawu i przyciśnięciu guzika zawartość z linijki dolnej EEPROM nie chcę się przekopiować do górnej linijki RAM. W drógą stronę bez problemu. Czego tu brakuje i co robię źle. Czy wogóle podejście do tej kwestii jest prawidłowe.Kod skleciłem sam, oczywiście w oparciu o inne przykłady.
    Bardzo proszę o pomoc i wyłożenie tematu. Inaczej dużo czasu zejdzie, a jeszcze jest tyle do poznania i przetestowania :D .Z góry dziękuję.

    Oto programik:


    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Poziom 7  
    Dziękuję szczywronek za odpowiedź na mojego posta.
    Aktualnie jestem zajęty ( praca przy domu ), ale jak tylko będę przy komputerze, to pokombinuję.Odezwę się.
    Miłego łikentu.

    Dodano po 4 [godziny] 47 [minuty]:

    Witam ponownie.
    Zapis i odczyt działa w obu kierunkach. Bardzo dziękuję za pomoc. Kiedy tak patrzyłem na wcześniejsze moje zapiski, to na "moją" logikę wydawało się prawidłowo, a tu niestety nie.Ciekawe to C :D .

    Temat zapisu i odczytu tablic uwazam za zamknięty.

    Poniżej poprawny kod. Pewnie się przyda takim, jak ja.


    Kod: c
    Zaloguj się, aby zobaczyć kod