Skocz do zawartości

[C] Komunikacja SPI między jednym master, a dwoma slave.


Pomocna odpowiedź

No tak jest gdzieś problem.

Slave1 nie dobiera danych a slave 2 wyświetla wartość 66. A tak przerobiłem program:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd.h"

#define MASTER 1   //jeżeli master to 1, jeżeli slave to 0
#if MASTER ==1

#define MOSI PB5
#define MISO PB6
#define SCK PB7
#define CS1 PB3
#define CS2 PB4
#define CS1_0 PORTB &= ~(1<<CS1)
#define CS1_1 PORTB |= (1<<CS1)
#define CS2_0 PORTB &= ~(1<<CS2)
#define CS2_1 PORTB |= (1<<CS2)

void InitSpiMaster(void);
uint8_t TransferSpi1(uint8_t byte);
uint8_t TransferSpi2(uint8_t byte);

int main(void) {
   DDRC |= (1 << PC1);
   PORTC |= (1 << PC1);
   lcd_init(); //inicjalizacja wyświetlacza
   InitSpiMaster();//inicjalizacja SPI
   lcd_locate(1, 0);
   lcd_str("master");

   while (1) {

       CS1_0;
       TransferSpi1('A');
       CS1_1;

       CS2_0;
       TransferSpi2('B');
       CS2_1;

   }

}

void InitSpiMaster(void) {
   CS1_1;
   CS2_1;
   //ustawienie kierunku wyjściowego dla linii MOSI, SCK i CS
   DDRB |= (1 << MOSI) | (1 << SCK) | (1 << CS1) | (1 << CS2);
   DDRB &= ~(1<<MISO);
   // aktywacja  SPI, tryb pracy Master, prędkość zegara Fosc/64
   SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1);

}
// definicja funkcji odbioru bajy

uint8_t TransferSpi1(uint8_t byte) {
   SPDR = byte;
   while (!(SPSR & (1 << SPIF)));
   return SPDR;
}
   uint8_t TransferSpi2(uint8_t byte) {
       SPDR = byte;
       while (!(SPSR & (1 << SPIF)));
       return SPDR;
   }

#endif

   //-----------------------------SLAVE

#if MASTER == 0

#define MOSI PB5
#define MISO PB6
#define CS1 PB4

   void InitSpiSlave(void);
   uint8_t TransferSpi(uint8_t byte);

   int main(void) {

       DDRC |= (1 << PC1); //Podświetlenie LCD
       PORTC |= (1 << PC1);
       lcd_init(); //inicjalizacja wyświetlacza
       InitSpiSlave(); // inicjalizacja SPI dla slave
       lcd_locate(1, 0);
       lcd_str("Slave 1"); //wyświetlenie napisu

       while (1) {
       	uint8_t bajt_o;
           bajt_o = TransferSpi(0);

           lcd_locate(0, 0);
           lcd_str("O:");
           lcd_int(bajt_o);
       }

   }

   void InitSpiSlave(void) {
       // ustawienie kierunku wyjściowego dla linii MOSI
       DDRB |= (1 << MISO);
       DDRB &= ~(1<<CS1) & ~(1<<MOSI);
       // aktywacja  SPI, tryb pracy SLAVE,
       SPCR |= (1 << SPE);
   }

   // definicja  funkcji wysyłającej bajt
   uint8_t TransferSpi(uint8_t byte) {

       SPDR = byte;
       while (!(SPSR & (1 << SPIF)));

       return SPDR;

   }

#endif

[ Dodano: 15-06-2013, 15:24 ]

Już działa nie wiem sam co zrobiłem ale wysyła do jednego dane i do drugiego. Tylko że slave1 dziwnie się zachowuje. Jak wpisałem w master żeby wysłał 123 to ostatnia cyfra się zmieniała 127,125,123, różnie losowo. zamieniłem kolejność funkcji TransferSpi z jeden na dwa to samo. Zawsze ten środkowy ma jakiś nie stabilny stan. A drugi slave nie, cały czas trzyma wysyłaną wartość. Czym to może być spowodowane?

aktualny kod:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd.h"

#define MASTER 1   //jeżeli master to 1, jeżeli slave to 0
#if MASTER ==1

