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

ATMEGA32 - Jak uruchomić równoległe wątki do pomiarów i komunikacji RS232?

pies_na_baby 07 Wrz 2013 19:04 5400 35
  • #1 12711317
    pies_na_baby
    Poziom 9  
    Witam.

    Pisałem już trochę programów w C++ ale nigdy nie korzystałem z tego zagadnienia.
    Czy jest możliwe aby atmega32 wykonywała dwa wątki(funkcje) równolegle?

    Mój mikroprocesor komunikuje się poprzez RS232 z komputerem i programem w Visual Studio 2010.
    Zależy mi na tym aby program w pętli głównej wykonywał swoje zadania(funkcje pomiarowe) a w wątku drugim wysyłał dane(wyniki pomiarów).
  • #2 12711338
    tadzik85
    Poziom 38  
    Przerwania....
  • #3 12711416
    pies_na_baby
    Poziom 9  
    Przerwania jednak działają inaczej.
    Podczas wykonywania głównego wątku odsyłają na chwile do funkcji pobocznej, wykonują ją i wracają spowrotem do tego samego miejsca w głównym wątku.
    Czyli tak naprawdę nadal jest to wykonywane "jeden po drugim".

    A ja chciałbym aby takie odesłanie zostało wykonane na początku funkcji głównej i równolegle działały dwie funkcje.
  • #4 12711441
    Steryd3
    Poziom 33  
    W gruncie rzeczy dobrze zorganizowane przerwania dadzą efekt poprawnie wykonywanego programu więc kolega tadzik85 właściwie miał racje. Innym rozwiązaniem jest zastosowanie systemu operacyjnego który zrealizuje równoległość wykonywania zadań z tym, że jest to oczywiście tylko jego złudzenie. Trzeba zauważyć, że sam system operacyjny który zarządza który wątek ma być obsłużony też absorbuje pewne zasoby obliczeniowe mikrokontrolera więc całość może działać jeszcze mniej wydajnie. Pełnej równoległości rozumianej tak, iż podczas jednej chwili czasu wykonywane są dwie funkcje jednocześnie na mikrokontrolerze posiadającym jeden rdzeń nie da się uzyskać i nie ma co kombinować.
  • #5 12711494
    tomekgl
    Poziom 16  
    Wszędzie w architekturach jednoprocesorowych zadania wykonywane są "jeden po drugim". System operacyjny dba o to aby jedna funkcja/wątek/proces nie zablokowały działania innych poprzez wywłaszczenie procesu, zapisanie stanu rejestrów i kontekstu i odpalenie kolejnego zadania z listy wg przyjętego algorytmu szeregowania.
    Jeżeli potrzebujesz "równoległości" 2 zadań, nie ma co kombinować, najprościej będzie jedno odpalać w przerwaniu a drugie poza. Ewentualnie napisać obie funkcje jako nieblokujące i odpalać po kolei w pętli nieskończonej.
  • #6 12711570
    BlueDraco
    Specjalista - Mikrokontrolery
    A po co ta "pętla główna"? Nie wystarczą same przerwania? Np. jedno od timera sterujące pomiarami, drugie od UARTa.
  • #7 12711630
    tomekgl
    Poziom 16  
    BlueDraco napisał:
    A po co ta "pętla główna"? Nie wystarczą same przerwania? Np. jedno od timera sterujące pomiarami, drugie od UARTa.

    Oczywiście można to zaimplementować na wiele sposóbów. Akurat tu użycie 2 przerwań (timer + USART), które mogą sie potencjalnie "przeplatać" wymaga zadbania o synchronizację tych 2 wątków i atomość operacji zapisu ostatecznej wartośći pomiaru jeżeli jest więcej niż 1 bajtowa. Pisząc odpowiednio te funkcje aby się nie blokowały, dużo prościej i bezpieczniej będzie odpalać je na zmianę.

    Poza tym jeżeli układ sam w sposób ciągły ma wysyłać dane, a nie na podstawie żądania, to oparcie się o przerwanie z USART (TX complete?) jest niecelowe moim zdaniem.
  • #8 12711657
    Steryd3
    Poziom 33  
    Zawsze można pomyśleć o zastosowaniu innego mikrokontrolera wyposażonego w DMA co mogło by załatwić problem zbierania danych. Oczywiście nie wszystkie dane mogą być zbierane bez użycia procesora ale często DMA okazuje się być wystarczające. Autor tematu musi doprecyzować jak dokładnie chce by całość wyglądała i wtedy można coś poradzić.
  • #9 12711667
    BlueDraco
    Specjalista - Mikrokontrolery
    Przy jednopoziomowym systemie przerwań łatwiej zsynchronizować dwa przerwania (które same zapewniają sobie "atomowość") niż przerwanie i "pętlę główną".
  • #10 12711789
    pies_na_baby
    Poziom 9  
    Czyli równolegle się nie da... ok, dzięki.

    Teraz opiszę dokładniej mój program:

    Do atmegi mam podłączone 4 różne czujniki. Wykonanie pomiaru każdego czujnika trwa około 1 sec.
    W zależności jaka prośba o daną przyjdzie z komputera po rs232 taki pomiar jest wykonywany.
    Komp wysyła prośbę i musi czekać około 1 sec na wynik.
    Więc cały cykl pomiarowy trwa 4 sec.
    W Visual Studio stworzyłem 4 wykresy na których są zapisywane dane z czujników.

    Wygląda to tak:

    1. prośba o daną z 1 czujnika
    2. 1 sec - wykonywanie pomiaru
    3. dodanie danej do wykresu
    4. prośba o daną z 2 czujnika
    5. 1 sec - wykonywanie pomiaru
    6. dodanie danej do wykresu
    7. itd.

    Więc czujnik 1 po wykonaniu pomiaru czeka 3 sec na polecenie następnego pomiaru.
    Czyli żeby obsłużyć 4 czujniki "na raz" potrzebuję 4 mikroprocesorów.
  • #12 12711866
    pies_na_baby
    Poziom 9  
    Tak, jest to stacja meteorologiczna z 4 czujnikami. Jednym z nich jest właśnie ten czujnik temperatury, tylko on pracuje w tym interfejsie. Reszta czujników jest własnej konstrukcji.
  • #13 12711951
    Steryd3
    Poziom 33  
    Można zrobić to w ten sposób by mikrokontroler zbierał dane z czujników w sposób ciągły("w kółko") i wysyłał je na żądanie do PC-ta. Oczywiście przy takim podejściu trzeba się zgodzić by przedstawiona dana mogła być trochę nieaktualna bo maksymalnie z przed 4 sekund. Przy założeniu, że dynamika zmian warunków środowiskowych takich jak wilgotność, temperatura czy ciśnienie nie jest zbyt duża taka metoda spokojnie powinna przynieść dobre rezultaty. Nie wiem jak planujesz zrealizować komunikację po magistrali 1-wire -ona bywa dość kłopotliwa i nie lubi być przerywana -w końcu opiera się na dość restrykcyjnych relacjach czasowych. W czujniku DS18B20 na konwersję czeka się co prawda coś pod 1 sekundę (przy pełnej rozdzielczości z tego co pamiętam 750ms ) ale w międzyczasie przecież można robić coś innego a dane z czujnika odczytać w sprzyjającej chwili. Komunikacje po magistrali 1-wire można też zrealizować z użyciem kolejnego interfejsu USART -zakładając, iż mikrokontroler posiada ich więcej niż jeden. Tak więc jakieś pola manewru są.
  • #14 12712028
    piotrva
    VIP Zasłużony dla elektroda
    Powiedz jakie te 3 pozostałe czujniki, bo DS18B20 możesz robić tak, że odpalasz przerwanie timera co 1s i wykonujesz w nim takie operacje: 1. odczyt temperatury, 2. wysłanie polecenia konwersji. Wywołanie tego w przerwaniu od razu zapewnia blokowanie innych przerwań, a z drugiej strony nie blokuje procesora na tak długi czas, żeby stwarzać problemy.

    Ogólnie jak bym zrobił to tak:
    1. Odczyt z czujników w przerwaniu - jeśli nie można przeplatać odczytu z pozostałych 3 czujników (powiedz co to i jak dokonujesz pomiaru) to zrób w przerwaniu maszynę stanów. Dzięki temu w jakichś zmiennych w programie głównym zawsze masz aktualne odczyty (jak wspominali koledzy - z pewnym opóźnieniem)
    2. Nadawanie/odbiór UART też w przerwaniu z buforem kołowym
    3. W pętli głównej sprawdzasz, czy w buforze odbiorczym UART masz zapytanie od PC, a jeśli tak to wtedy do bufora nadawczego pakujesz dane z wynikami i wtedy dokonujesz też przeliczeń czystych danych z czujników na odpowiednie wartości.

    Nie wiem jakie masz tam czujniki, ale ja w pewnym projekcie z 10 czujnikami analogowymi, w którym jeszcze konieczne było uśrednianie wyników z kilkudziesięciu szybko wykonywanych po sobie pomiarów stosowałem taką metodę, bo tako też PC musiałby czekać na wynik pomiaru około 1s
  • #15 12712117
    pies_na_baby
    Poziom 9  
    Nie chcę aż tak komplikować programu - ponieważ wykonanie tych przerwań i przeplatanie ich w międzyczasie z innymi żeby nie marnować cennych sekund jest dla mnie trudne do ogarnięcia programowo. (rozumiem że to miało by wyglądać tak że podczas konwersji - 750ms - wykonywał bym inne zadania)

    Zostawię to poprostu tak jak już mówiłem że mam:
    > prośba z kompa o pomiar
    > odczekanie
    > odebranie i wyświetlenie.

    Tylko to wiąże się z zastosowaniem opóźnień w Visualu czyli z zastosowaniem właśnie wątków równoległych.
    Do tej pory stosowałem Thread.Sleep(750); co zatrzymywało wykonywanie programu na 750 ms - po prostu program się na ten czas zawieszał.
    Teraz muszę zastosować wątek równoległy i po problemie - tutaj od razu kolejna prośba czy mogę zamieścić przykładowy kod i czy ktoś może mi go sprawdzić czy będzie działał w moim programie?
  • #16 12712301
    piotrva
    VIP Zasłużony dla elektroda
    Ale Ty nie musisz nic a nic dbać o przeplatanie przerwań w czasie - procesor sam zadba, że jak w jednej chwili zgłoszone zostaną 2 przerwania to wykonają się one po kolei.
    Pokaż jaki masz program na AVR'a i powiedz co to za 3 pozostałe czujniki i jak czytasz z nich dane.
    Może to o czym piszemy wygląda strasznie, ale to jest w rzeczywistości proste.
    A opóźnienie 750ms - porażka...
  • #17 12712663
    SylwekK
    Poziom 32  
    Ja w swoim stertowniku basenowym obsługę DS x2 zrobiłem w przerwaniach i oba wyniki mam co każde 750ms. Po prostu selektywnie wykonywane są komendy sterujące, które pojedynczo zajmują bardzo mało czsu prockowi. W Twoim przypadku lepiej ten odczyt przenieść do pętli głównej, a przerwania zostawić na bezpieczny niczym nie zakłócony przesył danych i jakiś licznik programowy dla opóźnień potrzebnych DS'om.
  • #18 12712687
    BlueDraco
    Specjalista - Mikrokontrolery
    Mam urządzenie, które w sposób ciągły mierzy temperaturę ośmioma DS18B20 i na żądanie z PC wysyła różne dane pomiarowe. Sam pomiar temperatury jest zrobiony na trójpoziomowym automacie zaimplementowanym na przerwaniach i odbywa się całkowicie "w tle". Procesor nie czeka w tym czasie na żadne zdarzenia w żadnych pętlach, a równocześnie w przerwaniu timera jest wykonywany algorytm sterowania grzaniem/chłodzeniem. Interpretacja poleceń z PC była zrobiona w pętli głównej, ale sama transmisja (akurat w tym urządzeniu przez USB CDC) jest obsługiwana w całości na przerwaniach.
    Cały cykl pomiarowy dla 8 czujników zajmuje ok. 5 sekund.

    Do tego, o czym piszesz, z całą pewnością nie potrzebujesz czterech procesorów. To tylko kwestia odpowiedniej budowy oprogramowania.
  • #20 12713514
    perlon
    Poziom 20  
    W powyższych postach to się pojawiało. Ja bym w przerwaniu na maszynie stanów na okrągło wysyłał żądania konwersji temperatury i odczytywał wszystkie czujniki. Odczyt temperatury i zapis do bufora "do zapisu" zrobiłbym atomowo. Z drugiej strony każde żądanie ze strony PC-ta również atomowo przepisywałoby bufor "do zapisu" na bufor "do odczytu" i odczytanie danej temperatury wg żądania PC'ta. Pętla główna w zasadzie byłaby pusta a pomiar temperatury i przesłanie danych do PC'ta odbywałyby sie asynchronicznie. Maksymalne opóźnienie odczytu temperatury to jeden cykl pomiarowy DS'ów.
  • #21 12715195
    pies_na_baby
    Poziom 9  
    Dzięki wszystkim za pomoc.

    Oto mój program:
    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kod jest bardzo prosty i przejrzysty - taki lubię najbardziej.
    Wczoraj przerobiłem cały program w Visualu i zastosowałem timery jako funkcje z opóźnieniami.

    Tutaj w kodzie jest tylko 1 czujnik, drugim jest:
    KAmodBAR-SPI Moduł czujnika ciśnienia z interfejsem SPI (MPL115A1)
    ale jeszcze jestem na etapie szukania biblioteki i poznania w ogóle jak się go używa.(jak ktoś miał już z nim do czynienia to proszę o kontakt)

    3 i 4 jest czujnik prędkości i kierunku wiatru własnej konstrukcji.
    Prędkość czytam na podstawie ilości pełnych obrotów wiatraka w określonym czasie.
    A kierunek z położenia wiatrowskazu.
  • #22 12715374
    tmf
    VIP Zasłużony dla elektroda
    Dobrze, że masz ATMEGA32, bo przy tym stylu programowania, zasoby mniejszego procka szybko by się wyczerpały - myślę o użyciu float do prostej operacji przeliczania temperatury, gdzie w zupełności wystarczy typ stałopozycyjny, lub użyciu molocha typu sprintf z typem float. No ale jeśli możesz sobie na to pozwolić to ok. Co do twojego problemu - skoro masz tylko 4 źródła pomiarowe, to może zmienić sposób wymiany danych z PC. Np. PC wysyła żądanie temperatury z jakimś ID, ale nie czeka na wynik. W tym czasie AVR sobie odnotowuje, że ma wysłać temperaturę i zaczyna konwersję, po czym czeka na kolejne polecenie. Jeśli nadejdzie to rozpoczyna pomiar w kolejnym kanale. Jeśli pomiar w danym kanale się kończy to wysyła do PC wynik, zaopatrzony w identyfikator żądania, dzięki czemu program na PC może zidentyfikować, który wynik jest dla którego żądania. Wtedy cała wymiana może trwać tak długo jak długo trwa najdłuższy pomiar (czyli 750 ms praktycznie niezależnie od liczby cuzjników).
    Zauważ też że twoja obsługa USART, gdzie masz w pętli głównej przerwy po 750ms, jest do kitu. Co jeśli w tym czasie wysłane zostanie z PC więcej żądań? Bufor odbiornika USART w AVR jest krótki. Żądania te zostaną stracone, a ty zyskasz błąd przepełnienia USART, którego oczywiście nie obsługujesz. Z kolei jeśli dokładnie panujesz nad wysyłaniem żądań z PC, to dlaczego po prostu nie stworzyć żadania, typu, wyślij mi komplet pomiarów i po sprawie.
  • #23 12715398
    BlueDraco
    Specjalista - Mikrokontrolery
    pies_na_baby napisał:

    Kod jest bardzo prosty i przejrzysty - taki lubię najbardziej.


    Widzę, że poczucie humoru Koledze dopisuje...

    Co byś powiedział na:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #24 12716250
    piotrva
    VIP Zasłużony dla elektroda
    Hehehe, no kod to arcydzieło.
    Ja tu nie widzę potrzeby stosowania ŻADNYCH OPÓŹNIEŃ.
    Napisaliśmy CI co zrobić z DS18B20, odczyt z czujnika ciśnienia to najpewniej wymiana kilku bajtów przez SPI - ułamek chwili, czujnik kierunku - dalej nie wiemy co to za dziwactwo, prędkość wiatru - tu pomysł ze zliczaniem impulsów w jednostce czasu też można zrobić na przerwaniach, ewentualnie stosować komplementarnie z pomiarem okresu dla zwiększenia dokładności przy niższych obrotach.
  • #25 15090378
    MateuszW_
    Poziom 8  
    Witam
    Nie chcę zakładać nowego wątku, więc piszę tutaj, bo problem podobny, choć nie do końca.
    Piszę program na procek XMega, który realizuje wiele rzeczy, a z istotnych tutaj steruje silnikiem krokowym i odczytuje temperaturę z DS18B20. Sterowanie silnikiem oparte jest na przerwaniu timera, w Którym wykonywany jest jeden krok, oraz określane jest opóźnienie do następnego kroku (czyli prędkość silnika), które to opóźnienie jest ładowane do timera. Generalnie max przewidziana częstotliwość aktywacji tego przerwania to ok 4 kHz i procek pracujący na 24 MHz się spokojnie wyrabia (robiąc w między czasie mnóstwo innych rzeczy) i praca silnika jest płynna.

    Problem sprawia czujnik DS18B20, z którego co kilka sekund odczytuję temperaturę. Jego obsługa zajmuje się biblioteka do 1Wire ze strony Atmela. To zwykła realizacja na jednym pinie IO. Transmisja danych działa tak, że każdy bit wysyłany/odbierany jest w bloku atomowym (wyłączone przerwania), aby nie zakłócić wymaganych zależności czasowych. Natomiast między bitami przerwania są odblokowywane, bo przerwy między bitami mogą być długie. Dlatego też, jeśli np silnik chce wykonać krok akurat w czasie transmisji bita, to musi poczekać na zakończenie i przed kolejnym bitem wykonywane jest przerwanie silnika.

    Wszystko byłoby fajnie, gdyby nie sygnał Reset/Presence, który trwa prawie 1 ms. W tym czasie przerwania również są zablokowane. Z tego powodu, jak przerwanie silnika trafi na ten moment to jest opóźnione o prawie 1 ms, a to bardzo dużo i daje się zauważyć (i usłyszeć) zaburzenie w płynności pracy. Inne wysyłane bity na magistrali są krótkie i raczej nie stanowią problemu.

    Dlatego zastanawiam się nad modyfikacją funkcji reset/presence, tak, aby możliwe było wywołanie przerwania w jej trakcie. Wydaje mi się, że w początkowym czasie 480 us, gdy procek ustawia stan niski mogę odblokować przerwania. Być może to przerwanie wydłuży troszkę zalecany czas, ale raczej nie powinno to być dużo (przerwanie silnika wykonuje się bardzo szybko). Gorzej z drugą częścią, gdzie czekamy na odpowiedź czujnika. Nie jestem pewien, gdzie tam mogę sobie pozwolić na odblokowanie przerwań. W zasadzie, jeślli np co któryś pomiar zostanie zakłócony przerwaniem (czujnik nie zostanie rozpoznany), to nie ma problemu, bo mogę poczekać na następny pomiar. Także myślę, że jeśli to nie będzie działało w każdym pesymistycznym przypadku, to nic się nie stanie.

    Chyba najlepiej by było zrobić dodatkowe przerwanie, które realizowało by elementarne operacje na magistrali 1Wire, czyli włączało stan niski linii i go zwalniało. Wtedy nie byłoby tego czekania 480 us i to dodatkowe przerwanie mogłoby przerwać przerwanie silnika na nieistotny czas. Tylko, czy to nie jest za duża komplikacja?
  • #27 15090655
    MateuszW_
    Poziom 8  
    Tak, znam tą metodę, jednak chciałbym jej uniknąć z uwagi na potrzebny dodatkowy sprzęt (tranzystory). Chciałbym w miarę możliwości zminimalizować ilość elementów na płytce, aby było to jak najtańsze. A jeśli 1Wire da się zrealizować bez dodatkowego sprzętu, to tak byłoby dla mnie najlepiej.
  • #28 15090664
    tmf
    VIP Zasłużony dla elektroda
    MateuszW_ napisał:

    Chyba najlepiej by było zrobić dodatkowe przerwanie, które realizowało by elementarne operacje na magistrali 1Wire, czyli włączało stan niski linii i go zwalniało. Wtedy nie byłoby tego czekania 480 us i to dodatkowe przerwanie mogłoby przerwać przerwanie silnika na nieistotny czas. Tylko, czy to nie jest za duża komplikacja?


    Na czas nadawania reset możesz odblokować przerwania. Ale lepiej to zrobić tak jak kolega powyżej sugeruje za pomocą USART - możesz kombinować sam, a jeśli chcesz to ściąnij darmowe przykłądy do moich książek o XMEGA i tam masz implementację OW na USART na XMEGA.
    A jeśli układ jest gotowy i nic nie możesz zmienić, to odczyt stanu możesz przez event system podpiąć pod timer w trybie capture i zamiast próbkować stan magistrali liczyć odstępy pomiędzy kolejnymi zdarzeniami mierzone przez timer. Jest to udziwniony sposób, ale może być jako workaround dla złego projektu :)

    Dodano po 1 [minuty]:

    MateuszW_ napisał:
    Tak, znam tą metodę, jednak chciałbym jej uniknąć z uwagi na potrzebny dodatkowy sprzęt (tranzystory). Chciałbym w miarę możliwości zminimalizować ilość elementów na płytce, aby było to jak najtańsze. A jeśli 1Wire da się zrealizować bez dodatkowego sprzętu, to tak byłoby dla mnie najlepiej.


    Przecież w XMEGA nie potrzebujesz dodatkowego tranzystora - pin IO możesz skonfigurować jako OD. To rozwiązanie nie wymaga żadnych elementów dodatkowych.
  • #29 15091062
    landy13
    Poziom 31  
    tmf napisał:
    ...ściąnij darmowe przykłądy do moich książek o XMEGA i tam masz implementację OW na USART na XMEGA.
    Przeczytałem trzy Twoje książki o mikrokontrolerach i protokół OW (także przez USART) opisany był w pierwszej z nich (o ATMEGA). W pozostałych dwóch (o XMEGA) nic takiego nie widziałem.
    Coś mi umknęło, czy też uzupełniłeś to w jakimś nowszym wydaniu?
  • #30 15091184
    tmf
    VIP Zasłużony dla elektroda
    landy13 napisał:
    tmf napisał:
    ...ściąnij darmowe przykłądy do moich książek o XMEGA i tam masz implementację OW na USART na XMEGA.
    Przeczytałem trzy twoje książki o mikrokontrolerach i protokół OW (także przez USART) opisany był w pierwszej z nich (o ATMEGA). W pozostałych dwóch (o XMEGA) nic takiego nie widziałem.
    Coś mi umknęło, czy też uzupełniłeś to w jakimś nowszym wydaniu?


    Wstyd mi przyznać, ale masz rację. Chyba przez nieuwagę nie umieściłem portu OW-USART dla XMEGA w przykładach. Istotnie są tylko przykłady w "Język C dla..." dotyczące zwykłych AVR. Obiecuję naprawić swój błąd i te brakujące informacje umieszczę na blogu kolegi Dondu, a przykłady wrzucę do repozytorium - najnowsze są zawsze na Atmel Spaces (przykłady na stronie Helionu uaktualniam tylko w razie istotnych zmian).
    Żeby naprawić swój błąd tylko napiszę na szybko, że OW przy pomocy USART na XMEGA realizuje się identycznie jak na ATMega (kod wymaga tylko kosmetycznych zmian związanych z nazwami rejestrów), a żeby nie był potrzebny dodatkowy tranzystor należy ustawić konfiogurację portu IO nadajnika UART (TxD) jako wyjście z otwartym drenem (konfiguracja wired-AND) oraz połączyć TxD z RxD. W przypadku XMEGA E5 połączenie TxD z RxD nie jest konieczne, gdyż w tym MCU USART może pracować w trybie kompatybilności z 1-wire, wystarczy ustawić odpowiedni bit. W razie czego służę pomocą.
REKLAMA