Skocz do zawartości

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


Jeżyk-1

Pomocna odpowiedź

Witam Państwa.

Próbuję wykonać komunikację trzech mikroprocesorów atmega16 za pomocą SPI.

Udało mi się dokonać komunikacji między dwoma AVR i tak wygląda kod programu:

#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 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 TransferSpi(uint8_t byte);

int main(void) {
DDRC |= (1 << PC1);
PORTC |= (1 << PC1);
lcd_init(); //inicjalizacja wyświetlacza
InitSpiMaster();//inicjalizacja SPI
//TransferSpi(0);
lcd_locate(1, 0);
lcd_str("master");
uint8_t cnt = 0; //deklaracja zmiennej licznika
while (1) {
	_delay_ms(300);

	cnt++; //Dodanie wartości licznika
	if (cnt == 99)
		cnt = 0; //jeżeli licznik ==99 zeruje zmienną cnt


	uint8_t bajt_oo;
	TransferSpi(cnt); //Wysłanie wartości zmiennej cnt
	bajt_oo = TransferSpi(0);

	lcd_locate(0, 0);
	lcd_str("W:");
	lcd_int(cnt); //Wyświetlenie wartości cnt na LCD

	lcd_locate(10, 0);
	lcd_str("O:");
	lcd_int(bajt_oo);

}

}

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

}
// definicja funkcji odbioru bajy

uint8_t TransferSpi(uint8_t byte) {
CS1_0;
SPDR = byte;
while (!(SPSR & (1 << SPIF)))
	;
return SPDR;
CS1_1;
}

#endif

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

#if MASTER == 0

#define MISO PB6
#define CS1 PB4
//#define CS1_0 PORTB &= ~(1<<CS1)
//#define CS1_1 PORTB |= (1<<CS1)


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
//TransferSpi( 0 );
lcd_locate(1, 0);
lcd_str("Slave 1"); //wyświetlenie napisu
uint8_t cnt = 99;

while (1) {
	cnt--; //Dodanie wartości licznika
	if (cnt == 1)
	cnt = 99; //jeżeli licznik ==99 zeruje zmienną cnt


	uint8_t bajt_o;
	bajt_o = TransferSpi(0);
	TransferSpi(cnt); //Wysłanie wartości zmiennej cnt

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

	lcd_locate(0, 0);
	lcd_str("W:");
	lcd_int(cnt); //Wyświetlenie wartości cnt na LCD


}

}

void InitSpiSlave(void) {
// ustawienie kierunku wyjściowego dla linii MOSI
DDRB |= (1 << MISO);
DDRB &= ~(1<<CS1);
// 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

Tak wgrany kod do master i slave wysyła między sobą dane.

Teraz został drugi slave do zaprogramowania i stworzyłem coś takiego:

#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 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
//TransferSpi(0);
lcd_locate(1, 0);
lcd_str("master");
uint8_t cnt = 0; //deklaracja zmiennej licznika
while (1) {
	_delay_ms(300);

	cnt++; //Dodanie wartości licznika
	if (cnt == 99)
		cnt = 0; //jeżeli licznik ==99 zeruje zmienną cnt


	uint8_t bajt_o1;
	TransferSpi1(0); //Wysłanie wartości zmiennej cnt
	bajt_o1 = TransferSpi1(0);

	uint8_t bajt_o2;
	TransferSpi2(0); //Wysłanie wartości zmiennej cnt
	bajt_o2 = TransferSpi2(0);

	lcd_locate(0, 0);
	lcd_str("O1:");
	lcd_int(bajt_o1);

	lcd_locate(10, 0);
	lcd_str("O2:");
	lcd_int(bajt_o2);

}

}

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);
// 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) {
CS1_0;
SPDR = byte;
while (!(SPSR & (1 << SPIF)))
	;
return SPDR;
CS1_1;
}
uint8_t TransferSpi2(uint8_t byte) {
	CS2_0;
	SPDR = byte;
	while (!(SPSR & (1 << SPIF)))
		;
	return SPDR;
	CS2_1;
}

#endif

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

#if MASTER == 0

#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
	//TransferSpi( 0 );
	lcd_locate(1, 0);
	lcd_str("Slave 2"); //wyświetlenie napisu
	uint8_t cnt = 99;

	while (1) {
		cnt++; //Dodanie wartości licznika
		if (cnt == 1)
		cnt = 99; //jeżeli licznik ==99 zeruje zmienną cnt


		uint8_t bajt_o;
		bajt_o = TransferSpi(0);
		TransferSpi(cnt); //Wysłanie wartości zmiennej cnt

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

		lcd_locate(0, 0);
		lcd_str("W:");
		lcd_int(cnt); //Wyświetlenie wartości cnt na LCD


	}

}