#define MOSI PB5
#define MISO PB6
#define SCK PB7
#define CS1 PB4
#define CS2 PB3
#define CS1_0 PORTB &= ~(1<<CS1)
#define CS1_1 PORTB |= (1<<CS1)
#define CS2_0 PORTB &= ~(1<<CS2)
#define CS2_1 PORTB |= (1<<CS2)

void InitSpiMaster(void);
uint8_t TransferSpi1(uint8_t byte);
uint8_t TransferSpi2(uint8_t byte);

int main(void) {
   DDRC |= (1 << PC1);
   PORTC |= (1 << PC1);
   lcd_init(); //inicjalizacja wyświetlacza
   InitSpiMaster();//inicjalizacja SPI
   lcd_locate(1, 0);
   lcd_str("master");

   while (1) {

       CS1_0;
       TransferSpi2(123);
       CS1_1;
_delay_ms(100);

       CS2_0;
       TransferSpi1(234);
       CS2_1;

   }

}

void InitSpiMaster(void) {
   CS1_1;
   CS2_1;
   //ustawienie kierunku wyjściowego dla linii MOSI, SCK i CS
   DDRB |= (1 << MOSI) | (1 << SCK) | (1 << CS1) | (1 << CS2);
   DDRB &= ~(1<<MISO);
   // aktywacja  SPI, tryb pracy Master, prędkość zegara Fosc/64
   SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1);

}
// definicja funkcji odbioru bajy

uint8_t TransferSpi1(uint8_t byte) {
   SPDR = byte;
   while (!(SPSR & (1 << SPIF)));
   return SPDR;
}
   uint8_t TransferSpi2(uint8_t byte) {
       SPDR = byte;
       while (!(SPSR & (1 << SPIF)));
       return SPDR;
   }

#endif

   //-----------------------------SLAVE

#if MASTER == 0

#define MOSI PB5
#define MISO PB6
#define CS1 PB4

   void InitSpiSlave(void);
   uint8_t TransferSpi(uint8_t byte);

   int main(void) {

       DDRC |= (1 << PC1); //Podświetlenie LCD
       PORTC |= (1 << PC1);
       lcd_init(); //inicjalizacja wyświetlacza
       InitSpiSlave(); // inicjalizacja SPI dla slave
       lcd_locate(1, 0);
       lcd_str("Slave 1"); //wyświetlenie napisu

       while (1) {
       	uint8_t bajt_o;
           bajt_o = TransferSpi(0);

           lcd_locate(0, 0);
           lcd_str("O:");
           if (bajt_o !=0 )
           lcd_int(bajt_o);
           else lcd_str("err");
       }

   }

   void InitSpiSlave(void) {
       // ustawienie kierunku wyjściowego dla linii MOSI
       DDRB |= (1 << MISO);
       DDRB &= ~(1<<CS1) & ~(1<<MOSI);
       // aktywacja  SPI, tryb pracy SLAVE,
       SPCR |= (1 << SPE);
   }

   // definicja  funkcji wysyłającej bajt
   uint8_t TransferSpi(uint8_t byte) {

       SPDR = byte;
       while (!(SPSR & (1 << SPIF)));

       return SPDR;

   }

#endif

W przypadku gdy nie wysłasz niczego ze Slave do Mastera to funkcja odbioru bajtu w trybie Slave nie powinna niczego pisać do SPDR. Po co ona dostaje jakiś argument? Wystarczy, że poczeka na SPIF i wczyta odebrany bajt. W przeciwnym wypadku musisz to dokładnie zsynchronizować. Obecnie Slave w przypadkowej chwili zapisuje coś do SPDR być może niszcząc odbierany właśnie bajt.

Komentarze do funkcji nadawania/odbioru bajtów odpowiednio dla Master/Slave są zamienione. To już lepiej, żeby w ogóle ich nie było.

W trybie Slave nie masz nigdzie zdefiniowanej linii SCK ani nie ustawiasz jej kierunku. Wiem, że to zadziała bo SPI i tak "wie", gdzie ona jest a przy okazji w odpowiednim DDR zostaje tam zero (to już niekoniecznie) ale skoro w trybie Master o to dbasz, to dla równowagi Slave powinien nie być w tym temacie poszkodowany.

Jak daleko masz od procesora do procesora i czym są połączone? Czy leżą na jednej płytce? Jakie są zegary procesorów?

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...