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

[C] ATmega8+zewn. ADC(MCP3202) z SPI nieprawidłowe działanie

adam cs 01 Kwi 2010 18:15 4887 23
  • #1 7907977
    adam cs
    Poziom 14  
    Witam.
    Myślę że ten dział najbardziej to tego pasuje ale jeśli moderator ma inne zdanie to proszę o przeniesienie ale niekasowanie:)
    Postaram się opisać wszystko najdokładniej jak mogę.
    Otóż zakupiłem taki układzik jest to przetwornik analogowo-cyfrowy (SAR) z interfejsem SPI, tutaj test jego datasheet:Link
    Na początku powiem, że dziesiątki razy szukałem w googlach ale nic nie znalazłem co mogło by mi pomóc może poza tym :link
    W tym układziku nóżka od zasilania jest referencją jednocześnie.
    Podłączam go deo ATmegi w taki sposób:
    [C] ATmega8+zewn. ADC(MCP3202) z SPI nieprawidłowe działanie
    Od razu mowię że ten schemat to tak na szybko żeby tylko zobrazować podłączenie między dwoma układami

    Kod do uc taki:
    
    #include<avr/io.h>
    #include<util/delay.h>
    #include "HD44780.c"
     int odb0=0;
     int odb1=0;
     int odb2=0;
     int suma=0;
    char i=0;
    void Inicjacja_spi()
    {
        DDRB |= ( 1 << PB5 ) | ( 1 << PB3 ) | ( 1 << PB2 );              //MOSI, SCK, SS' jako wyjścia
        SPCR = ( 1 << SPE ) | ( 1 << MSTR ) | ( 1 << SPR1 ) | ( 1 << SPR0 );   //Włączamy SPI,    
    }                                                                               //układ Master, najmniejsza częstotliwość SCK fosc / 128
    
    
    void Wyslij_spi(char bajt)
    {	
        SPDR = bajt;                    //Wysyłamy zawartość zmiennej bajt   
        while( ! bit_is_set( SPSR, SPIF ) );
    			//Oczekujemy na zakończenie transmisji ( do ustawienia SPIF ) przez sprzęt
    
    
    } 
    
    
     
    
    int main()
    {	
    	char buffer_n[5];
    	DDRB &=0xef;// MISO jako wejscie
    	int dana0=0x9f;// bajt z konfiguracją 
    	int dana1=0xff;
    	
    	DDRB |=0x01;
    	PORTB &=0xfe;
    	LCD_Initalize();
        char bajt = 0;
        Inicjacja_spi();
    	
        while(1)                //Pętla nieskończona
        {	
    		
    		
    		PORTB &=0xfb;// ustaw stan niski na linii ss czyli zezwól na przesył
            Wyslij_spi(dana0);// wyslij pierwszy bajt z konfiguracja
    		odb0=SPDR;// to co przyszło przypisz do zmiennej
    		odb0=(odb0<<9);// przesun o 9 w lweo bo to sa 3 najstarsze bity wyniku 12 bitowego
    		Wyslij_spi(dana1);// wyslij cokolwiek
    		odb1=SPDR;//to co przyszło przypisz do zmiennej
    		odb1=(odb1<<1);// przesun w lewo o 1 bo to są bity 8..1( bez LSB)
    		Wyslij_spi(dana1);//to co przyszło przypisz do zmiennej
    		odb2=SPDR;// tutaj będzie juz tylko LSB konwersji
    		PORTB |=0x04;// teraz  ustaw stan wysoki na linii ss czyli zablokuj przesył
    		suma=(odb2+odb1)+odb0;// zsumuj wszystko
    		
    		
    		utoa(suma, buffer_n, 10); // zamień na string
    		LCD_WriteText(buffer_n);// wyswietl
    		
            _delay_ms(5);
    		        
    		LCD_Clear(); 
            
            
        }
        return 0;
    }
    



    Zrobiłem sobie taki dzielnik rezystorowy , 4rezystory po 560 Ohm
    dla zera pokazuje 0
    dla 1,24 V:
    [C] ATmega8+zewn. ADC(MCP3202) z SPI nieprawidłowe działanie

    ale już dla 2.48 V:
    [C] ATmega8+zewn. ADC(MCP3202) z SPI nieprawidłowe działanie

    podobnie dla 3,73 V:
    [C] ATmega8+zewn. ADC(MCP3202) z SPI nieprawidłowe działanie

    Siedziałem wczoraj większość nocy nad tym i nie mogę dojść końca , z tego wszystkiego mogę stwierdzić jedynie tyle że przetwornik jako tako działa bo im wyższe napięcie dam na wejście tym większa liczba jest wyświetlana,ale wyniki są bardzo niestabilne poza tym jak mi pokazuje wynik na wyświetlaczu to nie zauważyłem skakania najmniej znaczącej cyfry ALE za to zmieniają się setki jak by było coś sknocone przy tym całym przesuwaniu i sumowaniu bajtów może coś pominięte może coś za dużo nie wiem dużo rzeczy mi przychodzi do głowy i dużo już próbowałem po prostu to wszystko razem nie działa jak powinno , dlatego proszę was drodzy forumowicze o sprawdzenie kodu i schematu może o czymś zapomniałem co dla dla was może być oczywiste . to jest moja pierwsza styczność z SPI.
    Jeśli coś jest nie jasne proszę pisać postaram się rozjaśnić .
    Byłbym niezmiernie wdzięczny za jakąkolwiek pomoc.
    Pozdrawiam .
  • #2 7912182
    super_noise
    Poziom 12  
    Proponuję psrawdzić, czy dobrze działa Ci SPI, za pomocą Oscyloskopu ew. Analizatora stanów logicznych.
  • Pomocny post
    #3 7912660
    rpal
    Poziom 27  
    Kolego ten scalak jest na tyle mało skomplikowany że MUSI działać albo masz błedy w połączeniach albo w programie. Ni ebaw się w żaden monitoring linii SPI bo to przerost formy nad treścią. Jak zewrzesz MISO do masy to po odczytaniu rejestru będziesz miał ciagle 0 jak z plustem bez przerwy 1 tyle ci starczy aby stwierdzić po poprawność działania SPI. Zastanawiło ciebie może źródło napięcia odniesienia, nie pamiętam dokładnie czy ten przetwornik ma już je wbudowane czy używa zewnętrznego ale tak na wyrost to 5v od zasilacza nie jest dobrym pomysłem na to i lepiej użyć wyspecjalizowanych układów z napięciem np. 4,01V
    Popatrzyłem w notę katalogową i jest tak jak pisałem, pilnuj częstotliwości zegara aby nie przekroczyć 1,8 MHz, odkłócaj układ kondensatorami (tantal!), a programowanie proste jak drut. Pierwszy bajt wysłanych danych niesie na pierwszym bicie (1) początek konwersji, drugi na 3 najstarszych bitach informacje programujące przetwornik jednocześnie zwracając MSB przetworzonych danych, trzeci to już LSB danych po konwersji. Twój problem wynika tak sądzę z pływającego napięcia odniesienia ale ta informacja jest jak wół napisana w nocie lub z zakłóceń od zasilania albo ze zbyt wysokiej częstotliwości na magistrali SPI.
  • #4 7920337
    adam cs
    Poziom 14  
    Wielkie dzięki kolego rpal, teraz transmisja przebiega prawidłowo tzn konwersja jest prawidłowo odczytywana, pozostaje mi tylko problem zakłóceń bo jak mierze napięcie regulując heltrimem to wyniki są prawidłowo odczytywane, tylko że w niektórych momentach pojawiają się losowe liczby.
    Ponieważ układ nie jest jeszcze samodzielnym urządzeniem to całość pracuje jako połączenie płytki stykowej z płytką testową z atmegą na pokładzie.
    Otóż zauważyłem że jak zbliże (niekoniecznie dotknę ) palce do przewodów typu MISIO , MOSI , SCK to wariuje jeszcze bardziej.
    A 1,8 MHz napewno nie przekroczyłem bo przy kwarcu 8MHz mam podział ustawiony 'przez 128' co zresztą widać w kodzie.
    Przewody połączeniowe mam tak z 5-10 cm (luźno w powietrzu, nie na płytce ) kondensatory odsprzęgające są(przy nóżkach takich jak gnd, agnd, avcc, vcc).
    Więc w czym problem ? jakoś w UARCIE i I2C nie miałem tych problemów.
    Oczywiście można by wykonać płytkę drukowaną gdzie połączenia między tymi scalakami były by wręcz minimalne ale przecież po to są płytki stykowe żeby testować układy czyż nie tak?
  • Pomocny post
    #5 7920385
    rpal
    Poziom 27  
    Nie miałem okazji testowac tego na tzw. pająkach ponieważ od razu robiłem gotowe PCB, jak się poczyta o przetwornikach A/DC to zawsze istotną sprawą jest prowadzenie masy dla takich układów gdzie producent wręcz podaje przykład jak ją wykonać, więc może z tego powodu to wariuje. W ogóle to masz podłączone masy i zasilasz to ze wspólnego zasilania ? To banalne pytanie ale ludzie popełniają różne gafy. Napięcie odniesienia zrobiłeś jak trzeba czy pozostałeś przy 5V ? W ogóle to dobrze jest uważnie czytac noty bo wiele niespodzianek tam czeka. Podam ci przykład kiedyś użyłem wyspecjalizowanego układu właśnie jako napięcie odniesienia. Wsadziłem kondensatory taakie jakie miałem pod ręką i okazało się że nie uzyskałem prawidłowego napięcia. Jakoś nie chciało mi się zawracać głowy tantalami a był to warunek konieczny do prawidłowego działania. Więc jeszcze raz powtórzę odkłócaj tak jak zalecił producent czyli ceramiczny+ tantal. Jak konstrukcja będzie OK wóczas możesz szukać błędów w programie lub w połączeniach. Aha, w nocie jest zaznaczone jak szybko można ponawiać kolejne próbkowanie. Te przetworniki nie należą do szybkich ale za to są tanie, Analog Device albo Burr Brown robi zdecydowanie szybsze ale i pieniądze tam są inne. Tak przy okazji to jak ty to programujesz bo jak masz programator szeregowy to nie powinieneś tego układu w ogóle zaprogramować bez wyjmowania przetwornika a co z połaczeniem programatora podczas pracy, jest czy nie ma ?
  • #6 7923793
    adam cs
    Poziom 14  
    Problem zakłóceń już rozwiązany okazało się (wstyd przyznać że nie pomyślałem o tym) że trzeba dodać rezystory podciągające( 10 KOhm) na liniach komunikacyjnych teraz o zakłóceniach niema mowy.

    W najbliższym czasie( jako podsumowanie) dodam prawidłowy kod i schemat połączeń , być może komuś się przyda .(dlatego proszę o nieblokowanie tematu)

    Pozdrawiam
  • #7 7931587
    adam cs
    Poziom 14  
    To jest prawidłowy kod oczywiście z przykładową konfiguracją przetwornika:
    
    #include<avr/io.h>
    #include<util/delay.h>
    #include "HD44780.c"
     int odb0=0;
      int odb1=0;
     int odb2=0;
     int suma=0;
    char calosci=0;
    int reszta=0;
    void Inicjacja_spi()
    {
        DDRB |= ( 1 << PB5 ) | ( 1 << PB3 ) | ( 1 << PB2 );              //MOSI, SCK, SS' jako wyjścia
        SPCR = ( 1 << SPE ) | ( 1 << MSTR ) | ( 1 << SPR1 ) | ( 1 << SPR0 );   //Włączamy SPI,    
    }                                                                               //układ Master, najmniejsza częstotliwość SCK fosc / 128
    
    
    void Wyslij_spi(char bajt)
    {	
        SPDR = bajt;                    //Wysyłamy zawartość zmiennej bajt   
        while( ! bit_is_set( SPSR, SPIF ) );
    			//Oczekujemy na zakończenie transmisji ( do ustawienia SPIF ) przez sprzęt
    
    
    } 
    
    
     
    
    int main()
    {	
    	char buffer_n[5];
    	DDRB &=0xef;// MISO jako wejscie
    	int dana0=0x01;// bajt z konfiguracją 
    	int dana1=0x00;// bajt nieznaczący
    	int dana2=0x00;//jw
    	DDRB |=0x01;// do RW wyświetlacza
    	PORTB &=0xfe;// stan niski
    	LCD_Initalize();
        char bajt = 0;
        Inicjacja_spi();
    	
        while(1)                //Pętla nieskończona
        {	
    		odb0=5;
    	while(odb0)
    	{
    		PORTB &=0xfb;// ustaw stan niski na linii ss czyli zezwól na przesył/////////////////////////
            Wyslij_spi(dana0);// wyslij pierwszy bajt z konfiguracja
    		
    		Wyslij_spi(dana1);// wyslij cokolwiek
    		odb1=SPDR;//to co przyszło przypisz do zmiennej
    	
    		Wyslij_spi(dana2);//to co przyszło przypisz do zmiennej
    		odb2=SPDR;// tutaj będzie juz tylko LSB konwersji
    		
    		PORTB |=0x04;// teraz  ustaw stan wysoki na linii ss czyli zablokuj przesył//////////////////
    		odb1=(odb1<<8);// przesuń te cztery najstarsze bity w lewo 
    		suma=suma+(odb1+odb2);
    		odb0--;
    		}
    		suma=suma/6;
    		reszta=suma%100;
    		calosci=suma/100;
    		utoa(calosci, buffer_n, 10); // zamień na string
    		LCD_WriteText(buffer_n);LCD_WriteText(",");
    		utoa(reszta, buffer_n, 10);
    		LCD_WriteText(buffer_n);
    		
    		
    		
    		_delay_ms(10);
    		
            
    		LCD_Clear(); 
            
            
        }
        return 0;
    }


    Filmik przedstawiający działanie czyli adc mierzy napięcie na dzielniku 1:10 a równolegle przed dzielnikiem podpięty multimetr :




    Schematu już nie przedstawiam gdyż jako napięcie odniesienia zastosowałem lm317, linie komunikacyjne podciągnąłem rezystorami do masy, wszystko połączone kabelkami , kondensatory zwykłe czyli elektrolit+ceramik.
    Oczywiście jak będzie czas to wpakuje to gdzieś żeby był jakiś pożytek np jako multimetr do zasilacza zrobię płytkę dam jakieś stabilne źródło ref. lepsze kondensatory itp czyli już bez fuszerki:)
    zauważyłem że chociaż nie zastosowałem ani dedykowanego źródła Uref ani kondensatorów tantalowych czy mkt to odczyty są jakby dziwnie stabilne a mierzę napięcie zasilacza a nie np z baterii czy z alumulatora może to jest właśnie cecha przetwarzania SAR ...
    Co ciekawe...
    Mogę tak wyregulować Uref że w zakresie 0-20V w 95% odczyty będą się pokrywać z wskazaniami multimetru +-0.01V , a w niektórych przypadkach różnica wyniesie ok 0.05 V. Coś jakby znaleść taki bardzo mały przedział napięcia mierzonego np 2-2.005 V że np w ICL-u zmiany będą o 1mV a w MCP o 4mV .
    Dlatego dołozyłem pętlę w programie mającą na celu uśrednić wynik ale praktyczne bez zmian.Cos jakby ch-ka przetwarzania w nielicznych przedziałach była troszeczkę odkształcona.
    Ale nie żeby to był kolejny problem tylko tak podałem jako ciekawostkę bo to mnie troszkę zastanowiło:)
    Pozdrawiam:)
  • #8 7932110
    super_noise
    Poziom 12  
    Cytat:
    Schematu już nie przedstawiam gdyż jako napięcie odniesienia zastosowałem lm317, linie komunikacyjne podciągnąłem rezystorami do masy...


    Pytanie: linie SPI masz podciągnięte do zasilania?

    Pozdrawiam,
    SNoise
  • #9 7932187
    rpal
    Poziom 27  
    Tak przy okazji to po co wam w ogóle podciąganie tych linii do masy czy zasilania? Gdzie te mądrości wyczytaliście ?
  • #10 7932241
    adam cs
    Poziom 14  
    super_noise napisał:


    Pytanie: linie SPI masz podciągnięte do zasilania?

    SNoise


    No właśnie mi chodzi o linie SPI . Więc do każdej linii podpiąłem rezystor "sciągający" do masy.


    A co do tych mądrości to gdzieś w google znalazłem kawałek schematu, zrobiłem tak samo no i zakłóceń nie ma - proste:)
  • #11 7933292
    rpal
    Poziom 27  
    Trochę to dziwne rozwiązanie bo w żadnej nocie nie opublikowane. Jako CS której linii kolega używa może SS?
  • #12 7933722
    super_noise
    Poziom 12  
    Dla mnie "podciąganie do masy" w samej nazwie już jest podejrzanie w elektronice cyfrowej.

    Ja stosuję podciąganie przez rezystor do zasilania (dokładnie takie samo jak w schemacie rezystor R3 - pullup dla !CS) ze względu na ograniczoną wydajność prądową portów uC oraz ze względu na pojemność linii transmisyjnej (długie kable).

    Przeglądałem pobieżnie notę MCP3202 i za żadne skarby nie mogłem znaleźć informacji jakiego rodzaju są tam zastosowane wejścia/wyjścia układu związane z interfejsem SPI. Jeżeli jest to otwarty dren lub kolektor to jesteśmy w domu.
  • #13 7935075
    rpal
    Poziom 27  
    Wyjście jest na bank trójstanowe, a wejście nie ma nic do rzeczy. Istotne jest CS bo tam muszą być ustalone lednoznaczne stany logiczne. Jak już musisz podciągać to do plusa i na tym właśnie wejściu. Absolutnie nie na MISO,MOSI lub SCK.
  • #14 7976434
    sony_1000
    Poziom 12  
    Witam,

    Ogólnie idea pomiaru jest jasna (opis tematu i kodu bardzo czytelny). Jedynie nie mam pojęcia skąd wiedziałeś jak interpretować/przeskalować wynik z przetwornika?
    Dostajesz w wyniku z przetwornika 2 bajty. Pierwszy bajt zawiera 3 nie znaczące bity, które defakto możemy programowo sobie wyzerować + bit stopu i reszta Twoich danych. Drugi bajt zawiera same dane.
    No i te moje nieszczęsne pytanie - skąd wiadomo jak zinterpretować te dane (gdzie stawić przecinek)? W jakich jednostkach podawany jest wynik?
  • #15 7976631
    rpal
    Poziom 27  
    kol.sony jak interpretować wynik i gdzie postawić przecinek wynika z noty katalogowej gdzie jest podany wręcz wzór na obliczenie. rodzielczoś *napięcie odniesienia czyli 4096*v. Jeśli napięcie odniesienia jest 4,1 V to wówczas wartość w postaci cyfrowej wacha się od 0 do 4,096 V i jest dokładnym odzwierciedleniem jako liczba w 2 bajtach danych uzyskanych na linii SO(MISO).W przypadku innego napięcia odniesienia inny jest zakres napięcia wejściowego przetwornika.
  • #16 7976763
    sony_1000
    Poziom 12  
    Witam,
    po raz pierwszy używam zewnętrznego przetwornika stąd moje właśnie pytanie.
    No i dziękuję za naprowadzenie na odpowiedź.

    Dla potomności:
    W nocie jak byk - sekcja 4.2 Digital Output Code (DOC)- wzór:

    DOC = (4096*Vin)/Vdd
    zatem:
    Vin = (DOC*Vdd)/4096 V
  • #17 7977423
    rpal
    Poziom 27  
    masz razję kolego tak jest w istocie, rozdzielczoś przetwornika to 12 bit, zatem dokładność pomiaru wynosi 0,001 V przy napięciu odniesienia 4,1 V i o taką wartość może zmieniać się wychodzące na wyjściu przetwornika dane. Tak jest w nocie więc pytanie które wcześniej zadałeś znając ten wzór jest cokolwiek bez sensu, Czy zgodzisz się z tym ?
  • #18 7978312
    sony_1000
    Poziom 12  
    Cytat:
    Tak jest w nocie więc pytanie które wcześniej zadałeś znając ten wzór jest cokolwiek bez sensu, Czy zgodzisz się z tym ?


    Przyznam, że trochę nie rozumiem teraz


    Cytat:
    No i te moje nieszczęsne pytanie - skąd wiadomo jak zinterpretować te dane (gdzie stawić przecinek)? W jakich jednostkach podawany jest wynik?


    Może wyjaśnię jeszcze raz.
    Używam przetwornika bardzo podobnego do tego w temacie. Notę katalogową przestudiowałem x razy jednak akapit, który wyjaśnia całość pomijałem
    (sam nie wiem dlaczego).
    Przetwornik po konwersji dawał mi jakąś wielką liczbę i nie wiedziałem
    jak ją przeskalować by otrzymać napięcie. Z kodu zamieszczonego przez autora tematu nie mogłem wywnioskować na jakiej zasadzie przeskalowywany jest wynik, więc uznałem, że jest zasada jakaś, która mówi, że stawia się przecinek w odpowiednie miejsce (lub coś w ten dieseń).
    Dlatego po prostu zapytałem - a Twoja odpowiedź - naprowadziła mnie na ten wzór i wtedy wszystko zrozumiałem.
    Mam nadzieję, że wyjaśniłem mój tok rozumowanie.
  • #19 7980438
    rpal
    Poziom 27  
    teraz tak , nie przeczytałeś po prostu tego jak się ma napięcie odniesienia do odczytanej wartości wystawionej na wyjściu danych ot tyle, a wzór to wyjaśniał :)
  • #20 8570926
    pawelko111
    Poziom 12  
    Witam szanownych kolegów!!!
    Mam podobny problem, tyle tylko ze pojawia się dobry wynik, po czym jakieś głupoty kilka odczytów, po czy znów dobry wynik i tak to leci!!!
    Moje pytanie, jakie najlepiej dać te kondensatory odkłócające? tantalowe o pojemności? między nóżkami gnd i vcc, a masą układu?
  • #21 8573856
    rpal
    Poziom 27  
    te pytanie jest poniżej pasa, w DS stoi jak wół jakie mają być kondensatory (tantalowe) a także sposób prowadzenia masy oraz zasilanie napięciem odniesienia. Wystarczy ino poczytać.
  • #22 8578613
    pawelko111
    Poziom 12  
    Witam serdecznie!!!
    Próbując wykorzystać kod kolegi z tego wątku natknąłem się na coś takiego.

    
     reszta=suma%100; 
     calosci=suma/100;
    


    Problem jest w tym, że jeśli będziemy mieć liczbę np. 305 to
    reszta wynosi "5", a całości "3". Wyświetlając to poźniej
    dostaniemy "3,5", a nie "3,05" jak powinno być.

    Także, w ten sposób nie można tego wyświetlać.

    Pozdrawiam
  • #23 8579659
    rpal
    Poziom 27  
    kol. pawełek
    305%10=5
    305/10=30
    30%10=0
    30/10=3
    3%10=3
    i reszta z dzielania potem dzielenie liczby aż ta liczba osiągnie 0
    teraz jasne ?
  • #24 8581516
    pawelko111
    Poziom 12  
    Witam
    Jasne jak słońce, należy to zrobić w pętli albo inny sposób bardziej pamięcio chłonny - wykorzystać sprintf.
    Chodziło mi tylko o to, że kod przewodni tego wątku ma pewne "błędy".

    Dzięki pozdrawiam serdecznie
REKLAMA