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

[AtMega16] [AtMega16][C] - Implementacja multitaskingu dla odczytu ds18b20 i sterowania GPIO

chris-s 10 Kwi 2013 23:31 2607 24
REKLAMA
  • #1 12183900
    chris-s
    Poziom 15  
    Witam,
    Od niedawna przełamałem się i wykonałem drugie, po paru latach niechęci, podejście do uC. Tym razem wujek Google wydawał się jakby bardziej pomocny, a i elektrodowa szukajka dawała bardziej trafne odpowiedzi. Opanowałem wejścia / wyjścia, wyświetlacz 7seg, potem wyświetlacz HD44780 2x16 i 4x20, a na koniec ds18b20. Niestety tu sielanka się kończy. Chciałem np, żeby powyżej jakieś temp. odczytanej z ds18b20 włączał się wentylator, albo coś takiego. Chciałem też, żeby przyciskami możnabyło tę wartość zmienić. Jednak odczyt trochę trwa, poz tym w wielu funkcjach pojawia się "delay", która po prostu zatrzymuje program. I tu pojawia się potrzeba multitaskingu. Jedna funkcja czeka na wciśnięcie guzika, inna cały czas "rozmawia" z ds18b20, jeszcze inna miga diodą jak trzeba coś zasygnalizować itd.
    Niestety internetowe tutoriale i udostępnione kody źródłowe są dla mnie jeszcze zbyt skomplikowane i nie jasne.
    Czy ktoś z Was dysponuje, albo chciałby napisać (i się podzielić) z przystępnymi komentarzami, kod źródłowy programu, w którym jest pokazane jak się zabrać za multitasking w AtMedzie 16?

    Pozdrawiam :)
  • REKLAMA
  • Pomocny post
    #2 12183927
    dondu
    Moderator na urlopie...
    Witaj.

    Zadanie nie jest trudne i spokojnie dasz sobie z nim radę we własnym zakresie.
    Po prostu wszystko należy opierać o timery i inne wewnętrzne moduły oraz przerwania.
    W dodatku program można tak napisać, by jeden timer obsługiwał różne funkcjonalności.

    Innymi słowy, zacznij pisać od nowa swój program, ale tak, by pętla główna była pusta :)
    Aktualnie mam w przygotowaniu cykl artykułów, w których będzie pokazany multitasking - publikacja już w nadchodzący weekend, więc może nieco sobie poszerzysz wiedzę.

    Ale tak naprawdę, chodzi o kombinowanie i taki podział zadań pomiędzy timery i "bebechy", by wszystko ogarnąć przerwaniami. Tutaj potrzebne jest inne myślenie i zapomnienie, że delay istnieje :)
  • #3 12184674
    GanzConrad
    Poziom 25  
    Żeby nie wykładać Ci wszystkiego na tacy powiem tak:
    zerknij do noty katalogowej swojego uP i przeczytaj opis Timera0
    ustaw preskaler na wartość 1024 (jeśli korzystasz z kwarcu np 12MHz)
    TCCR0 |= (1<<CS02)|(1<<CS00);
    ustaw tryb CTC:
    TCCR0 |= (1<<WGM01);
    ustaw wartość przepełnienia tak, aby występowało co 10ms
    OCR0 = 117; // dla 12MHz miałem chyba 117

    w obsłudze przerwania dodajesz dziesiątki milisekund , jak zliczysz 100 - to znaczy, że minęła sekunda (ustawiasz zmienną flagi sekundy na "1" i licznik sekund od 1-2) i w pętli głównej możesz wysłać ConvertT do czujnika. Po minięciu kolejnej sekundy odczytujesz temperaturę, a w przerwaniu zerujesz licznik sekund.
    Jak będziesz się bawił RTC to będzie Ci on generował przerwanie (np na INT0) dokładnie co sekundę i wtedy możesz zrezygnować z Timera. (chociaż nie wiem czy jest to "poprawne", ponieważ przy uszkodzeniu RTC wykłada się cała magistrala 1-Wire)
  • #4 12186261
    chris-s
    Poziom 15  
    Witam. Dziękuję za zainteresowanie. Zanim wezmę się za program muszę uporać się z kilkom małymi problemami :(
    Niestety nigdy nie wykorzystywałem ani przerwań, ani timerów. To niestety sprawia, że nie wiem do końca jak się zabrać za ten program. Nie mogę do końca zrozumieć czym się różnią przerwania od znanych mi już funkcji (void), które wywołujemy w głównej pętli. Mam na myśli brak zrozumienia dla różnicy między ustawieniem flagi, która w pętli głównej przywoła jakąś funkcje, a wywołaniem tej funkcji od razu.
    Nie używam zewnętrznego kwarcu, tylko wewnętrzny oscylator. Nie za bardzo też rozumiem te wektory i samo "aktywowanie" przerwania.
    Co do timerów, to coś o nich czytałem i chociaż na razie słabo mi z nimi szło, to może dam radę. :)
    Prędkość procesora ustawiłem na 1.6MHz. Mam nadzieje, że to nie wyklucza możliwości zastosowania multitaskingu.

    Jeszcze raz dziękuję,
    Pozdrawiam :)
  • #5 12186797
    stanleysts
    Poziom 27  
    Polecam jakieś tutoriale, albo książki do uC, bo inaczej czarno to widzę.
  • #7 12190491
    chris-s
    Poziom 15  
    Poległem... :( Ale jest progres! Ale jednak poległem...

    Mam już kod, który wygląda, przynajmniej jak dla mnie sensownie, ale niestety nie działa. Czy ktoś z Was mógłby mi pomóc w rozwikłaniu problemu?
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Niestety, ale funkcja wykonuje się jakby do aktywowania Timera. Potem, na samym początku pętli nieskończonej "while" nie wykonuje się nawet pierwsze polecenie (napis "before everything"). Trochę mnie to dziwi, bo zanim dodałem polecenia napisów na wyświetlaczu przeczuwałem, że problem leży gdzieś dalej. Po załadowaniu tego programu wyświetla mi się tylko
    Temp 1:
    aft timer


    Znając życie i początkujących programistów takich jak ja, to coś prostego i głupiego, ale niestety już trochę nad tym dziś siedzę a nawet z pomocą Googla znaleźć nie mogę :(
    Dziękuję za chęci pomocy, posty i linki!
    Pozdrawiam
  • Pomocny post
    #8 12190926
    Tom1988p
    Poziom 16  
    Odblokuj przerwania przed pętlą główną za pomocą polecenia "sei();" bo inaczej nie będzie działać.
  • REKLAMA
  • #9 12191031
    chris-s
    Poziom 15  
    Niestety, nawet to nie pomogło :(
  • #10 12191149
    stanleysts
    Poziom 27  
    Co nie działa? Nie da się pisać 300 linii kodu i potem liczyć, że całość zadziała.
  • REKLAMA
  • #11 12191153
    Tom1988p
    Poziom 16  
    Podaj komplet plików, zobaczymy co tam jest nie tak.
  • Pomocny post
    #12 12191159
    pbuhne
    Poziom 15  
    Wywal ten średnik za while(1);
  • #13 12191210
    chris-s
    Poziom 15  
    Nie pisałem od razu 300 linijek kodu.
    Na początku miałem gotowy, dobrze działający program, ale zrobiony po staremu, czyli z "delay'ami".
    Teraz funkcje z tego programu wkleiłem po prostu do dość krótkiego programu, w którym zamiast "delay'ów" jest timer.
    Generalnie wiem, że pisząc program warto go testować co kilka linijek (nowych funkcji), ale tym razem wydawało mi się, że łączę dwa sprawdzone programy. Stąd moje zdziwienie, że nie działa i nie wiem czemu.
    Pozdrawiam
  • #14 12191290
    chris-s
    Poziom 15  
    pbuhne napisał:
    Wywal ten średnik za while(1);


    Fakt, to pomogło. Program wykonuje się w całości, jednak teraz powstał nowy problem. - Program cały czas uważa, że jest wciśnięty przycisk od zmniejszania temperatury. Nie wiem dlaczego tak jest, skoro ustawiłem rezystor podciągający.
    Przy okazji pisania tego posta ustawiona temperatura zmalała już do -8000'C To chyba sporo poniżej 0K :P

    EDIT:
    Nie wiem jak to możliwe, bo uC jest nówka sztuka, ale chyba coś jest z pinem 1 portu a. Jak przypisałem przyciski do innych wejść, to działa dobrze :)
  • REKLAMA
  • #15 12191359
    pbuhne
    Poziom 15  
    Sprawdź fizyczne połączenia, czy gdzieś zwarcia nie ma na pinie od zmniejszania i wstaw aktualny kod.
  • #16 12191404
    chris-s
    Poziom 15  
    Zwarcia raczej nie ma, bo odłączałem wszystkie przewody od klawiatury od płytki ewaluacyjnej, która jest, trzeba przyznać, porządnie wykonana. (W sensie, że kupiona, a nie na płytce stykowej)
    Kod:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #17 12191476
    Tom1988p
    Poziom 16  
    To podciągnij zewnętrznym rezystorem i zobacz czy zmienia się zachowanie.

    Kody wstawiaj w znacznikach "syntax"

    Niepotrzebnie zwiększasz ilość kodu używając flaga1 i flaga2, wrzuć to co w nich masz tam gdzie je ustawiasz. Główna pętla sanie się czytelniejsza...
  • #18 12191517
    chris-s
    Poziom 15  
    Teraz wygląda tak :)

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #19 12191748
    Tom1988p
    Poziom 16  
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    Idea dobra ale robisz odczyt co 800ms i to już nie jest dobre, rozumiem eliminacja drgań jest już pokonana ale może lepiej będzie tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Męczysz zbędnie procesor używając w w odczycie temperatury
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    Ja bym to przeniósł do pętli głównej a nawet do osobnej funkcji w której tylko tym "rysował" dane na wyświetlaczu.
    Zamiast używanie niby to double (faktycznie float) czyli liczby zmiennoprzecinkowej proponuje liczbę stało przeciekową, w internecie można szybko znaleźć przykłady.
  • #20 12191828
    chris-s
    Poziom 15  
    Co do klawiszy, to zmieniłem na tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Teraz uC cały czas czeka na wciśnięcie przycisku. Za to kiedy jest już wciśnięty, to nie dość, że wyeliminowane są drgania, to nie trzeba wciskać tyle razy ile chcę się zmienić, tylko można potrzymać :)
    Zmieniłem jeszcze z 800 na 500 ms. Sprawdzałem "na czuja". Dla mnie tak jest najwygodniej, ale to już kwestia gustu. ;)

    Co do tych zmiennych, to może coś z tym zrobię, ale na pewno nie dziś, bo nie mam już siły.

    WIEEEELKIE DZIĘKI za pomoc :)
  • Pomocny post
    #21 12192673
    Tom1988p
    Poziom 16  
    Powrócę jeszcze do tematu. Timery programowe to objaśnił Mirekk36 w swojej książce oraz artykułach i wideo poradnikach, bardzo dobrze je się stosuje. Jest to proste, wystarczy ustawić jakiś timer w tryb CTC i wywoływać przerwanie co jakiś zamierzony czas (stosuje około 10ms).
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
    OCRx wyliczamy według tego wzoru:
    F_CPU/Prescaler/100
    Zaokrągloną wartość wpisujemy do rejestru OCRx.

    W przerwaniu po prostu zmienna jest zmniejszana o jeden aż osiągnie 0.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Następnie wykorzystujemy takie zmienne np. w głównej pętli programu aby określano funkcje wykonywały się co określony czas np. wyświetlanie obrazu, obróbka danych czy inne funkcje.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #22 12192921
    BlueDraco
    Specjalista - Mikrokontrolery
    Jeżeli używasz liczb zmiennopozycyjnych, to problem drgań przycisków masz automatycznie z głowy. Zastosowanie tutaj zmiennego przecink to chory pomysł - te operacje zajmują większość czasu procesora i większość pamięci Flash.

    Mopesz np. trzymać temperaturę jako liczbę całkowitą w dziesiątych częściach stopnia.
  • #23 12193177
    Tom1988p
    Poziom 16  
    Innymi słowy zamiast float 27,6 to liczba całkowita uint16_t (unsigned int) 276, następnie wartość można do wyświetlenia rozbić na dwie części:
    całkowita = 276/10
    ułamkowa = 276%10

    Do porównania (obróbki) nie ma takie potrzeby. Bo co za różnica czy będzie 23.4 > 24.7 czy to będzie 234 > 247 wynik i tak taki sam...
  • Pomocny post
    #24 12194402
    BlueDraco
    Specjalista - Mikrokontrolery
    Wynik taki sam, tylko czynność porównania kilkadziesiąt razy wolniejsza.
  • #25 12195166
    chris-s
    Poziom 15  
    @Tom1988p Wielkie dzięki, to co zawarłeś w swoim poście o timerach już jakoś sobie sam wydedukowałem (z resztą dodałem dodatkową zmienna zmniejszaną przez przerwanie). Dzięki Tobie jednak inni szukający czegoś o timerach, przerwaniach i multitaskingu będą mogli wszystko zrozumieć.
    @BlueDraco i Tom1988p dzięki, nie wpadłem na to. :)
    Pozdrawiam :D
REKLAMA