Jeżyk-1 Napisano Czerwiec 14, 2013 Udostępnij Napisano Czerwiec 14, 2013 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ć ?
davidpi Czerwiec 14, 2013 Udostępnij Czerwiec 14, 2013 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.
Jeżyk-1 Czerwiec 14, 2013 Autor tematu Udostępnij Czerwiec 14, 2013 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ą.
Elvis Czerwiec 14, 2013 Udostępnij Czerwiec 14, 2013 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.
davidpi Czerwiec 14, 2013 Udostępnij Czerwiec 14, 2013 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.
Jeżyk-1 Czerwiec 15, 2013 Autor tematu Udostępnij Czerwiec 15, 2013 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.
Elvis Czerwiec 15, 2013 Udostępnij Czerwiec 15, 2013 Jeżyk-1, zamien return SPDR; CS1_1; Na CS1_1; return SPDR;
Jeżyk-1 Czerwiec 15, 2013 Autor tematu Udostępnij Czerwiec 15, 2013 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.
Elvis Czerwiec 15, 2013 Udostępnij Czerwiec 15, 2013 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ć.
Jeżyk-1 Czerwiec 15, 2013 Autor tematu Udostępnij Czerwiec 15, 2013 Ale te opóźnienie jest po stronie master. W pętli głównej też mam opóźnienie tylu _delay_ms(), Po za tym jak tej linii nie ma program nadal nie działa.
Elvis Czerwiec 15, 2013 Udostępnij Czerwiec 15, 2013 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);
Jeżyk-1 Czerwiec 15, 2013 Autor tematu Udostępnij Czerwiec 15, 2013 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.
Elvis Czerwiec 15, 2013 Udostępnij Czerwiec 15, 2013 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.
Jeżyk-1 Czerwiec 15, 2013 Autor tematu Udostępnij Czerwiec 15, 2013 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ć.
Elvis Czerwiec 15, 2013 Udostępnij Czerwiec 15, 2013 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.
Pomocna odpowiedź
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ę »