Skocz do zawartości

Arduino Leonardo - wielowatkowosc


Pomocna odpowiedź

Napisano

Witam !

chciałbym się dowiedzieć czy jest jakaś biblioteka realizująca wielowątkowość w arduino?

Sprawdziłem kilka bibliotek np Timers.h, ale ona po prostu sprawia ze funkcje wywołują się co jakiś określony czas ale nie wykonują się w tym samym czasie.

Przykład:

Funkcja A() ma w sobie pętle nieskończona, a funkcja B() robi coś innego, jeżeli ustawie to tak:

timer.attach(0, 100, A);

timer.attach(1, 500, B);

to cały czas będzie się wykonywała funkcja A(), a B() nigdy się nie wywołała, a chciałbym tak żeby w tle wykonywała się funkcja B().

Jak to zrobić ?

Masz tylko jeden procesor, więc tak naprawdę w danej chwili może być wykonywany tylko jeden ciąg instrukcji. Jak rozumiem chodzi o system w którym tylko wydaje się, że wiele rzeczy dzieje się na raz, czy tak?

Cóż, AVR to bardzo mały procesor, ale można sobie z wieloma jednoczesnymi zadaniami poradzić. Jeżeli piszesz swoje programy np. na PC, to możesz być w lekkim szoku, bo tutaj jednak nie stosuje się (raczej) systemów z wywłaszczaniem. Tzn. zrobienie systemu operacyjnego w którym możesz sobie dowolnie odpalać nowe wątki a każdy z nich może czuć się swobodnie we wnętrzu maszyny jest bardzo kosztowne, jeśli nie niemożliwe. Dlatego zacznij od tego:

https://learn.adafruit.com/multi-tasking-the-arduino-part-1/overview

To jest prosty przykład jak - zmieniając trochę swoje podejście do tworzenia kodu Arduino - można zrobić quasi-równoległość. Generalnie dużo bardziej opłaca się tutaj (z punktu widzenia marnowanych zasobów typu RAM, moc obliczeniowa) współpraca, czyli takie pisanie kodu, by zużywał on tylko tyle procesora ile jest absolutnie konieczne. Gdy tylko trzeba na coś poczekać, oddajesz sterowanie do schedulera, np. takiego jak ten:

https://www.arduino.cc/en/Reference/Scheduler

Możesz też zrobić własne, krótkie funkcje które będą panowały nad poszczególnymi zadaniami w systemie i wywoływać je w przerwaniu: cyklicznie jedna po drugiej lub wszystkie na raz w jednym. Jeżeli zapewnisz, że np. każda z nich nie będzie dłuższa niż np. 1ms (jak się tak zastanowić to bardzo dużo czasu), to możesz wywoływać je po kolei z przerwania np. od timera 2 ustawionego na okres 1.5ms. Jakiś margines zawsze się przydaje. Napisz dokładniej co chcesz robić i jakie zadania przewidujesz.

Możesz też poczytać o tym, ale to już nie Arduino, choć pracuje także na AVR:

http://www.freertos.org/a00098.html

Mam czujniki odbiciowe i chciałbym żeby jeden watek cały czas z czytywał z nich wartości i przekazywał do zmiennej globalnej.

Drugi watek odpowiada za sterowanie silnikiem, jest tam pętla while(czujnik>wartość) no i chciałbym żeby pętla została przerwana jeżeli wartość na czujniku się zmieni na jakąś tam zakładana.

Na pierwszy rzut oka to wygląda tak, jakbyś mógł zrobić jedną dużą pętlę w której odczytujesz stan czujnika a potem korzystasz z tego w funkcji obsługi silnika. Dlaczego nie chcesz/ nie możesz tak zrobić? To wydaje się najprostsze.

EDIT: Na czym polega odczyt czujnika? Ile czasu trwa i co wtedy procesor robi?

To samo z funkcją sterowania silnikiem.

Buduje Line-followera no i moge to zrobic wsyztsko w jednej petli tak naprawde i w tym whilu cały czas wykonywac pomiar, po prostu myślałem ze da się do zrobić "ładniej", ale skoro nie to musze zostac przy tej metodzie.

Uzywam sensora odbiciowego QTR-8A, do odczytu wykorzystuje funkcje z biblioteki QTR ktora zwraca mi wartosc całkowitą. Czas odczytu to około 3200 mikro sekund

OK, to moim zdaniem masz kilka możliwości:

1. Zostawić to jak jest, czyli używać funkcji z biblioteki QTR włączając skanowanie czujników do pętli głównej. To trywialne i tak pewnie napisana jest większość programów na Arduino. Cóż, takie biblioteki są pisane do bardzo prostych strukturalnie programów - to cała zaleta, ale chyba i największa bolączka tego środowiska. Masz rację, że pomyślałeś o innych rozwiązaniach.

