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

Ponownie problem generatora na ATmega8

19 Cze 2006 20:57 1504 3
  • Poziom 26  
    Witam po raz sto pierwszy.

    Stali bywalcy elektrody pewnie mają już dosyć tych tematów (i mnie zapewne też :D), ale powróciłem do tego zagadnienia.

    Żeby nie było, poświęciłem dwa dni na szperaniu po elektrodzie w poszukiwaniu postów o tej tematyce; znalazło się troche (oj troche :)), ba...nawet znalazłem kod źródłowy w C/C++ który co prawda kompilował mi się ale po zflaszowaniu procesora nic sie nie "odzywało", jednakże po "wgraniu" gotowego skompilowanego przez kogoś *.hex'a procesor działał bardzo dobrze, tzn. dioda led (ta jakże nieszczęsna) migała z częstotliwością 1Hz (co sprawdzałem na dłuzszych okresach czasu...i nic sie nie późniła :)).

    Jednakże niekompilujący siękod nie daje mi spokoju. Kod jest autorstwa użytkownika VSS i wygląda następująco:

    (jest to co prawda jakiś soft do wyświetlacza, ja jednak wykorzystałem tylko port PD0, który generuje częstotliwość 1Hz, linijkę tę pogrubiłem)





    VSS napisał:
    /*
    zegar.c - firmware for simple digital clock based on AVR ATmega8, designed for VSS from pl.misc.elektronika
    Copyright (C) 2006 Dariusz Rzońca

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    */

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/sleep.h>

    unsigned char godzina[6];//godzina[0] - jednostki sekund, godzina [5] - dziesiatki godzin
    const unsigned char tablica_7seg[]={0x08,0x6E,0x84,0x24,0x62,0x30,0x10,0x6C,0x00,0x20};//wyglad cyfr na wyswietlaczu
    /* Połączenie:
    Segmenty: ( najpierw nóżka, potem segment)
    3 A
    4 F
    5 G
    6 B
    11 E
    12 D
    13 C
    */
    const unsigned char tablica_multipleks[]={0x1F,0x3E,0x3D,0x3B,0x37,0x2F};//[0] - baza sterujaca wyswietlaniem jednostek sekund,
    /* Połączenie:
    Anody: (najpierw nózka, potem kolejna cyfra)
    23 5
    24 4
    25 3
    26 2
    27 1
    28 6
    */
    unsigned char aktualny_wyswietlacz;
    unsigned int czesci_sekundy;

    SIGNAL (SIG_OUTPUT_COMPARE2)//512 razy na sek
    {
    if (++czesci_sekundy==512)
    {
    czesci_sekundy=0;
    godzina[0]++;//minela sekunda
    if (bit_is_clear(PINB,PINB0))
    {
    godzina[0]=0;//zerowanie sekund
    godzina[1]=0;
    }
    if (bit_is_clear(PINB,PINB1)) godzina[2]++;//ustawianie minut
    if (bit_is_clear(PINB,PINB2)) godzina[4]++;//ustawianie godzin
    if (godzina[0]==10)//przepelnienie jednostek sekund
    {
    godzina[0]=0;
    godzina[1]++;
    }
    if (godzina[1]==6)//przepelnienie dziesiatek sekund
    {
    godzina[1]=0;
    godzina[2]++;
    }
    if (godzina[2]>=10)//przepelnienie jednostek minut
    {
    godzina[2]-=10;
    godzina[3]++;
    }
    if (godzina[3]==6)//przepelnienie dziesiatek minut
    {
    godzina[3]=0;
    godzina[4]++;
    }
    if (godzina[4]>=10)//przepelnienie jednostek godzin
    {
    godzina[4]-=10;
    godzina[5]++;
    }
    if (godzina[5]==2 && godzina[4]==4)//przepelnienie 24h
    {
    godzina[4]=0;
    godzina[5]=0;
    }
    }
    if (++aktualny_wyswietlacz==6) aktualny_wyswietlacz=0;
    PORTC=0x3F;//wygaszamy wszystkie wyswietlacze
    PORTD=tablica_7seg[godzina[aktualny_wyswietlacz]];//przygotowywujemy cyfrę
    PORTC=tablica_multipleks[aktualny_wyswietlacz];//wlaczamy odpowiedni wyswietlacz
    if (czesci_sekundy>=256) PORTD|=_BV(PD0);//miganie diodą na PD0
    }

    int main (void)
    {
    DDRC=_BV(PC0)|_BV(PC1)|_BV(PC2)|_BV(PC3)|_BV(PC4)|_BV(PC5);
    DDRD=_BV(PD0)|_BV(PD1)|_BV(PD2)|_BV(PD3)|_BV(PD4)|_BV(PD5)|_BV(PD6)|_BV(PD7);
    PORTB=_BV(PB0)|_BV(PB1)|_BV(PB2);//pullup klawiatura
    ASSR=_BV(AS2);//t2 - praca asynchroniczna
    TCNT2=0;
    OCR2=7;
    TCCR2=_BV(WGM21)|_BV(CS21);//CTC, preskaler 8
    while (ASSR&(_BV(TCN2UB)|_BV(OCR2UB)|_BV(TCR2UB)));//czekamy na zapisanie zmian
    TIMSK=_BV(OCIE2);//przerwanie od porównania
    sei();
    set_sleep_mode(SLEEP_MODE_PWR_SAVE);//sleep to dla nas power save
    while(1) sleep_mode();
    return(0);
    }



    Teraz przedstawie własną uroczą działalność, którą zapożyczyłem od Otulaka (być może tu znanego):

    Kubbaz napisał:

    #include <avr/io.h>

    /******************************************************

    Definicje stałych

    *******************************************************/

    #define F_CPU 1000000 /* 1MHz zegar procesora */

    #define CYCLES_PER_US ((F_CPU+500000)/1000000) /* cpu cycles per microsecond */


    /**************************************************************

    Koniec definicji stałych

    **************************************************************/



    //definiujemy stany portu sterującego diodą LED

    #define LED_ON sbi(DDRD,PD0);sbi(PORTD,PD0)

    #define LED_OFF sbi(DDRD,PD0);cbi(PORTD,PD0)

    // Piszemy procedury opóźnienia czasowego

    void delay(unsigned int us)

    {

    unsigned int delay_loops;

    register unsigned int i;

    delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)

    for (i=0; i < delay_loops; i++) {};

    }

    void delayms(unsigned int ms)

    {

    unsigned int i;

    for (i=0;i<ms;i++)

    {

    delay(999);

    asm volatile (

    "WDR"::);

    }

    }

    int main (void)

    {

    for (;;)

    {

    LED_ON;

    delayms(1000);

    LED_OFF;

    delayms(1000);

    }



    return (0);

    }


    Powyższy kod w przeciwieństwie do kodu użytkownika VSS kompiluje mi się i procesor działa wg algorytmu, lecz generator jest do KITU !!

    Szczerze powiem, że nie wiem do czego służą te dwie linijki kodu:

    #define F_CPU 1000000 /* 1MHz zegar procesora */

    #define CYCLES_PER_US ((F_CPU+500000)/1000000) /* cpu cycles per microsecond */

    To że opisane są jako: 1MHz zegar procesora i cpu cycles per microsecond , to rozumiem; mam na myśli ich znaczenie dla procesora; jakiś wirtualny "kwarc", timer czy co ...??

    Oto mój schemat programatora i jedej diody LED podłączonej w obwód.

    Ponownie problem generatora na ATmega8

    W związku z powyższym proszę o poradę jak zmodyfikować powyższy kod, tak aby pracował on z kwarcem zegarkowym (32,768kHz), a mikrokontroler odmierzał dokładnie czas.


    Za wszelką pomoc z góry serdecznie dziękuję i pozdrawiam. Kubbaz.

    P.S. Jeśli czegoś nie dopowiedziałem, a chcecie wiedzieć piszcie.
  • Serwerowe OpowieściSerwerowe Opowieści
  • Poziom 33  
    To nie kwestia modysfikacji kodu, a właściwego ustawienia fuse bitów, tak aby procesor wykorzystywał zewnętrzny kwarc. Domyśle AVRy mają włączony rezonator wewnętrzny 1MHz.
    Na forum było mnóstwo wątków na temat ustawiania fuse bitów, jest to też dobrze opisane w manuala uC.

    Przy okazji - odmierzanie czasu w ten sposób zawsze będzie obarczone błedami i to całkiem sporymi. Zwróć uwagę, że w gónym programie do odmierzania czasu jest użyte przerwanie tajmera, a nei licznei pętli.
  • Serwerowe OpowieściSerwerowe Opowieści
  • Poziom 26  
    Tdv napisał:

    Przy okazji - odmierzanie czasu w ten sposób zawsze będzie obarczone błedami i to całkiem sporymi. Zwróć uwagę, że w gónym programie do odmierzania czasu jest użyte przerwanie tajmera, a nei licznei pętli.


    a użtkownik VSS pisze:

    VSS napisał:
    Przez tydzień spóźniał sie o około 1 sekundę w stosunku do DCFa


    Więc o co chodzi?? Jak dla mnie 1 sekunda tygodniowo by w zupełności wystarczyła :D.

    A co do manuala uC, to poszperam w nim.
  • Poziom 33  
    No ale napisałem, że ten program wyżej używa do odmierzania czasu przerwania od tajmera.
    To jest licznik sprzętowy, który odlicza z góry zaprogramowaną liczbę impulsów i po ich odliczeniu powoduje skok programu do odpowiedniego miejsca w programie, wykonanie ustalonych zadań, po czym procesor wrca do roboty, którą robił przed przerwaniem. Z zasady działania jest to dosyć dokładna forma mierzenia czasu. Dosyć dokładna, nei znaczy super dokładna ;-D.
    Część programu odpowiedzialna za odmierznie czasu (właśnie ten program, który wykonuje procesor po załoszeniu od licznika sprzętowego) zaczyna się od:
    Code:

      SIGNAL (SIG_OUTPUT_COMPARE2)