void InitSpiSlave(void) {
	// ustawienie kierunku wyjściowego dla linii MOSI
	DDRB |= (1 << MISO);
	DDRB &= ~(1<<CS1);
	// 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

I teraz wszystko przestało działać. Master wysyła i swoje wysłane dane odbiera, a co skutkuje że nie dostaje żadnych danych od slave1 i slave2.

Czy ktoś poratuję co mogę w tym przypadku zrobić ?

Link do komentarza
Share on other sites

Kod dla drugiego slave'a powinien być taki sam jak dla pierwszego. To master decyduje z kim chce gadać. Uaktywnia jednego slave'a i z nim gada. potem go dezaktywuje, uaktywnia drugiego i z nim gada. I tak na zmianę.

Ahh chyba źle Cię zrozumiałem. Myślałem, że pytasz jak działa SPI gdy mamy dwa slave'y.

OK.

Czemu w drugim programie w funkcji main() w pętli głównej while(1) zamieniłeś dekrementację cnt na inkrementację?? Ta zmienna chyba powinna być zmniejszana a nie zwiekszana.

Link do komentarza
Share on other sites

I tak zrobiłem na początku że wgrałem kod z pierwszego przypadku do slave1 i slave2. Po czym testowałem pracę tylko między dwoma układami master <> slave. I działało gdy pracował master <> slave1 i gdy pracował master <> slave2. Następnie zrobiłem kod 2 który miał pracować z 2 slave. I jak jest wykonywana funkcja TransferSpi1() to odpowiednio sterowny jest pin SS do slave 1. tak samo jest przy funkcji TransferSpi2() co steruje pinem ss dla slave2. I nie rozumiem dlaczego to nie działa.

Czemu w drugim programie w funkcji main() w pętli głównej while(1) zamieniłeś dekrementację cnt na inkrementację?? Ta zmienna chyba powinna być zmniejszana a nie zwiekszana.

A to ma taki wpływ by tak się zachowywał układ?

Wcześniej master miał odejmowanie a slave dodawanie bym widział zmianę wartości które się wysyłają.

Link do komentarza
Share on other sites

W funkcji transferspi masz kod po return - nie jest wykonywany, wiec nie konczysz poprawnie komunikacji.

[ Dodano: 14-06-2013, 22:33 ]

Ze zmienna cnt tez nie jest najlepiej. Master jej nie uzywa (wysyla zero) a slave liczy od 99 do przepelnienia, pozniej do 1 i przeskakuje do 99 - chyba nie o to chodzilo.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Hmm jest już późno więc mogę pisać jakieś dyrdymały 😅

1. Master w ogóle nie używa zmiennej cnt. Wysyła ciągle 0.

2. Pamiętaj aby dla mastera skonfigurować jego włąsny pin SS jako wyjście. Tak jest bezpiecznie.

3. To jest ważne. Czy logika działania SPI jest Ci znana?? Układ slave tak naprawdę nie potrafi wysyłać żadnych danych. Żeby odczytać coś od slave'a musisz zrobić taką operację: wysłać do slave'a żądanie (np jakąś komendę) a potem wysłać jakąkolwiek liczbę po to by master generował taktowanie na lini SCK. W tym czasie slave po odebraniu żądania ładuje do SPDR daną do wysłania i ona podczas taktowania wędruje do mastera.

Obejrzyj te funkcje do wysyłania i odbierania dla mastera

void SPI_Write(uint8_t dana)
{
SPDR = dana;
while(bit_is_clear(SPSR,SPIF)){;}
}

uint8_t SPI_Read()
{
return SPDR;
}

uint8_t SPI_Send(uint8_t dana_write)
{
SPI_Write(dana_write);
_delay_us(10);
SPI_Write(0xFF);
return SPDR;
}

Natomiast dla slave wystarczy tylko to

void SPI_Write(uint8_t dana)
{
SPDR = dana;
}

uint8_t SPI_Read()
{
return SPDR;
}

Slave powinien odbieranie robić w przerwaniu, lub chociaż sprawdzać co chwilę. Gdy odbierze komendę powinien użyć funkcji SPI_Write(dana) podając jej daną do wysłania.

Link do komentarza
Share on other sites

Ogólnie zasadę działania SPI jaką przedstawiłeś to znam. Gorzej z zastosowaniem tego w praktyce.

Kod jaki pokazałeś jest bardzo zbliżony do mojego tylko rozbity na 3 funkcje. Spróbuję coś podobnego zastosować u mnie zobaczymy jak to wyjdzie.

Z przerwaniem też próbowałem lecz zatrzymałem się już przy wysyłaniu danych od master do slave.

Dlaczego master nie używa zmiennej cnt i wysyła cały czas 0 ?

taką samą funkcję zastosowałem wcześniej dla dwóch układów (master <> slave) i działało.

Link do komentarza
Share on other sites

Jeżyk-1, zamien
    return SPDR; 
   CS1_1; 

Na

    
CS1_1; 
return SPDR;   

To już zmieniłem w tej chwili cały kod wygląda tak:

#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");
uint8_t cnt = 0; //deklaracja zmiennej licznika
while (1) {
	_delay_ms(300);

	cnt++; //Dodanie wartości licznika
	if (cnt >= 99)
		cnt = 0; //jeżeli licznik ==99 zeruje zmienną cnt


	uint8_t bajt_o1;
	TransferSpi1(cnt); //Wysłanie wartości zmiennej cnt
	_delay_ms(1);
	bajt_o1 = TransferSpi1(0);



	uint8_t bajt_o2;
	TransferSpi2(cnt); //Wysłanie wartości zmiennej cnt
	_delay_ms(1);
	bajt_o2 = TransferSpi2(0);

	lcd_locate(0, 0);
	lcd_str("O1:");
	lcd_int(bajt_o1);

	lcd_locate(10, 0);
	lcd_str("O2:");
	lcd_int(bajt_o2);

	lcd_locate(1, 9);
	lcd_str("W:");
	lcd_int(cnt);

}

}

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) {
CS1_0;
SPDR = byte;
while (!(SPSR & (1 << SPIF)));
while(PINB & (1<<MISO));
CS1_1;

return SPDR;
}
uint8_t TransferSpi2(uint8_t byte) {
	CS2_0;
	SPDR = byte;
	while (!(SPSR & (1 << SPIF)));
	while(PINB & (1<<MISO));
	CS2_1;
	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
	uint8_t cnt = 0;

	while (1) {
		cnt=cnt+2; //Dodanie wartości licznika Slave 1 cnt+2, slave 2 cnt+3
		if (cnt >= 99)
		cnt = 0; //jeżeli licznik ==99 zeruje zmienną cnt


		uint8_t bajt_o;
		bajt_o = TransferSpi(0);
		_delay_ms(1);
		TransferSpi(cnt); //Wysłanie wartości zmiennej cnt

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

		lcd_locate(0, 0);
		lcd_str("W:");
		lcd_int(cnt); //Wyświetlenie wartości cnt na LCD


	}

}

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

