Skocz do zawartości

NightTrain

Użytkownicy
  • Zawartość

    5
  • Rejestracja

  • Ostatnio

Informacje

  • Płeć
    Mężczyzna

Osiągnięcia użytkownika NightTrain

Młodszy odkrywca

Młodszy odkrywca (3/19)

  • Za 5 postów
  • To już rok!
  • Młodszy Juror

Odznaki

0

Reputacja

  1. Dziękuję za odpowiedź. Dodałem kilka LEDów sygnalizujących aktualny stan programu: LED1 - wejście do funkcji MAIN, LED2 - funkcja Write_To_nRF, LED3 - zakończenie funkcji NRF24L01INIT - ustawienie rejestrów modułu nRF24L01, LED4 - poprawne ustawienie rejestru STATUS modułu - sprawdzane w pętli WHILE, LED5 - funkcja RESET odpowiedzialna za skasowanie flag przerwań w module nRF po każdym nadaniu/odebraniu danych, LED6 - sygnalizacja niepowodzenia transmisji, LED7 - sygnalizacja nowych danych do odczytu, LED8 - obieg pętli WHILE. Funkcja MAIN wygląda tak: 1) - określenie kierunków działania pinów, do których podpięte są diody, wyłączenie diod. 2) - mignięcie diodą LED1 - funkcja MAIN. 3) - wywołanie funkcji SPIInit(). 4) - wywołanie funkcji nRF24L01Init(). Podczas obsługi tej funkcji kilkakrotnie miga dioda sygnalizująca funkcję Write_To_nRF - logiczne, funkcja nRF24L01 kilkakrotnie wywołuje funkcję Write_To_nRF, 5) - wywołanie funkcji konfigurującej przerwanie INT0. Pod pin PD2 (INT0) podłączony jest pin IRQ modułu radiowego. Docelowo, zmienia on stan na niski po odebraniu/wysłaniu danych przed moduł nRF. Ma to spowodować wywołanie przerwania w programie. 6) - sprawdzenie stanu rejestru STATUS modułu nRF - jeśli jest OK zaświecenie diody. Tutaj wszystko działa. 7) - wysłanie 5 bajtów danych funkcją Transmit_Payload. Wywołuje ona 2 razy funkcję Write_To_nRF więc dioda sygnalizująca tę funkcją miga 2 razy. 8) - sprawdzenie czy transmisja się powiodła - jeśli nie, ma zapalić się LED. Nic się nie świeci, więc przyjmuję, że jest OK. 9) - sprawdzenie czy są jakieś nowe dane do odczytu. Jeśli tak, zaświeć LED. LED się świeci - AVR odebrał jakieś dane od modułu nRF. Jak wynika z działania SPI skoro wysłał to jednocześnie odebrał. Działa. 10) - wywołanie funkcji RESET - skasowanie flag przerwań w module nRF. Dioda miga - funkcja wykonała się prawidłowo. 11) - mignięcie diody na końcu pętli WHILE - OK. Problem jest z przerwaniem generowanym przez moduł nRF24L01. Konfiguracja przerwania w programie wygląda następująco: void INT0_interrupt_init(void)//Przerwanie generowane po pomyslnej transmisji lub odbiorze pakietu. Pin IRQ zmienia swój stan na niski, co powoduje przerwanie na pinie INT0 procesora. { DDRD|=_BV(PD2);//INT0 jak wejscie PORTD|=_BV(PD2);//Podciaganie wejscia INT0 EICRA|=_BV(ISC01) |_BV(ISC00);//Zbocze narastajace EIMSK|=_BV(INT0);//Zezwolenie na przerwanie INT0 } Podłączenie przycisku podającego masę na pin PD2 powoduje wywołanie przerwania i jego obsługę (mignięcie diodą). Zakładam więc, że przerwanie od strony programu działa poprawnie. Mamy podciąganie, więc w stanie normalnym napięcie na pinie PD2 wynosi 5V, wciśnięcie przycisku (podanie masy) oraz puszczenie przycisku (zmiana ze stanu niskiego na wysoki) powoduje wywołanie przerwania. Według dokumentacji modułu nRF, bity 4,5 i 6 rejestru CONFIG odpowiedzialne są za wybór źródła przerwania pojawiającego się na pinie IRQ. Może to być: - bit 4 - osiągnięto maksymalną liczbę retransmisji danych, - bit 5 - wysłano dane, - bit 6 - nowe dane. Ustawienie rejestru CONFIG na wartość 0x1E (źródłem przerwania jest wysłanie oraz odebranie danych) powoduje, że stan pinu IRQ modułu nie zmienia się - cały czas jest na nim obecne napięcie 3,3V. Wnioskuję, że moduł nie odebrał ani nie wysłał żadnych danych. Pojawiają się rozbieżności. Skoro tak, to dlaczego dwa warunki w pętli WHILE sprawdzające czy transmisja się powiodła oraz czy są nowe dane do odczytu wskazują, że wszystko przebiegło pomyślnie ? Ustawiłem również rejestr CONFIG na wartośc 0x6E (źródłem przerwania jest tylko bit MAX_RT rejestru STATUS wskazujący, że osiągnięto maksymalną liczbę retransmisji danych; 15 razy). Zakładam, że transmisja nie przebiega pomyślnie, dane są wysyłane kilkakrotnie aż do osiągnięcia maksymalnej liczby retransmisji (15 razy) następnie jest generowane przerwanie. Przy takich ustawieniach pin IRQ modułu nRF zmienia swój stan, napięcie zmienia się odpowiednio 0V do 3,3V. Podsumowując: układ nie odbiera danych (również nie wysyła), więc nie ma zmiany stanu pinu IRQ. W pętli WHILE sprawdzam stan bitu MAX_RT (maksymalna liczba retransmisji) i jeśli wynosi 1 oznacza, że transmisja się nie powiodła. Cały czas ma on wartość 0 bo dioda się nie świeci. Na tej podstawie założyłem, że transmisja przebiegła pomyślnie. Z drugiej strony, pin IRQ modułu nRF wskazuje, że bit ten został ustawiony co oznacza niepowodzenie transmisji.
  2. Wykorzystuję program ze zdjęć z linku, który podałem w poprzednim poście. Po prostu przepisałem program ze zdjęć. Autor co prawda udostępnia kod do skopiowania pod linkiem: https://gist.github.com/klalle/83ec2a1a691523f2829f jednak nie wykorzystałem go, gdyż różni się do tego, który opisuje na blogu. Jest dla mnie mniej zrozumiały. Wspomniana przeze mnie funkcja RESET ma dokładnie taką postać jak wskazuje Autor bloga, czyli: void reset(void)//Po kazdym odebraniu/wyslaniu danych IRQ musi zostać skasowane w nRF. Robi to poniższa funkcja. { _delay_us(10); CLEARBIT(PORTC, 6);//CSN w stan niski _delay_us(10); Write_Byte_SPI(W_REGISTER + STATUS);//Zapisz do rejestru STATUS. _delay_us(10); Write_Byte_SPI(0x70);//Skasuj wszystkie IRQ w rejestrze STATUS. _delay_us(10); SETBIT(PORTC, 6);//CSN w stan wysoki. } Wywołanie tej funkcji w głównej pętli WHILE powoduje zawieszenie się programu. Wystarczy usunąć dwie linie wywołujące funkcję Write_Byte_SPI żeby program się nie zawieszał. W pętli WHILE wywołuję funkcję RESET a po powrocie z niej zmieniam stan diody. Bez wywołań funkcji Write_Byte_SPI w funkcji RESET, dioda zmienia stan (wszystko działa), po dodaniu dwóch linii wywołujących Write_Byte_SPI program się zawiesza. Prędkość SPI mam ustawioną na 1MHz. Opóźnienia Autor bloga komentuje następująco: _delay_us(10); //Make sure last command was while ago Może nie będzie to zbyt estetyczne, ale tak wygląda kod, który teraz generuje w/w problem. /* * Transmiter.c * * Created: 2018-02-09 13:03:58 * Author : Piotr */ #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdio.h> #include "nRF24L01.h" #define BIT(x) (1<<(x)) #define SETBITS(x,y) ((x)|=(y)) #define CLEARBITS(x,y) ((x)&=(~(y))) #define SETBIT(x,y) SETBITS((x), (BIT((y)))) #define CLEARBIT(x,y) CLEARBITS((x), (BIT((y)))) #define W 1 #define R 0 uint8_t *data; /* nRF24L01+ pinout: CE - PC7 CSN - PC6 SCK - SCK (PB7) MOSI - MOSI (PB5) MISO - MISO (PB6) IRQ - INT0 (PD2) */ void SPI_init(void) { DDRC|= _BV(PC6)|_BV(PC7); //Pin CSN i CE jako wyjscie DDRB|=_BV(PB4) |_BV(PB5) |_BV(PB7); // Pin SS, MOSI pin SCK jako wyjście SPCR|=_BV(SPE) |_BV(MSTR) |_BV(SPR0) |_BV(SPIE); // SPI Enable, Tryb Master, CLK/16, Przerwanie //SPSR|=_BV(SPIF);// Flaga przerwania - transmisja zakonczona SPDR;//Skasuj flagę SPIF SETBIT(PORTC, 6); //CSN High CLEARBIT(PORTC, 7); //CE Low } char Write_Byte_SPI(unsigned char cData) { SPDR = cData; // Wpisz dane do rejestru while(!(SPSR & (1<<SPIF)));//Poczekaj na koniec transmisji return SPDR; //Zwróć to co odebrano. (Kiedy wysyła, to jednocześnie odbiera). } uint8_t *Write_To_nRF(uint8_t readWrite, uint8_t reg, uint8_t *val, uint8_t antVal) { //readWrtie - W lub R, reg - rejestr, *val - tablica danych, antVal - liczba INTów w pakiecie. cli(); if(readWrite == W) //W = 1, R = 0 (define na początku). { reg = W_REGISTER + reg; //Dodaj nowy bit do rejestru. } static uint8_t ret[32]; //Tablica, która zostanie zwrócona na końcu. "*" na początku funkcji jest potrzebna, żeby było możliwe zwrócenie tablicy. _delay_us(10); CLEARBIT(PORTC, 6);//CSN w stan niski _delay_us(10); Write_Byte_SPI(reg); //Ustaw nRF w stan odczytu albo zapisu. Zależnie przy było W czy R. _delay_us(10); int i; for(i = 0; i < antVal; i++) { if(readWrite == R && reg != W_TX_PAYLOAD)//Czy chcesz odczytać rejestr {//Zapisując do W_TX_PAYLOAD nie można dodać W dopóki on jest na tym samym poziomie w rejestrze (?) ret[i] = Write_Byte_SPI(NOP);//Wyślij bajt, żeby odczytać dane. _delay_us(10); } else { Write_Byte_SPI(val[i]); _delay_us(10); } } SETBIT(PORTC, 6); //CSN w stan wysoki sei(); return ret; //Zwróc tablice. } void nRF24L01_init() { _delay_ms(100); uint8_t val[5]; //Dane do przekazania funkcji Write_To_Nrf val[0] = 0x01; Write_To_nRF(W, EN_AA, val, 1);//Tryb zapisu, zapis do rejestru EN_AA, val - dane do zapisania, 1 - liczba bajtow val[0] = 0x01; Write_To_nRF(W, EN_RXADDR, val, 1);//Aktywny kanał 0 transmisji //Ustawienie rozmiaru adresu modul nRF (jak duzo zajmuje bajtow) val[0] = 0x03; Write_To_nRF(W, SETUP_AW, val, 1); //Ustawienie czestotliwości val[0] = 0x01;//2,401GHz Write_To_nRF(W, RF_CH, val, 1); //Ustawienie trybu poboru mocy i szybkości val[0] = 0x07;//0b00000111 bit 3 = 0 co oznacza 1Mbps, (wiekszy zasieg), bit 2 i 1 trby mocy (11 - 0dB, 11 - -18dB) Write_To_nRF(W, RF_SETUP, val, 1); //Adres odbiornika (5 bajtów) int i; for(i = 0; i <5; i++) { val[i] = 0x12; } Write_To_nRF(W, RX_ADDR_P0, val, 5); //Wcześniej był wybrany kanał 0, wiec ten adres został nadany dla kanalu 0. Mozna dodać inne adresy, żeby komunikować się z większą liczką modułów. nRF. //Adres nadajnika (5 bajtów) for(i = 0; i<5; i++) { val[i] = 0x12; } Write_To_nRF(W, TX_ADDR, val, 5); //Ustawienie rozmiaru danych val[0] = 5; //5 bajtów na pakiet Write_To_nRF(W, RX_PW_P0, val, 1); //Ustawienie rejestru CONFIG. val[0] = 0x1E; //bit O = 0 -> Transmiter, bit 0 = 1 -> Receiver, bit 1 = 1 -> Power Up, bit 4 = 1 ->mask_MAX_RT. IRQ nie jest wyzwalane, jeśli transmisja się nie powwiedzie. Write_To_nRF(W, CONFIG, val, 1); //Liczba prób i opóźnienia pomiędzy próbami val[0] = 0x2F; // bit 2 -> Opoznienie 750us, F -> liczba prób (15). Opoznienie musi wynosi minimum 500us przy 250kbps oraz jesli dane maja wiecej niż 5 bajtów przy predkosci 1Mbps i jeśli mają powyżej 15 bajtów przy 2Mbps. Write_To_nRF(W, SETUP_RETR, val, 1); //Opoznienie konieczne zeby przejsc w tryb StandBy (niski stan na CE) _delay_ms(100); } void Transmit_payload(uint8_t *W_buff) { Write_To_nRF(R, FLUSH_TX, W_buff, 0);//Wyczyszczenie rejestru ze starych danych Write_To_nRF(R, W_TX_PAYLOAD, W_buff, 5); sei(); _delay_ms(10);//Konieczne opoznienie zeby pracowac po zaladowaniu do nRF danych SETBIT(PORTC, 7);//CE w stan wysoki - rozpocznij transmisje _delay_us(20); CLEARBIT(PORTC, 7); //CE w stan niski - zakoncz transmisje. _delay_ms(10); } void reset(void)//Po kazdym odebraniu/wyslaniu danych IRQ musi zostać skasowane w nRF. Robi to poniższa funkcja. { _delay_us(10); CLEARBIT(PORTC, 6);//CSN w stan niski _delay_us(10); Write_Byte_SPI(W_REGISTER + STATUS);//Zapisz do rejestru STATUS. _delay_us(10); Write_Byte_SPI(0x70);//Skasuj wszystkie IRQ w rejestrze STATUS. _delay_us(10); SETBIT(PORTC, 6);//CSN w stan wysoki. } int main(void) { DDRA|=_BV(PA3) |_BV(PA2) |_BV(PA1) |_BV(PA0);// LED PORTB|=_BV(PB4); uint8_t W_buffer[6]; uint8_t a=0; SPI_init(); nRF24L01_init(); sei(); while (1) { for(uint8_t i = 0; i<5; i++) { W_buffer[i] = 0x93; } Transmit_payload(W_buffer); PORTA&=~_BV(PA1); //Zaświec LED blad _delay_ms(50); PORTA|=_BV(PA1);//Wylacz LED blad _delay_ms(50); reset(); } } Dla większej czytelności usunąłem niektóre funkcje jak np. funkcję odbioru danych od drugiego nRF24L01, czy funkcję konfigurującą przerwanie generowane przez moduł radiowy. Plik nagłówkowy nRF24L01.h ma następującą postać: https://github.com/maniacbug/RF24/blob/master/nRF24L01.h .
  3. No tak. Teraz działa bo wysyłam 1 bajt i czekam 100ms co w zupełności wystarcza do wysłania tego bajtu. Przy większych pakietach to się nie uda. Jeśli chodzi o moduł nRF24L01 to w dużej mierze opieram się o projekt ze strony: http://gizmosnack.blogspot.com/2013/04/tutorial-nrf24l01-and-avr.html . Wykorzystuję kod tam zaprezentowany, jednak nie do końca on działa poprawnie. Funkcja, której zadaniem jest wysyłanie danych przez SPI wygląda tak: char Write_Byte_SPI(unsigned char cData) { SPDR = cData; while(!(SPSR & (1<<SPIF))); return SPDR; } Pusta pętla WHILE kręci się do momentu ustawienia bitu SPIF, następnie zwraca to co odebrano. Funkcja ta jest wywoływana do przesyłania komend do modułu nRF24L01. I faktycznie, jak się dzisiaj okazało, przy próbie wywołania funkcji RESET (odpowiedzialnej za skasowanie w module radiowym flag zakończenia nadawania/odebrania pakietu) program zawiesza się. Funkcja RESET wygląda następująco: void reset(void)//Po każdym odebraniu/wysłaniu danych IRQ musi zostać skasowane w nRF. Robi to poniższa funkcja. { _delay_us(10); CLEARBIT(PORTC, 6);//CSN w stan niski _delay_us(10); Write_Byte_SPI(W_REGISTER + STATUS);//Zapisz do rejestru STATUS. _delay_us(10); Write_Byte_SPI(0x70);//Skasuj wszystkie IRQ w rejestrze STATUS. _delay_us(10); SETBIT(PORTC, 6);//CSN w stan wysoki. } W_REGISTER i STATUS to nazwy dla rejestrów modułu radiowego. W_REGISTER to 0x20, a STATUS to 0x07. Ustawienia konfiguracyjne rejestrów modułu nRFl24L01 odbywają się z wykorzystaniem funkcji Write_To_nRF. Przyjmuje ona 4 argumenty typu UINT8_T. uint8_t *Write_To_nRF(uint8_t readWrite, uint8_t reg, uint8_t *val, uint8_t antVal) Przesłanie z wykorzystaniem funkcji Write_To_nRF działa poprawnie. W ciele funkcji mamy kilka wywołań funkcji Write_Byte_SPI do której przekazywana jest np. wartość 0xE1 - wtedy nic się nie zacina i działa poprawnie. Jak się domyślam dlatego, że argumenty funkcji Write_To_nRF są rzutowane na UINT8_T i dopiero potem przekazane do Write_Byte_SPI. W przypadku wywołania funkcji Write_Byte_SPI(W_REGISTER + STATUS) mamy tak naprawdę Write_Byte_SPI(0x20 + 0x07). Nie ma tutaj rzutowania na UINT8_T i może dlatego program nie działa. Przy próbie wywołania funkcji RESET() ze zmienionymi liniami: Write_Byte_SPI(W_REGISTER + STATUS); Write_Byte_SPI(0x70); na Write_Byte_SPI((uint8_t)(W_REGISTER + STATUS)); Write_Byte_SPI((uint8_t)(0x70)); program nie zawiesza się. Czy dobrze to wszystko rozumuję ?
  4. Dziękuję za odpowiedź. Faktycznie, wystarczyło ponowne przeczytanie dokumentacji, a właściwie jednego zdania: " writing a byte to the SPI Data Register starts the SPI clock generator, and the hardware shifts the eight bits into the Slave". Czyli wystarczy wpisać dane do SPDR, a potem oczekiwać albo na ISR od SPI, które jest wywoływane bitem SPIF albo czekać aż warunek pustej pętli WHILE przestanie być spełniany. Teraz rozumiem. Dodałem polecenie SEI(), a funkcję wysyłającą bajt po SPI zmieniłem do postaci: uint8_t SPI_send_rec_byte(uint8_t byte) { SPDR=byte; } W przerwaniu sprawdzam to co przesłał SLAVE. Dziękuję za pomoc.
  5. Dzień dobry, Mam zamiar zrealizować komunikację radiową pomiędzy dwoma mikrokontrolerami z wykorzystaniem modułu nRF24L01+. Do tego celu muszę opanować komunikację SPI. Zrobiłem prosty układ z wykorzystaniem ATmega644 oraz ATtiny2313A. ATmega jest układem MASTER, który wysyła cyklicznie jeden znak po magistrali SPI do urządzenia SLAVE (ATtiny2313), który go odbiera u siebie interfejsem USI, a następnie wyświetla na LCD. W momencie kiedy MASTER wysyła dane do SLAVE, SLAVE wysyła do MASTERA również jeden znak. Po odebraniu znaku MASTER zmienia stan diody LED. Cały problem w tym, że nie wykonuje się przerwanie występujące po pomyślnym wysłaniu danych przez MASTER. Komunikacja działa poprawnie, bo diody LED obrazujące nadanie i odebranie danych przez poszczególne układy działają zgodnie z oczekiwaniami. Podczas ustawiania bitów odpowiedzialnych za SPI w układzie MASTER, ustawiłem bit odpowiedzialny za przerwanie. W ATmega644 jest to bit SPIE w rejestrze SPCR. Nie stosowałem natomiast polecenia SEI() dlatego, że po umieszczeniu go w kodzie, program w ogóle nie rusza. Zawiesza się. W SLAVE również nie używam polecenia SEI(), a mimo to przerwanie od przepełnienia licznika interfejsu USI wykonuje się poprawnie. Tworząc kod opierałem się na przykładach z książki T. Francuz (Język C dla mikrokontrolerów AVR) oraz korzystałem z kursu C publikowanego na łamach czasopisma EdW. Podsumowując: Jeśli przerwanie od SPI w układzie MASTER, nie wykonuje się dlatego, że brakuje komendy SEI() to dlaczego dodanie komendy SEI() powoduje zawieszenie się AVRa? Z góry dziękuję za pomoc. /* * Master.c #include <avr\io.h> #include <util\delay.h> #include <string.h> #include <stdio.h> #include <avr/interrupt.h> void SPI_master_init() { DDRB|= _BV(PB4) |_BV(PB5) | _BV(PB7); //Piny MOSI, SCK jako wyjście SPCR|=_BV(SPE) | _BV(MSTR) |_BV(SPR0) |_BV(SPIE); //SPI Enable, Tryb master, CLK/16, Interrupt Enable SPSR|=_BV(SPIF);//Interrupt Flag - Transmission Complete SPDR; //Skasuj flagę SPIF sei();//Bez tego komunikacja działa. } uint8_t SPI_send_rec_byte(uint8_t byte) { SPDR=byte; while(!(SPSR & _BV(SPIF))); return SPDR; } volatile uint8_t liczba = 0; int main() { SPI_master_init(); DDRB|=_BV(PB2) |_BV(PB3); // PB2 i PB3 jako wyjście - LED PORTB|=_BV(PB2); //Wyłączony LED PORTB|=_BV(PB3); char znak; while(1) { znak = (char)SPI_send_rec_byte('D'); //Wyślij do SLAVE znak 'D', to co odbierzesz wpisz do zmiennej 'znak'. if (znak == 'B')//Jesli odebrano 'B' mrugnij LEDem. { PORTB&=~_BV(PB2); _delay_ms(30); PORTB|=_BV(PB2); _delay_ms(30); } _delay_ms(1000); } } ISR(SPI_STC_vect)//Każde wystąpienie przerwania SPI (kazde zakonczenie nadawania) zmienia stan diody LED. TO SIE NIE WYWOŁUJE. { if(liczba%2) { PORTB&=~_BV(PB2); } else { PORTB|=_BV(PB2); } liczba++; if(liczba == 9) liczba = 0; }
×
×
  • 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.