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

Problem z komunikacją SPI.

slaweks86 05 Sie 2010 12:31 1799 6
REKLAMA
  • #1 8367272
    slaweks86
    Poziom 11  
    Witam, mam problem z komunikacją SPI na Atmega8. Zrobiłem chyba wszystko jak należy, ale dalej nie działa. Poniżej zamieszczam kody dla Mastera i Slavea.

    ======= M A S T E R =========
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #define DD_MOSI PINB3
    #define DD_SCK PINB5
    #define DD_MISO PINB4
    #define DDR_SPI PORTB
    
    void SPI_MasterInit(void)
    {
    	DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
    	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
    }
    
    void SPI_MasterTransmit(char cData)
    {
    	SPDR = cData;
    	while(!(SPSR & (1<<SPIF)))
    	{
    	}
    }
    
    int main()
    {
    	char litera='a';
    
    	DDRD=0x40; //PIND6 podlutowany jest do PINB2, czyli SS Slave'a
    	
    	SPI_MasterInit();
    	PORTD=0x00; //wysłanie 0 na SS i rozpoczęcie transmisji
    	SPI_MasterTransmit(litera);
    	PORTD=0x40; //zakończenie transmisji czyli wysłanie 1
    }
    


    ============ S L A V E ==============
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #define DD_MOSI PINB3
    #define DD_SCK PINB5
    #define DD_MISO PINB4
    #define DD_SS PINB2
    #define DDR_SPI PORTB
    
    void wait(int i)  //pętla spowalniająca
    {
        int k, j;
        for (k=0;k<i;k++) { for (j=0; j < 10;j++);}
    }
    void SPI_SlaveInit(void)
    {
    
    	DDR_SPI=(1<<DD_MISO);
    	SPCR=(1<<SPE);
    }
    
    char SPI_SlaveReceive(void)
    {
    
    	while (!(SPSR & (1<<SPIF))) //dopóki nie odbierze danych to dioda miga szybko
    	{
    		PORTD=0x00;
    		wait(400);
    		PORTD=0x80;
    		wait(400);
    	}
    
    	return SPDR;
    }
    
    int main()
    {
    	char dane;
    
    	DDRD=0x80; //dioda podpięta do PD7
    
    	SPI_SlaveInit();
    
    	dane=SPI_SlaveReceive();
        
    	if(dane=='a') 
    	{
    	while(1) { PORTD=0x80;} //jeżeli odbierze dane to dioda ma się świecić
    	}
    	else
    	{
    		while(1) //jeżeli odbierze dane, które się nie zgadzają 
    				 //z wysyłanymi to dioda miga wolno
    		{
    		PORTD=0x00;
    		wait(2000);
    		PORTD=0x80;
    		wait(2000);
    		}
    	}
    }
    


    Do Slavea mam podłączoną diodę, która informuje mnie w jakim stanie się znajdujemy. Efektem jest jej ciągłe szybkie miganie, czyli tak jakby czekała na odebranie danych. Co może być nie tak? Może ktoś ma gotowy program który obsługuje transmisję SPI i działa, czyli taki sprawdzony?
  • REKLAMA
  • #2 8369625
    ginar
    Poziom 21  
    Przy założeniu, że sprzęt jest ok spróbuj zainicjalizować nadajnik Master wg:

    void SPI_MasterInit(void)
    {
       DDRB|=1<<PB2;
       PORTB |=1<<PB2;
       DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
       SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
    } 
  • REKLAMA
  • REKLAMA
  • #4 8371010
    slaweks86
    Poziom 11  
    zmiana kodu nic nie dała. Dalej dioda w slave miga szybko czyli cały czas coś odbiera, ale nie wiem co, bo jak podłączyłem diodę do mastera to tam wykonuje się cały program, czyli inicjacja mastera, przesyłanie danych (nie wiem czy dobrych) i program się kończy... Może ktoś to już napisał w C i ma działający kod to byłbym bardzo wdzięczny..

    proszę o pomoc:)
  • REKLAMA
  • #5 8371595
    rpal
    Poziom 27  
    Dioda to koledze miga pewnie dlatego że w rejestrze odbiorczym SPI nie ma żadnego odebranego znaku i program pracuje bez przerwy w pętli dotąd aż coś odbierze a nie odbiera nic. Wywal te miganie z programu głownego i zobaczysz co się dzieje tan naprawę. Poza tym tak naprawdę do nie wiadomo co ty tam obierasz bo masz zastosowane potężne opóźnienia nawet jak coś w tzw. międzyczasie przyjdzie do odbiornika to kolejny bajt danych zostanie zastąpi to co już zdążyłeś odebrać. Wszystko przez te zwłoki czasowe. Najprędzej masz złe połączenia z nadajnikiem i stąd kłopoty. Przy takim sposobie testowania nigdy nie będziesz wiedział z jakiej okazji miga tobie ta dioda. Lepiej ją po prostu na stałe zapalać z chwilą odbioru i kasować np. przez naciśnięcie przycisku.
  • #6 8383767
    slaweks86
    Poziom 11  
    tak też zrobiłem jak napisałeś ale nic z tego. Wywaliłem opóźnienia. Nie wiem tylko o co chodzi z tym zastępowaniem danych. U mnie master tylko raz wysyła dane i slave tylko raz odbiera. Zgodnie z kodem źródłowym wyżej.
  • #7 8601179
    percol
    Poziom 12  
    Na początek powinno być:
    
    #define DDR_SPI DDRD
    


    zamiast:
    
    #define DDR_SPI PORTB
    


    Kolejna uwaga: staraj się pisać programy nie wpisując wartości dla wszystkich pinów portu! Stan wysoki na wybranym pinie łatwo osiągniesz np. tak:
    PORTD|=0xF0; // dla pinów PD4, PD5, PD6 i PD7 

    albo tak:
    PORTD|=((1<<PD5)|(1<<PD1)); // piny PD5 i PD1 

    Stan niski uzyskasz w ten sposób:
    PORTD&=~(0x07); // dla pinów PD0, PD1 i PD2 

    Piszę o tym, bo nigdy nie wiadomo czy przypadkiem czegoś nie masz na jakimś pinie a co mogłoby utrudniać zlokalizowanie potencjalnego błędu, zwłaszcza w bardziej skomplikowanym programie.
    Tutaj szczęśliwie nie powinno być żadnych problemów pod warunkiem, że niewykorzystywane nóżki (porty) nie są wejściami, ewentualnie zwarte są do masy (przez oporniki np. 2k albo większe) tudzież do plusa - nieważne, muszą tylko mieć stan ustalony.

    Kolejny tip:
    Ustaw na Masterze najwolniejszy transfer, a więc zamiast:
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
    wstaw:
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPR1);
    - może pomóc gdy taktujesz Atmegę wewnętrznym oscylatorem (który jest wolny i dosyć niestabilny! => jeśli dwie Atmegi tak pracują, zwłaszcza na fosc/4, mogą pojawić się błędy w komunikacji). Co prawda w programie masz fosc/16 ale co szkodzi spróbować na najwolniejszej fosc/128?
    Jeśli już na takim żółwiu nie ruszy to znaczy, że gdzieś jest poważny błąd!

    Piszesz:
    Cytat:
    U mnie master tylko raz wysyła dane i slave tylko raz odbiera. Zgodnie z kodem źródłowym wyżej.

    A to nie do końca jest prawda! Slave owszem wpada w pętle nieskończoną świecenia/migania ale Master NIE! Program skończy swe działanie i Bootloader załaduje go od nowa...

    Jeśli na pokładzie masz kwarc/rezonator - włącz go (fuse bity).

    Acha, zamiast własnych pętli opóźniających możesz użyć gotowych (_delay_us() i _delay_ms() - zwłoka w mikrosekundach i w milisekundach odpowiednio) i skalibrowanych z pliku nagłówkowego <util/delay.h>, jedyne co musisz zrobić to tylko (wcześniej) zdefiniuj częstotliwość pracy procesora, np.:
    
    #define F_CPU 12000000UL // 12MHz dla kwarcu, 1MHz dla wewn. oscylatora
    


    Kolejna sprawa (najważniejsze na końcu;), ale to PODSTAWA!
    Sprawdź koniecznie jakość ścieżek między mikrokontrolerami (omomierzem dotykaj do połączonych nóżek obu scalaków, opór powinien być minimalny! Grubo poniżej 1 oma inaczej coś może trzeszczeć/niełączyć = zakłócenia/wadliwe działanie!).

    Powodzenia!
REKLAMA