I Master wyświetla to samo co samy wysyła, slave1 działa z dziwnym opóźnieniem i w odebranych ma cały czas wartość zero, Slave 2 pracuje z podobną częstotliwością do master i odbiera dane od mastera.

Link do komentarza
Share on other sites

To na pewno jest niepotrzebne:

    while(PINB & (1<<MISO));

Poza tym lepiej wstawić opóźnienia po stronie mastera, nie po stroni slave-a.

[ Dodano: 15-06-2013, 14:05 ]

Zobacz jeszcze jedną rzecz - spróbuj zresetować (ew. kilka razy) slave1. Zobacz, czy nie zacznie działać.

Link do komentarza
Share on other sites

Dodaj do master:

       uint8_t bajt_o1; 

       TransferSpi1('X'); 

       TransferSpi1(cnt); //Wysłanie wartości zmiennej cnt 

Po stronie slave:

           uint8_t bajt_o; 

           while (TransferSpi(0)!='X');

           bajt_o = TransferSpi(0); 
Link do komentarza
Share on other sites

Czy o coś takiego chodziło:

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

#define MASTER 0    //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");
   uint8_t cnt = 0; //deklaracja zmiennej licznika
   while (1) {
       _delay_ms(300);

       cnt++; //Dodanie wartości licznika
       if (cnt >= 99)
           cnt = 0; //jeżeli licznik ==99 zeruje zmienną cnt


       uint8_t bajt_o1;
       TransferSpi1('X');
       TransferSpi1(cnt); //Wysłanie wartości zmiennej cnt
       _delay_ms(1);
       bajt_o1 = TransferSpi1(0);



       uint8_t bajt_o2;
       TransferSpi2('X');
       TransferSpi2(cnt); //Wysłanie wartości zmiennej cnt
       _delay_ms(1);
       bajt_o2 = TransferSpi2(0);

       lcd_locate(0, 0);
       lcd_str("O1:");
       lcd_int(bajt_o1);

       lcd_locate(10, 0);
       lcd_str("O2:");
       lcd_int(bajt_o2);

       lcd_locate(1, 9);
       lcd_str("W:");
       lcd_int(cnt);

   }

}

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) {
   CS1_0;
   SPDR = byte;
   while (!(SPSR & (1 << SPIF)));
   CS1_1;

   return SPDR;
}
   uint8_t TransferSpi2(uint8_t byte) {
       CS2_0;
       SPDR = byte;
       while (!(SPSR & (1 << SPIF)));
       CS2_1;
       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 2"); //wyświetlenie napisu
       uint8_t cnt = 0;

       while (1) {
           cnt=cnt+3; //Dodanie wartości licznika Slave 1 cnt+2, slave 2 cnt+3
           if (cnt >= 99)
           cnt = 0; //jeżeli licznik ==99 zeruje zmienną cnt


           uint8_t bajt_o;
           while (TransferSpi(0)!='X');
           bajt_o = TransferSpi(0);
           _delay_ms(1);
           TransferSpi(cnt); //Wysłanie wartości zmiennej cnt

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

           lcd_locate(0, 0);
           lcd_str("W:");
           lcd_int(cnt); //Wyświetlenie wartości cnt na LCD


       }

   }

   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