2. Odpalić przerwanie okresowe od timera 2 a w jego obsłudze wywoływać skan czujników. Fajne, bo czujniki robią się "same" a w jakiejś globalnej zmiennej volatile będziesz miał wyniki. Jeżeli do tego w przerwaniu będziesz ustawiał jakąś flagę np. "sensor_ready_flag", to w pętli "konsumującej" wyniki (tej od silnika) możesz ją sprawdzać i jeśli nie ma nowych danych, nic ciekawego nie robić. Po odczytaniu i wykorzystaniu wyników powinieneś tę flagę oczywiście kasować. Metoda ma tę wadę, że czas wykonania (jak piszesz) funkcji odczytu jest makabrycznie długi. Na ten czas procesor będzie zamierał w tym sensie, że nie obsłuży żadnego innego przerwania: ani od UARTa ani od timera 0, który w Arduino domyślnie liczy czas rzeczywisty. Trochę kiepsko, choć przy zrozumieniu kosztów może być akceptowalne.

3. Napisać własną obsługę czujnika. To wbrew pozorom nie jest trudne, przecież to tylko kilka napięć do zmierzenia. W obsłudze przerwania od timera 2 (np. 50 czy 100Hz) ustawiasz startowy kanał przetwornika A/C i odpalasz pierwszą konwersję. W obsłudze przerwania od przetwornika A/C zapamiętujesz wynik, zmieniasz kanał i startujesz następny pomiar. Po wykonaniu wszystkich (ile ich masz?), gdy jesteś w obsłudze ostatniego przerwania od ADC zbierasz wyniki do kupy, ew, jakoś obrabiasz i oddajesz w zmiennej globalnej plus ustawienie flagi. Takie coś kosztuje minimalną ilość czasu procesora, niczego nie blokuje a program główny widzi, że co 20 lub 10ms dostaje nowe dane z czujnika - ja bym tak zrobił. Jeżeli masz w systemie wiele takich rzeczy które w większości czekają na jakieś zdarzenia sprzętowe, możesz je poupychać w przerwaniu a na poziomie podstawowym robić tylko rzeczy organizacyjne lub kluczowe, ale czasochłonne. W szczególnym przypadku pętla główna programu może być pusta 🙂

Co Ty na to?

o kurde powiem Ci, że bardzo dużo nowych rzeczy teraz usłyszałem.

1 - tak bym bardzo nie chciał robić, moim zdaniem to bardzo "nieeleganckie" i do tego jeżeli bede chciał rozbudować pojazd i wrzucić nowe czujniki np odległości to wszystko będzie masakrycznie długą mało przejrzysta funkcja loop().

2 - jeżeli czas wykonania funkcji odczytu jest taki długi to chyba nie warto interesować sie tym rozwiązaniem

3 - droga eliminacji wydaje mi się ta opcja jest najlepsza, ale również najmniej dla mnie zrozumiała i najtrudniejsza. Odpowiadając na pytanie mam tych czujników 6.

Musisz mi bardzo pomoc żebym mógł to zrozumieć.

Najważniejsze pytanie:

Czy da sie to zrobić przy pomocy C/C++ czy trzeba wykorzystać np assemblera ?

Ja bym tak nie odrzucał opcji pierwszej od razu. Nikt ci nie każe tego wszystkiego robić w jednej funkcji przecież, możesz sobie podzielić i wołać je z loop co odpowiednią liczbę obrotów pętli.

Co do szybszego odczytywania czujników, to może być trudno -- ADC w AVR-ach jest dość wolny. Możesz go nieco przyśpieszyć kosztem mniejszej dokładności, albo użyć zewnętrznego ADC...

janiu, przede wszystkim przeczytaj o timerach w Arduino: jak zrobić przerwanie okresowe i jak podpiąć do takiego zdarzenia sprzętowego funkcję obsługi (tzw. ISR) - jest tego dużo w sieci (Arduino timer interrupts). Jak już będziesz umiał odpalić któryś wolny timer, podwiesić pod przerwanie swoją obsługę i np. mrugać diodką, jesteś już prawie guru 🙂

Potem znajdź dane katalogowe procesora ATmega32u4 a w nich rozdział o przetworniku ADC:

http://www.atmel.com/Images/Atmel-7766-8-bit-AVR-ATmega16U4-32U4_Datasheet.pdf

Radzisz sobie z takimi tekstami? Jeśli nie, na pewno znajdziesz w sieci jakieś poradniki (ATmega adc tutorial). Tutaj już nie wykorzystasz żadnej magii Arduino w rodzaju analogRead, bo te funkcje czekają na zakończenie pomiaru. Będziesz musiał grzebać w rejestrach przetwornika, ale to nic strasznego, sam zobaczysz. Oczywiście wszystko da się zrobić bez uciekania do asemblera 🙂

W razie problemów, pytaj.

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...