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

Ładowanie lub odczyt z tablicy w języku C dla atmega 8

Tomq 16 Lis 2013 18:43 4146 34
  • #1 16 Lis 2013 18:43
    Tomq
    Poziom 38  

    Witam.
    Jakiś czas temu zainteresowałem się programowaniem mikrokontrolerów AVR, potem miałem dłuższą przerwę i chciałbym wrócić do nauki.

    Obecnie chciałbym napisać program, który zapisuje do tablicy kolejność wciśniętych klawiszy, a następnie na żądanie (czyli po wciśnięciu klawisza przywołania)wyświetla kolejność wciskania klawiszy w odstępach 0,5sekundy.

    Jeśli opis wydaje się zagmatwany, to może tu będzie jaśniej:
    - zwieram po kolei różne wyprowadzenia PORTD do masy, a każde z tych zwarć zapisuje aktualny stan rejestru PIND na kolejne pozycje w tablicy (rejestr[8]). Gdy wcisnę przycisk przywołania (tu: PORTC1) program uruchamia pętle która ładuje kolejne wartości z tablicy do portu D, do którego podpięte są diody. Świecą więc po kolei diody o tych numerach, które przyciski były po kolei wciśnięte.

    Problem jaki napotkałem jest taki, że mój kod nie do końca działa. Gdy wcisnę po kolei kilka klawiszy i chce to odczytać, to czasem wyświetla to, że do tablicy była załadowana wartość 0.

    Przykładowo:
    - wciskam klawisz 1,3,2,1,3
    - pokazuje 1,3,wszystkie_diody_zapalone,2,1

    Listing:

    Kod: c
    Zaloguj się, aby zobaczyć kod



    Próbowałem także zrobić warunek wciskania klawiszy i ładowania wartości do tablicy w ten sposób:

    Kod: actionscript
    Zaloguj się, aby zobaczyć kod


    Ale efekt jest ten sam.

    Jeśli ktoś ma jakieś sugestie to proszę pisać.

    0 29
  • Pomocny post
    #2 16 Lis 2013 18:55
    tadzik85
    Poziom 38  

    DRGANIA STYKÓW!!

    0
  • #3 16 Lis 2013 19:33
    Tomq
    Poziom 38  

    Ok, ok, tylko jaki jest w takim wypadku mechanizm ładowania zer (lub przechodzenia do następnej pozycji tablicy) podczas drgań styków?

    Wstawiłem opóźnienia (wartość 20-120 ms) tam gdzie wciska się lub zwalnia jakiś przycisk i nadal program nie działa tak jak trzeba:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Jak inaczej można wyeliminować ten problem?
    Dlaczego co którąś pozycje do tablicy wpisuje się "0"? A może wpisywane wartości są dobre, a problem leży w odczytywaniu wartości z tablicy?

    EDIT:
    Zauważyłem, że liczby odczytywane są w złej kolejności:
    jeśli wcisnę: 12312312 to zapalają się diody:
    - np (wszystkie),3,1,2,(wszystkie),1,3
    - innym razem: 2,(wszystkie),1, (wszystkie),3,2

    Może tablica jest źle zdefiniowana? Ale przecież podałem jako ilość 8 elementów i liczę je zaczynając od 0.

    0
  • Pomocny post
    #4 16 Lis 2013 21:07
    tadzik85
    Poziom 38  

    Drgania występują również przy zwalnianiu przycisku, stąd chwile zapalenie wszystkich diod.

    0
  • #5 16 Lis 2013 21:10
    Tomq
    Poziom 38  

    To jak je w tym wypadku wyeliminować?
    Przecież:


    Kod: c
    Zaloguj się, aby zobaczyć kod

    A więc ładuje stan PIND do rejestru i czeka 80ms, a potem:


    Kod: c
    Zaloguj się, aby zobaczyć kod

    "kiedy jest wciśniety przycisk 1 lub przycisk2 lub przycisk3 lub przycisk4" "nic nie rób"

    a jeszcze potem:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #6 16 Lis 2013 21:11
    tadzik85
    Poziom 38  

    Po wykryciu reakcji odczekać potem znów sprawdzić stan portu.

    0
  • #7 16 Lis 2013 21:13
    Tomq
    Poziom 38  

    To jest :

    Kod: c
    Zaloguj się, aby zobaczyć kod


    wykryto wciśnięcie przycisku

    Kod: c
    Zaloguj się, aby zobaczyć kod


    czekaj 80ms

    Kod: c
    Zaloguj się, aby zobaczyć kod

    dopiero teraz przypisz do tablicy stan PIND.



    --------------------------------
    Co miałeś na myśli pisząc "znów sprawdzić"?

    0
  • #8 16 Lis 2013 21:19
    tadzik85
    Poziom 38  

    Uporządkuj program, wiem ze to 1 próba i testowa ale kiepsko się czyta takie rozjechane linie.

    Wciskasz przycisk - drganie
    zwalniasz przycisk - drganie

    sprawdzasz stan portu czekasz i znów sprawdzasz. i dopiero tą 2 wartością się zainteresuj.

    0
  • #9 16 Lis 2013 23:04
    Tomq
    Poziom 38  

    Już się chyba w tym pogubiłem. Powstawiałem kilka opóźnień, ale nie wiem, które tu są potrzebne, a które nie. Niby trochę lepiej już to działa, ale i tak za każdym razem zdarzają się złe odczyty (wszystkie diody świecą).

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #10 16 Lis 2013 23:14
    tadzik85
    Poziom 38  

    nadal nie zrozumiałeś

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #11 16 Lis 2013 23:33
    BlueDraco
    Specjalista - Mikrokontrolery

    Tak to jest, kiedy nie sprawdza się stanu przycisków w przerwaniu timera...

    0
  • #12 17 Lis 2013 11:30
    Tomq
    Poziom 38  

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Nie wiem jak inaczej można to napisać. Sprawdzam, czy któryś przycisk jest wciśnięty, czekam aż 180ms, sprawdzam znowu, czy któryś przycisk jest wciśnięty, jeśli tak to dopiero teraz ładuje stan portu do danej pozycji w tablicy i do czasu, aż przycisk jest wciśnięty.

    I nadal nie działa. Albo źle to napisałem, albo nie tędy droga i muszę spróbować albo z polutowaniem kondensatorów pod przyciski, albo z tym sposobem: http://mirekk36.blogspot.com/2012/10/obsuga-klawiszy-drgania-stykow-cd2.html


    Cytat:
    Tak to jest, kiedy nie sprawdza się stanu przycisków w przerwaniu timera...

    Naprawdę nie da się tego zrobić w prostszy sposób?

    0
  • Pomocny post
    #13 17 Lis 2013 11:48
    dondu
    Moderator Mikrokontrolery Projektowanie

    Da się, ale timer to w 99% przypadków najlepszy sposób tym bardziej, że z reguły jakiś timer "biega" z innym zadaniem i można się do niego podczepić z obsługą drgań.

    Tutaj masz bardzo dobrą bibliotekę: http://mikrokontrolery.blogspot.com/2011/04/jezyk-c-biblioteka-obsluga-klawiatury.html
    Inne rozwiązania: http://mikrokontrolery.blogspot.com/2011/03/epp-drgania-stykow.html
    Przykład BlueDraco choć na STM: http://mikrokontrolery.blogspot.com/2011/02/o-drganiach-stykow-bez-bajek-przykad.html

    0
  • Pomocny post
    #14 17 Lis 2013 12:27
    BlueDraco
    Specjalista - Mikrokontrolery

    Ze sposobem mirekk36 to już na pewno nie będzie działać dobrze.

    Jeśli szukasz prostszego sposobu stwierdzenia wciśnięcia przycisku niż w dwóch linijkach kodu, to obawiam się, pe nie znajdziesz.

    0
  • #16 17 Lis 2013 14:08
    Tomq
    Poziom 38  

    Zastanawiam się czy to na pewno chodzi o drgania styków. Podlutowałem kondensatory 100nf między przyciski, a masę i program działa tak samo (mimo kombinowania z różnymi opóźnieniami).



    Dlaczego program wpisuje zera do tablicy (czego efektem jest zapalenie wszystkich diód)? Przecież przyciski są normalnie podciągnięte do zasilania (PORTD =0xff), więc jeśli program zapisałby do tablicy stan PIND w w chwili gdy puściłem przycisk i pojawiły się drgania to:
    -albo zapisałby drganie ze stanem niskim, czyli w tablicy występowałyby po sobie dwa takie same znaki (jeden pojawia się po wciśnięciu, drugi po zwolnieniu klawisza)
    -albo zapisałby drganie ze stanem wysokim, czyli żaden przycisk nie wciśnięty, a więc w tablicy byłaby wartość "0xFF", a nie "0"


    Postanowiłem to sprawdzić i zdefiniowałem tablice od razu ładując do niej:
    = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}

    i jest różnica. Efekt jest taki, że nadal podczas wyświetlania zawartości z tablicy kolejność zapalania się diód jest zła, ale w przerwach między poprawnymi wyświetleniami nie palą się wszystkie diody, tylko nie pali się żadna (wartość PORTB=0xff, czyli to co załadowane pierwotnie w tabeli). Czyli wychodzi na to, że te błędne wyświetlenia (zapalone wszystkie diody zamiast jednej) to był efekt tego, że w tablicy były zera. Teraz błędne wyświetlenie polega na tym, że wszystkie diody są zgaszone (bo domyślnymi wartościami w tablicy są 0xff, czyli zgaszone diody)


    Więc problemem jest chyba to, że
    - program nie odczytał wartości PIND, a już ją ładuje do tablicy,
    - albo program nie zdążył załadować odczytanej wartości z PIND, a już przeszedł do kolejnej iteracji.

    Może trzeba powalczyć z instrukcją asm volatile("nop"), zeby program mial chwile oddechu przed (po?) odczytaniem wartości PIND?
    Albo po zapisie testować, czy dana pozycja w tablicy jest różna od 0xff? Tzn jak program wykonując pętle ładuje stan PIND do tablicy, to zaraz po tym niech sprawdzi, czy na pewno po załadowaniu dana pozycja w tabeli jest inna niż wartość domyślna?



    Macie jakiś pomysł jak to ugryźć?


    Mimo wszystko za podrzucone linki dziękuję.

    0
  • Pomocny post
    #17 17 Lis 2013 20:20
    LED5W
    Poziom 32  

    Zwiększasz i, nawet gdy żaden przycisk nie został naciśnięty.
    Drugi if powinien być wewnątrz pierwszego. Na Twoim miejscu zapisałbym stan wejść przed pierwszym if, a w drugim sprawdził, czy jest taki sam.

    0
  • Pomocny post
    #18 18 Lis 2013 00:04
    dondu
    Moderator Mikrokontrolery Projektowanie

    Żeby na 100% nie było różnicy między badanymi stanami pinów podczas kolejnych badań oraz zapisu do rejestru, powinieneś tylko w jednym miejscu odczytać PIND i zapisać w zmiennej. Dopiero zmienną testować i gdy trzeba zapisać do tablicy.

    Sprawdź (pokaż) jak wygląda zawartość pliku .lss.


    Tomq napisał:
    Może trzeba powalczyć z instrukcją asm volatile("nop"), zeby program mial chwile oddechu przed (po?) odczytaniem wartości PIND?

    To jest istotny problem, ale tylko w przypadku, gdy w dwóch kolejnych instrukcjach wykonasz najpierw zapis stanu pinów X, a w drugiej odczyt pinów Y zależnych od stanów pinów X zapisanych wcześniejszą instrukcją.

    Przykładem może być klawiatura matrycowa. Ustawiasz nr wiersza i kolejną instrukcją odczytujesz kolumny - wtedy należy dodać NOP. Szczegóły: http://mikrokontrolery.blogspot.com/2011/04/jak-mikrokontroler-widzi-sygnal-cyfrowy.html?a

    0
  • Pomocny post
    #19 18 Lis 2013 07:46
    kchpl
    Poziom 14  

    Tomq napisał:
    Kod: c
    Zaloguj się, aby zobaczyć kod



    Witam
    Wg mnie to pętla for która indeksuje rejestr "biegnie" cały czas niezależnie czy coś nacisnąłeś czy nie i zwiększa adres stąd błędna kolejność (tak naprawdę to losowy adres zapisu) i "puste miejsca".
    Proponowałbym zwiększać adres po zapisie do tablicy wciśniętego przycisku oraz dodać if`a sprawdzającego przekroczenie adresu 8.
    np.
    if(porzycisk)
    {
    rejestr[adres]=przycisk;
    adres++;
    if(adres>7){adres=0;}
    }

    0
  • Pomocny post
    #20 18 Lis 2013 13:37
    tehaceole

    Poziom 28  

    Tomqu z podanych przeze mnie linków ściągnij przykład 04 i podmień w nim main.c na:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    oraz main.h na:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Jeżeli dysponujesz jakimś LCD to podłącz go (oraz Twoje wejścia i wyjścia) zgodnie z opisem zamieszczonym w pliku 00_CzytajToKodyAVR.txt
    Przykład działa (tylko że ja wyświetlam na LCD stany wejść zamiast sterować wyjściami), ale nie jest jeszcze zoptymalizowany żeby Ci już całkiem nie zaciemnić (choćby wyświetlanie tekstów z RAM zamiast z FLASH).

    Hasła do wujka Google: bufor kołowy, struktura, pole bitowe, tablica, enum, przekazywanie struktury lub tablic przez wskaźnik.

    Poczytaj na stronie Mirekk36 o stosowaniu buforów bo ma to przyjaźnie rozpisane.

    0
  • #21 18 Lis 2013 18:10
    Tomq
    Poziom 38  

    Dziękuje za odzew z Waszej strony. Naprawdę miło widzieć taką chęć pomocy.


    Zadziałał poniższy kod, niemniej wezmę też pod uwagę inne propozycję i je wypróbuje. Spróbuje też zrobić kod bardziej przejrzystym, np. zdefiniować wciśnięcie jakiegoś klawisza jako makro (poleceniem "#define"). Następnym krokiem będzie zapewne wyświetlanie zawartości tabeli na wyświetlaczu 7-segmentowym.
    tehaceole - posiadam wyświetlacz alfanumeryczny 2x16, ale jeszcze nie robiłem z nim żadnych prób i nie czuje się na siłach by go obsługiwać.


    Kod: c
    Zaloguj się, aby zobaczyć kod


    Tematu jeszcze nie zamykam, może ktoś będzie chciał jeszcze coś dodać, może ja jeszcze o coś dopytam. Jeszcze raz dziękuję za zainteresowanie i pomoc.\


    "*.lss" obecnego pliku:


    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #22 18 Lis 2013 18:14
    tehaceole

    Poziom 28  

    Tomq podpowiem Ci, że nie mając debuggera możesz sobie znacząco zabawę z uP ułatwić robiąc "debug" przy użyciu np. wyświetlacza albo uart. Po prostu wyświetlasz sobie wartość zmiennej jaka Cię interesuje i porównujesz jej wartość z założeniami działania danego fragmentu kodu.

    I przede wszystkim staraj się ZAWSZE doprowadzać do tego, aby po kompilacji nie było ani jednego warninga - te pozostawione same sobie w końcu zaczną żyć własnym życiem a wtedy na próżno szukać babola w kodzie.

    0
  • #23 18 Lis 2013 18:31
    Tomq
    Poziom 38  

    Cytat:
    Tomq podpowiem Ci, że nie mając debuggera możesz sobie znacząco zabawę z uP ułatwić robiąc "debug" przy użyciu np. wyświetlacza albo uart. Po prostu wyświetlasz sobie wartość zmiennej jaka Cię interesuje i porównujesz jej wartość z założeniami działania danego fragmentu kodu.

    Oczywiście, już zanim napisałem temat na forum pomyślałem "łatwiej by było gdybym mógł podejrzeć co się teraz dzieje tam w tablicy". Nie mówię, że nie chce mi się robić proponowanego przez Ciebie rozwiązania, po prostu nie czuje się jeszcze na siłach. O przekazywaniu tablic, strukturach, itp już sobie wydrukowałem materiały do poczytania, natomiast "enum" z tego co zauważyłem występuje raczej w "c++" niż w "c".

    Cytat:
    I przede wszystkim staraj się ZAWSZE doprowadzać do tego, aby po kompilacji nie było ani jednego warninga - te pozostawione same sobie w końcu zaczną żyć własnym życiem a wtedy na próżno szukać babola w kodzie.

    Fakt, zwykle ignorowałem warning o tym, że definiuje częstotliwość CPU w programie, ale właśnie znalazłem to: http://mikrokontrolery.blogspot.com/2011/03/fcpu-gcc-gdzie-definiowac.html i od teraz szybkość procesora określam w Makefile, a nie w kodzie. I od teraz absolutne zero warningów.

    0
  • #24 18 Lis 2013 19:48
    tmf
    Moderator Mikrokontrolery Projektowanie

    enum występuje i w c i w C++. Pamiętaj też, że w Atmel Studio masz symulator, nawet jeśli nie masz sprzętowego debuggera to kod możesz sobie zasymulować. Często wystarczy symulować nie cały kod (co jest pewną sztuką), lecz funkcję, która sprawia problemy. Dużo można się dzięki temu nauczyć.
    BTW, definiujesz F_CPU w makefile? Czy to znaczy, że piszesz sobie skrypt make, zamiast korzystać z jakiegoś sensownego IDE?

    0
  • Pomocny post
    #26 18 Lis 2013 21:24
    el2010tmp
    Poziom 25  

    Prościej by było zamiast:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    napisać:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #27 18 Lis 2013 23:19
    dondu
    Moderator Mikrokontrolery Projektowanie

    el2010tmp napisał:
    Prościej by było ...
    ...napisać:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Owszem, ale przy takich uproszczeniach po paru miesiącach przerwy zrozumienie programu będzie sprawiało problemy i zajmowało zbędny czas.
    Dlatego należy zrobić na przykład tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Do powyższych definicji można dodać także dodatkową definicję i zmienić warunek:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    ... lub dowolnie inaczej, ale na pewno nie tak jak proponujesz. Warto to robić, by łatwo, szybko i przyjemnie rozumieć co się napisało oraz wykorzystywać do innych projektów napisane wcześniej programy (znaczna oszczędność czasu).


    Tomq napisał:
    Korzystam z WinAvr. Nie piszę od nowa skryptu, zmodyfikowałem na swoje potrzeby ten przykładowy z programu i skopiowałem do katalogu wynikowego z programem.

    Zamiast tego przesiądź się na oryginalne narzędzia Atmela czyli AVR Studio lub Atmel Studio:
    http://mikrokontrolery.blogspot.com/2011/04/kompilator-i-srodowisko-programistyczne.html
    które automatycznie wykonują makefile i co najważniejsze zawsze poprawnie :)

    0
  • #28 20 Lis 2013 17:50
    el2010tmp
    Poziom 25  

    dondu napisał:
    el2010tmp napisał:
    Prościej by było ...
    ...napisać:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Owszem, ale przy takich uproszczeniach po paru miesiącach przerwy zrozumienie programu będzie sprawiało problemy i zajmowało zbędny czas.
    Dlatego należy zrobić na przykład tak:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Do powyższych definicji można dodać także dodatkową definicję i zmienić warunek:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    ... lub dowolnie inaczej, ale na pewno nie tak jak proponujesz. Warto to robić, by łatwo, szybko i przyjemnie rozumieć co się napisało oraz wykorzystywać do innych projektów napisane wcześniej programy (znaczna oszczędność czasu).


    Tomq napisał:
    Korzystam z WinAvr. Nie piszę od nowa skryptu, zmodyfikowałem na swoje potrzeby ten przykładowy z programu i skopiowałem do katalogu wynikowego z programem.

    Zamiast tego przesiądź się na oryginalne narzędzia Atmela czyli AVR Studio lub Atmel Studio:
    http://mikrokontrolery.blogspot.com/2011/04/kompilator-i-srodowisko-programistyczne.html
    które automatycznie wykonują makefile i co najważniejsze zawsze poprawnie :)


    :D
    A ja sądziłem że ta konstrukcja jest zbyt rozwlekła... :D :D :D
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #30 14 Gru 2013 21:22
    Tomq
    Poziom 38  

    Cytat:
    Tak to jest, kiedy nie sprawdza się stanu przycisków w przerwaniu timera...


    Wracam do tematu, bo zrobiłem własny projekt zamka na szyfr z wykorzystaniem klawiatury szesnastkowej i czterech siedmiosegmentowych wyświetlaczy. Wszystko ładnie działa, tylko napisałem obsługę klawiatury z wykorzystaniem delayów, wiec widać, że słoma z butów nieco wystaje. Poczytałem o timerach i zmodyfikowałem nieco kod, proszę więc o sprawdzenie poprawności nowego kodu i ewentualnie dalsze sugestie.

    Korzystałem z :
    http://mikrokontrolery.blogspot.com/2011/02/o-drganiach-stykow-bez-bajek-przykad.html
    https://www.elektroda.pl/rtvforum/topic2358423.html


    Kod obsługi klawiatury szesnastkowej - stara wersja na delayach:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Obecnie obsługa przycisku, bez delayów, za to z timerem wygląda tak (tylko dwa przykładowe przyciski):
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Drugi sposób, oparty na timerach na pewno działa, bo krótkie przyciśniecie przycisku nie zmienia wyświetlanej cyfry. Właściwie ten kod realizuję funkcje wyświetlania cyfry nie w reakcji na wciśniecie przycisku, ale w reakcji na przytrzymanie go przez określony czas.



    EDIT:
    Tu nieco inne podejście. Program działa tak: testuje czy flaga programowa (tu: zmienna a) i jednocześnie przycisk jest wciśnięty, jeśli tak to zeruje flagę i zwiększa licznik "b". Jeśli b doliczył do 3, to wtedy dopiero jest wyświetlana cyfra na wyświetlaczu.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Widzę jednak, że powinno to działać odwrotnie. Zaraz po wykryciu pierwszego wciśnięcia powinna się wyświetlić cyfra. Druga rzecz, to chyba muszę użyć tu tablicy, żeby wpisywać do niej naciśnięcia klawisza, a potem je odczytać, żebym mógł sprawdzić, czy na pewno zostały zapisane w takiej kolejności w jakiej się pojawiły.

    0