Bo efekt jest ten sam master odbiera to samo co sam wyśle, a oba slave nie pracują. Nawet nie zmienia się wartość licznika na LCD.

Link do komentarza
Share on other sites

A sama komunikacja działa poprawnie? Może napisz program, który będzie wysyłał np. 'A' do slave1 i 'B' do slave2 - a po stronie slave wyswietl co przychodzi.

Kolejny etap to sprawdzenie w drugą stronę - jeden slave niech wysyla '1' drugi '2' i pytanie, czy poprawnie przechodzi.

Link do komentarza
Share on other sites

Wcześniej miałem taki 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 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 TransferSpi(uint8_t byte);

int main(void) {
DDRC |= (1 << PC1);
PORTC |= (1 << PC1);
lcd_init(); //inicjalizacja wyświetlacza
InitSpiMaster();//inicjalizacja SPI
//TransferSpi(0);
lcd_locate(1, 0);
lcd_str("master");
uint8_t cnt = 0; //deklaracja zmiennej licznika
while (1) {
	_delay_ms(300);

	cnt++; //Dodanie wartości licznika
	if (cnt == 99)
		cnt = 0; //jeżeli licznik ==99 zeruje zmienną cnt


	uint8_t bajt_oo;
	TransferSpi(cnt); //Wysłanie wartości zmiennej cnt
	bajt_oo = TransferSpi(0);

	lcd_locate(0, 0);
	lcd_str("W:");
	lcd_int(cnt); //Wyświetlenie wartości cnt na LCD

	lcd_locate(10, 0);
	lcd_str("O:");
	lcd_int(bajt_oo);

}

}

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

}
// definicja funkcji odbioru bajy

uint8_t TransferSpi(uint8_t byte) {
CS1_0;
SPDR = byte;
while (!(SPSR & (1 << SPIF)))
	;
return SPDR;
CS1_1;
}

#endif

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

#if MASTER == 0

#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
//TransferSpi( 0 );
lcd_locate(1, 0);
lcd_str("Slave 1"); //wyświetlenie napisu
uint8_t cnt = 99;

while (1) {
	cnt--; //Dodanie wartości licznika
	if (cnt == 1)
	cnt = 99; //jeżeli licznik ==99 zeruje zmienną cnt


	uint8_t bajt_o;
	bajt_o = TransferSpi(0);
	TransferSpi(cnt); //Wysłanie wartości zmiennej cnt

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

	lcd_locate(0, 0);
	lcd_str("W:");
	lcd_int(cnt); //Wyświetlenie wartości cnt na LCD


}

}

void InitSpiSlave(void) {
// ustawienie kierunku wyjściowego dla linii MOSI
DDRB |= (1 << MISO);
DDRB &= ~(1<<CS1);
// 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

Tylko że on łączył się albo z slave 1 albo z slave 2. I w tedy komunikacja między nimi działała poprawnie. Jak przerobiłem go do powyższej wersji przestało działać.

Link do komentarza
Share on other sites

W tym kodzie na oko widać błędy. To że działa, jeszcze o niczym nie świadczy. Nie zwalniasz linii CS, więc nie ma szans w przypadku 2 układów podrzędnych.

Twój program transmituje po 2 bajty (w obie strony). Przez to jest narażony na kolejny problem - synchronizację. Pomyśl co się stanie, jak slave przeoczy 1 bajt i zacznie od odebrania drugiego z pary.

Dlatego proponuję najpierw najprostsze rozwiązanie - transmisję pojedynczego bajtu. Poza tym w Twoim programie nie masz pewności, czy odbierasz dokładnie te dane, które wysyłasz. (Podejrzewam, że coś z tym jest nie tak, bo program nie odbierał 'X').

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

Jeszcze jedna rzecz, która może pomóc: po stronie mastera (ale tylko mastera!) dodaj długie oczekiwanie (np. 200ms) przed każdym transferem. Zobacz, czy to poprawi działanie.

Link do komentarza
Share on other sites

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...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.