• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Niedziałający program przetwornika ADC Atmega8

VPS Starter Arubacloud
0 głosów
375 wizyt
pytanie zadane 12 marca 2022 w Mikrokontrolery przez Mavimix Dyskutant (8,390 p.)
zamknięte 16 marca 2022 przez Mavimix

Mam taki fragment kodu:

volatile float d = 0;
volatile bool myFlag = false;

void adcInit()
{
    ADMUX |= (1 << REFS0) | (1 << REFS1) | (1 << MUX2) | (1 << MUX0);
    ADCSRA |= (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}

int main(void)
{
    uartInit();
    adcInit();
    sei();

    DDRC &= ~(1 << PC5);

    while (1)
    {
        MCUCR |= (1 << SM0) | (1 << SE);
        ADCSRA |= (1 << ADSC);
        MCUCR = 0x00000000;

        if (myFlag)
        {
            char str[8] = {0};
            sprintf(str, "%d.%02u", (int)d, (int)((d - (int)d) * 10000));

            for (int i = 0; i < 8; i++)
            {
                print_char(str[i]);
            }

            d = 0;
            print_newLine();
            myFlag = false;
        }
        _delay_ms(1000);
    }
}

ISR(ADC_vect)
{
    d = 0.002490234375 * ADC;
    //d = (ADCH * 256 + ADCL) * 2.56 / 1024;
    myFlag = true;
}

Napięcie które mierze ma 1,582V (zmierzone miernikiem, napięcie biorę z dzielnika napięcia, który jest podłączony do zasilania (5V) i masy układu), natomiast na terminalu pojawia się wartość w okolicach 1,2 - 1,3V i ciągle skacze nawet +- 0,2V i po prostu się nie zgadza z tym co jest w rzeczywistości. Kondensatory i dławik mam podpięte wg. datasheetu, dodatkowo zewnętrzny kwarc. Ponadto gdy zakomentuję linię w przerwaniu i odkomentuję w ten sposób:

//d = 0.002490234375 * ADC;
d = (ADCH * 256 + ADCL) * 2.56 / 1024;

To wyświetla się jedna wartość cały czas i nawet jak wejście ADC podepnę do masy to dalej ta wartość się pojawia, jakby ADC się zawieszał.

W czym jest problem, że pomiar tak skacze i się nie zgadza, a w drugim przypadku w ogóle się "zawiesza"?

komentarz zamknięcia: Jak w komentarzu
komentarz 13 marca 2022 przez Oscar Nałogowiec (29,290 p.)
W 6 i chyba 7 linii raczej powinno być zwykłe podstawienie a nie |=.
komentarz 13 marca 2022 przez Mavimix Dyskutant (8,390 p.)
Jak zmieniłem |= na = to problem dalej występuje.
komentarz 13 marca 2022 przez Oscar Nałogowiec (29,290 p.)

Ta główna pętla trochę jeszcze dziwnie wygląda. Ustawiasz ADSC (start przetwarzania) i dwie instrukcje dalej oczekujesz, że już flaga zakończenia jest ustawiona. Tam powinna być pętla oczekiwania na myFlag. Konwersja ADC trwa dość długo.

Nie bardzo rozumiem też tej zabawy z MCUCR.

komentarz 13 marca 2022 przez Mavimix Dyskutant (8,390 p.)

Poprawiłem w ten sposób:

volatile float d = 0;
volatile bool myFlag = false;
 
void adcInit()
{
    ADMUX |= (1 << REFS0) | (1 << REFS1) | (1 << MUX2) | (1 << MUX0);
    ADCSRA |= (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}
 
int main(void)
{
    uartInit();
    adcInit();
    sei();
 
    DDRC &= ~(1 << PC5);
 
    while (1)
    {
        MCUCR |= (1 << SM0) | (1 << SE);
        ADCSRA |= (1 << ADSC);

        //KOMENTARZ
        //MCUCR = 0x00000000;
 
        //OCZEKUJACY WHILE ZAMIAST IF
        while (!myFlag);

            char str[8] = {0};
            sprintf(str, "%d.%02u", (int)d, (int)((d - (int)d) * 10000));
 
            for (int i = 0; i < 8; i++)
            {
                print_char(str[i]);
            }
 
            d = 0;
            print_newLine();
            myFlag = false;

        _delay_ms(1000);
    }
}
 
ISR(ADC_vect)
{
    //ZMIANA
    unsigned int l = ADCL;
    unsigned int h = ADCH;
    d = (h * 256 + l) * 2.56 / 1024;
    //d = 0.002490234375 * ADC;
    myFlag = true;
}

Błąd z zawieszaniem się ADC zniknął, natomiast na terminalu dalej bzdury są. Jeżeli chodzi o MCUCR to docelowo chciałem wprowadzić uC w tryb uśpienia dla ADC, wierząc iż jest to geneza problemu.

komentarz 13 marca 2022 przez Oscar Nałogowiec (29,290 p.)

Wygląda lepiej.

Jeśli chodzi o sleep:

To enter any of the six sleep modes, the SE bit in MCUCR must be written to logic one and a SLEEP instruction must be executed.

Czyli te wszystkie rejestry jedynie ustalają co ma być uśpione, właściwy tryb uśpienia następuje w trakcie wykonania instrukcji SLEEP (assemblerowa). Na pewno jest jakaś funkcja/makro w C, która wykonuje taką instrukcję.

Mam też wątpliwości co do twojego sposobu wypisania wyniku. %02d wypisze "00" jak dostanie 1, "05" jak dostanie 5 ale "500" jak dostanie 500. Mnożysz przez 10000 (linia 30), ale wymuszasz wyświetlenie co najmniej 2 cyfr. Chyba powinno być 5 cyfr.

Jak dostaniesz 1.0001 wyświetlisz 1.01.

8-bitowy odczyt musi być wykonany w kolejnośc ADCL, ADCH - teraz tak masz, poprzednio nie było to pewne.

 

komentarz 13 marca 2022 przez Mavimix Dyskutant (8,390 p.)
edycja 13 marca 2022 przez Mavimix

W linii 22 dodałem:

sleep_enable();
sleep_cpu();
sleep_disable();

I poprawiłem linię 30 na:

sprintf(str, "%d.%05u", (int)d, (int)((d - (int)d) * 100000));

Dalej nie działa. Może to być kwestia zasilania? Zasilam układ programatorem z USB więc może w tym jest problem? Bo software'owo już nie mam pojęcia co jest nie tak, oprócz tych niuansów. Już nawet inną Atmege próbowałem i nic.

komentarz 13 marca 2022 przez Oscar Nałogowiec (29,290 p.)
Może opisz dokładniej co nie działa. Przetwornik ADC zawsze da trochę pływający wynik, uniknięcie tego wymagałoby zastosowania super - precyzyjnych elementów, płytek itp. 10 bitów to dokładność 0.1%.  Na wszelki wypadek wypisuj dodatkowo bezpośrednie wartości odczytane z ADC, będziesz wiedział jak błąd wygląda "u źródła".

Mierniki cyfrowe stosują inne przetworniki - z podwójnym całkowaniem - ich wynik jest dokładnie, analogowo uśredniany przez czas równy okresowi sygnału w sieci zasilającej (50Hz - 20ms) co eliminuje zakłócenia od zasilania. Jeśli chcesz zminimalizować zakłócenia, zasilaj układ z baterii/akumutorka z analogowym stabilizatorem (jeśli będzie potrzebny). Mierniki zawsze mają baterie... Przetwornik w Atmedze to przetworniki z aproksymacją bitową (SAR) i układem sample-hold - mierzy wartość bardzo chwilową.

Uśredniać można oczywiście programowo.
komentarz 16 marca 2022 przez Mavimix Dyskutant (8,390 p.)
Problemem okazał się rezonator, który podpiąłem zbyt długimi kablami. Kiedy przyłączyłem go jak najbliżej pinów wszystko pięknie działa. Dzięki za pomoc.

Podobne pytania

0 głosów
1 odpowiedź 221 wizyt
pytanie zadane 24 marca 2016 w C i C++ przez Mavimix Dyskutant (8,390 p.)
0 głosów
1 odpowiedź 288 wizyt
pytanie zadane 30 marca 2022 w Mikrokontrolery przez Mavimix Dyskutant (8,390 p.)
0 głosów
2 odpowiedzi 685 wizyt
pytanie zadane 6 lutego 2020 w Mikrokontrolery przez Mavimix Dyskutant (8,390 p.)

92,453 zapytań

141,262 odpowiedzi

319,088 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...