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.

ATMEGA88 - Program wykonuje tylko przerwanie

czolgowy 05 Lut 2013 20:46 2187 19
  • #1 05 Lut 2013 20:46
    czolgowy
    Poziom 10  

    Witam,

    Mam problem z programem, który powinien wyświetlać 4 cyfry na wyświetlaczach 7led (multiplex), po naciśnięciu przycisku powinien zliczać od 0 do 9 i wyświetlać takie same cyfry na każdym wyświetlaczu.... niestety nie reaguje na przycisk... wygląda jakby program wykonywał tylko przerwanie, wyświetla "0000",

    ATMEGA88, 8 MHz na wewnętrznym oscylatorze,

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Elektrycznie wszystko jest ok, bo jak wgram poniższy program, wszystko jest ok, tzn. zliczanie od 0 do 9 i wyświetlanie na pojedynczym segmencie 7led.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod

    0 19
  • Pomocny post
    #3 05 Lut 2013 21:32
    dondu
    Moderator Mikrokontrolery Projektowanie

    Witaj,

    O volatile kolega słyszał?
    Jeśli nie, to czas poczytać: http://mikrokontrolery.blogspot.com/2011/04/problemy-c-volatile.html

    Stosuj nowe funkcje obsługi przerwań ISR(), tym bardziej, że używasz nowe ich wektory: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

    0
  • #4 05 Lut 2013 21:47
    mickpr
    Poziom 39  

    dondu napisał:
    O volatile kolega słyszał?
    No tak, o tym zapomniałem.
    Ale że pętla lata z "full speed" napisałem...

    0
  • #6 05 Lut 2013 21:55
    mickpr
    Poziom 39  

    dondu napisał:
    ak na wszelki wypadek wyjaśniam, że pisałem to do autora tematu, a nie do Ciebie
    Wiem, napisałem niestylistycznie.

    0
  • #7 06 Lut 2013 10:23
    BlueDraco
    Specjalista - Mikrokontrolery

    switch(w) nie ma sensu, bo w każdym case jest to samo. Nawet jak już zmienisz to tak, żeby wyświetlało 4 różne cyfry, to i tak będzie to coś typu PORTD = c[cyfra[i]];

    Konstrukcja switch służy do robienia różnych rzeczy w zależności od wartości danej, a nie do robienia zawsze tego samego z różnymi danymi.

    0
  • #8 06 Lut 2013 20:05
    czolgowy
    Poziom 10  

    Witam i dziękuję za bardzo szybkie odpowiedzi !

    Po kolei...

    dondu napisał:
    Witaj,

    O volatile kolega słyszał?
    Jeśli nie, to czas poczytać: http://mikrokontrolery.blogspot.com/2011/04/problemy-c-volatile.html

    Stosuj nowe funkcje obsługi przerwań ISR(), tym bardziej, że używasz nowe ich wektory: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html


    ano słyszał.... tylko szukałem w nie tam gdzie trzeba, tzn nie sądziłem, że problem jest w definicji zmiennych, a szukałem problemu w obsłudze przerwnia.....już po poście na forum doczytałem o zmianie na ISR, ale też nie pomogło :)

    BlueDraco napisał:
    switch(w) nie ma sensu, bo w każdym case jest to samo. Nawet jak już zmienisz to tak, żeby wyświetlało 4 różne cyfry, to i tak będzie to coś typu PORTD = c[cyfra[i]];

    Konstrukcja switch służy do robienia różnych rzeczy w zależności od wartości danej, a nie do robienia zawsze tego samego z różnymi danymi.


    switch(w) jest "przygotowany" pod wyświetlanie różnych cyfr, ale ja wolę dodawać funkcje po kolei, bo potem nie wiem co nie działa....

    Teraz program wygląda tak:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Teraz zlicza od 0 do 9999 po przytrzymniu przycisku... tak wiem, że delay za mały, ale do testów jest ok, przy delayu 100+ za wolno nalicza :)

    Teraz sekundnik, potem wyświetlanie temperatury itd...

    0
  • #9 06 Lut 2013 20:30
    BlueDraco
    Specjalista - Mikrokontrolery

    Masz błąd w procedurze wyświetlania - na wyświetlaczu będzie widać "duchy" sąsiednich cyfr.

    Gdybyś zamiast zmiennych s1, s1, s10 zrobił tablicę, mógłbyś wywalić switch, tak, jak Ci to pokazałem wyżej:
    PORTD = c[cyfra[i]];

    Twoja pętla główna ciągle zamienia liczbę na cyfry, a wystarczy zrobić to jeden raz po zmianie wartości.

    Tablicy c nie ma sensu deklarować jako volatile, za to jest sens zadeklarować ją jako const, a naljepiej const PROGMEM, z sięganiem do niej przez prog_read_byte().

    Zmienna w powinna być zadeklarowana w funkcji obsługi przerwania timera jako static.

    Zmienna sek powinna być zadeklarowana w main jako static.

    0
  • #10 07 Lut 2013 18:29
    pbuhne
    Poziom 14  

    Piszesz to w C ? Bo widzę ze dałeś syntax C++...

    A kolega wie jaki rozmiar w systemie 8-bitowym ma integer? Jak tam się ma zmieścić 1000 czy nawet 10000?

    Jeśli C to druga sprawa, używasz zmiennych niezainicjowanych (np. int i; , a potem robisz i++;) widzę ze kompilator gcc się nie czepia, ale np MS już tak. Nigdy nie ma pewności co pod ta zmienna jest, przed użyciem, wiec dobrze by było zmienne od razu inicjować (przypisać wartość) np. int i = 0; a potem i++; tak bynajmniej mnie uczono i się do tego stosuje.

    W takiej pętli while, jak Ty masz to program praktycznie non-stop czeka w delay:
    przechodzi przez 2 ify i w delaya, i tak w kolko.... Dołącz tego delaya do ifa. Zresztą :

    Kod: c
    Zaloguj się, aby zobaczyć kod


    po dwa razy robisz s10 i s100 po co? Pomijam już ze to liczby 8-bitowe ;)

    Jak już to zrób:

    s1000 = (sek / 1000) % 10;
    s100 = (sek/100) % 10;
    s10 = (sek/10) % 10;
    s1 = sek % 10;

    Oczywiście na zmiennych o odpowiednim rozmiarze np uint16_t lub int16_t :)

    To tyle rad od początkującego ;)

    0
  • #11 07 Lut 2013 20:17
    czolgowy
    Poziom 10  

    BlueDraco napisał:
    Masz błąd w procedurze wyświetlania - na wyświetlaczu będzie widać "duchy" sąsiednich cyfr.


    Faktycznie :) a ja myślałem, że to wina "przydługich" przewodów na płytce stykowej i laptop sieje, albo zasilacz laptopa, które są w biskiej odległości....

    Czyli najpierw zaświecić segment, ustawić cyfrę i zgasić segment ?

    BlueDraco napisał:

    Gdybyś zamiast zmiennych s1, s1, s10 zrobił tablicę, mógłbyś wywalić switch, tak, jak Ci to pokazałem wyżej:
    PORTD = c[cyfra[i]];


    Prawdę mówiąc na moim poziomie zaawansowania nie bardzo trybię co masz na myśli....

    BlueDraco napisał:

    Twoja pętla główna ciągle zamienia liczbę na cyfry, a wystarczy zrobić to jeden raz po zmianie wartości.


    Dać to do if'a, tam gdzie i++ ?


    Kod: c
    Zaloguj się, aby zobaczyć kod


    Prawdę mówiąc zerżnąłem to z jakiegoś forum o programowaniu jako algorytm rozbicia liczby na cyfry...

    pbuhne napisał:
    A kolega wie jaki rozmiar w systemie 8-bitowym ma integer? Jak tam się ma zmieścić 1000 czy nawet 10000?


    a wg kursu, którym się posługuję to int ma 0...65535, lub -32k.. +32k.., tzn 16 bit, więc już sam nie wiem...

    0
  • #12 07 Lut 2013 20:54
    BlueDraco
    Specjalista - Mikrokontrolery

    Najpierw zgasić poprzednią cyfrę, potem wystawić nowe segmenty, potem uaktywnić nową cyfrę.

    Co mam na myśli - to dokładie Ci napisałem. Zamiast zmiennych s1, s100 itd. trzymaj to, co w nich jest w kolejnych elementach tablicy cyfry. Np.

    cyfry[3] = sek / 1000;
    cyfry[2] = sek % 1000 / 100;
    cyfry[1] = sek % 100 / 10;

    I wyrzucasz bezsensowny switch z obsługi wyświetlania.

    Tak, konwersję rób wtedy, gdy zmieniacz wartość sek.

    Tak zapisana konwersja, jaką masz w tej chwili jest błędna (to, co podałem wyżej jest ok), bo próbujesz przechowywać w s100, która ma 8 bitów, liczbę z zakresu 0..999.

    0
  • #13 07 Lut 2013 21:09
    pbuhne
    Poziom 14  

    Wielkość Integera zależy od systemu, np 32bit ma na PC (Windows 32), na atmega 8 bit. Ten kurs to pewnie jakiś na PC ?

    Z tym zrzynaniem to nie polecam, lepiej zrobić coś swojego, prostszego od zera, niż przepisywać coś, czego nie rozumiemy.

    Polecam stronę kolegów z forum: Link Jest tam kurs C, sporo dobrych rad na początek.

    0
  • #14 07 Lut 2013 21:18
    BlueDraco
    Specjalista - Mikrokontrolery

    pbuhne: typ int wg standardu C musi mieć min. 16 bitów - i tyle ma na AVR. Tutaj problem nie jest z int, a z użyciem zmiennych 8-bitowych jako tymczasowych do obliczeń na int.

    0
  • #15 07 Lut 2013 21:56
    pbuhne
    Poziom 14  

    Musze sprostować swoją wypowiedź, rzeczywiście, BlueDraco ma rację int na AVR ma 16 bitów, mój błąd wyniknął z tego że użyłem uint8_t u siebie i tym się zasugerowałem.

    Tak więc, poprawa, int na AVR ma 16 bitów.

    Przepraszam za wprowadzenie w błąd.

    0
  • #16 09 Lut 2013 20:20
    czolgowy
    Poziom 10  

    Co do kursów, to kożystam z kilku...

    Pozmieniałem conieco, ale doszedłem to tego, że na każdym segmencie wyświetla mi tą samą cyfrę od 0 do 9. Kiedy zaczynam manipulować z tablicą cyfra[...] przy przeliczaniu wszystko się wykrzacza... a chciałbym, żeby liczyło do 9999.




    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • Pomocny post
    #17 09 Lut 2013 20:53
    pbuhne
    Poziom 14  

    Parę uwag do przerwania:

    Kod: c
    Zaloguj się, aby zobaczyć kod



    Wyświetlanie multipleksowe polega na tym, że:

    wystawiasz 1. wartość (znak)
    aktywujesz 1. segment
    gasisz 1. segment

    wystawiasz 2. wartość (znak)
    aktywujesz 2. segment
    gasisz 2. segment

    itd... Bo jeśli wystawisz 1. , aktywujesz segment 1 a potem zmienisz wartość na 2. i aktywujesz 2. seg. to masz zapalone oba i oba pokazują wartość 2.

    W jednej chwili może się świecić jeden segment.

    Weź na początek ustaw sobie liczbę na jakąś konkretną np 2473 (żeby każda była inna) i spróbuj to wyświetlić.

    No i to "rozdzielanie na cyfry" nadal jest błędne:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Podaliśmy Ci już wcześniej sposób na to rozdzielenie.

    0
  • Pomocny post
    #18 10 Lut 2013 13:04
    BlueDraco
    Specjalista - Mikrokontrolery

    1. Po pierwsze nie "na każdym segmencie", a "na każdej pozycji". Wyżwietlacz jednej cyfry składa się z siedmiu segmentów, dlatego nazywa się "siedmiosegmentowym".
    Wyświetla Ci to samo, bo tak kazałeś w programie:
    cyfra[3] = sek % 10; //tysiace
    cyfra[2] = sek % 10; //setki
    cyfra[1] = sek % 10; //dziesiatki
    cyfra[0] = sek % 10; //jednosci
    - na czterech pozycjach zapisujesz to samo.

    2. PORTD ^= PORTD to to samo co PORTD=0, tylko wolniej i bardziej pokrętnie

    0
  • #19 13 Mar 2013 14:41
    czolgowy
    Poziom 10  

    Ok, nie mam za dużo czasu na hobby... dlatego taka zwłoka na odpowiedź.
    Wygląda na to, że wszystko działa... zlicza do 9999 i się zeruje.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    A teraz pytanie: gdybym chciał dodać drugi przycisk i zliczanie w dół do 0000, to jak skonstruować warunek i typ zmiennej "sek" ?

    Kod: c
    Zaloguj się, aby zobaczyć kod
    ??

    0
  • Pomocny post
    #20 13 Mar 2013 16:27
    BlueDraco
    Specjalista - Mikrokontrolery

    No mniej-więcej... Jakoś zadziała chyba.
    Ja bym napisał:
    if (!sek)
    sek = 10000;
    sek --;

    albo:
    if (!(sek --))
    sek = 9999;

    Wtedy sek może mieć typ bez znaku, bo nigdy nie przyjmie wartości ujemnej, która byłaby z czymś porównywana.

    0