KursyPoradnikiInspirujące DIYForum

RFM12B – #2 – Koniec ciszy w eterze

RFM12B – #2 – Koniec ciszy w eterze

Poprzednio zakończyliśmy na podłączeniu modułu RFM12B do procesora i sprawdzeniu komunikacji po magistrali SPI.

Teraz już czas najwyższy na przesłanie informacji pomiędzy dwoma modułami. Zatem do dzieła!

« Poprzedni artykuł z seriiNastępny artykuł z serii »

Wstępna konfiguracja układu i oczekiwanie…

Na samym początku musimy odpowiednio skonfigurować nasz układ, co zrealizujemy korzystając z następującej funkcji:

void Rfm_init(void){
	Rfm_xmit(SW_RESET);//resetuję programowo układ RFM12B
	_delay_ms(250);

	//inicjalizacja RFM12B
	//ustawienie pasma 868MHz, konfiguracja FIFO
	Rfm_xmit(CONFIGURATION|EN_DATA_REG|EN_FIFO|BAND_868|CAP_12_0);
	//włączenie oscylatora
	Rfm_xmit(POWER|EN_OSC|DIS_CLKO);
	//ustawienie pasma (musi być takie samo w nadajniku i odbiorniku)
	//Dla naszego układu częstotliwość musi zawierać się w przedziale 860480000-879515000Hz i musi być podawana ze skokami 5000Hz
	Rfm_xmit(FREQUENCY|RF12_FREQUENCY_CALC_868(868000000UL));
	//ustawienie prędkości transmisji danych (musi być takia sama w nadajniku i odbiorniku)
	Rfm_xmit(BAUD|BAUD_4800);
	//ustawienie pasma 134kHz i parametrów odbiornika
	Rfm_xmit(RECEIVER|P20_VDI|BW134|LNA_0|RSSI_103);
	//ustawienie cyfrowego filtra danych i opcji odzyskiwania zegara
	Rfm_xmit(DATA_FILTER|AUTO_CR|DIGITAL_F|DQD_4);
	//reset bufora FIFO, konfiguracja synchronizacji za pomocą 2 bajtów, ustawienie generowania przerwania FFIT po odebraniu 8 bitów
	Rfm_xmit(FIFO_RST|FIFO_IT_8|FIFO_SYNC|HS_RST_DIS);
	

	//konfiguracja kontrolera częstotliwości
	Rfm_xmit(AFC|KEEP_RX|REST_OFF|EN_FOFFSET|EN_AFC);
	//konfiguracja nadajnika i jego mocy (na ustawienie maksymalne)
	Rfm_xmit(TRANSMITER|FSK_PHASE_0|FSK_DF_90K|OUT_P_0);
	//konfiguracja pętli PLL
	Rfm_xmit(PLL|PLL_DH_DIS|SEL_CLK_2_5|MAX_BAUD_256);

	//wyłączenie timera wakeup
	Rfm_xmit(WAKEUP_TIM|WUT_X_2_0|0);
	//wyłączenie oszczędzania energii
	Rfm_xmit(LOW_DC|LOW_DC_DIS);
	//ustawienie monitora napięcia na 2,2V
	Rfm_xmit(BOD_CLK|CLK_5_00|BOD_2_2);
}

Najpierw oczywiście dokonujemy programowego resetu naszego układu, aby mieć pewność, że nie natkniemy się na jakieś niespodzianki czy pozostałości po poprzednich transmisjach.

Potem przystępujemy do konfiguracji układu, zapisując wartości do rejestrów konfiguracyjnych. Opiszę tu pokrótce, co robią dane polecenia, jednak do pełnego ich zrozumienia konieczna jest lektura noty katalogowej:

  1.  Ustawiamy częstotliwość pracy układu (musi być zgodna z oznaczeniem pasma na układzie: 433/868/915MHz) oraz inne parametry analogowe. Włączamy także bufor odbiorczy danych.
  2. Włączamy oscylator i wyłączamy wyjście zegarowe z układu (w celu zmniejszenia zakłóceń).
  3. Ustawiamy częstotliwość nośną (czyli częstotliwość, na jakiej będzie pracował układ) – nadajnik i odbiornik muszą mieć ustawioną oczywiście tę samą wartość. Jeśli chcemy używać równolegle kilku linii komunikacyjnych, opartych na tych układach, to możemy kolejnemu systemowi ustawić inną częstotliwość. W komentarzu podałem zakres częstotliwości dla modułu 868MHz i skok, z jakim możemy je ustawiać – pamiętajmy jednak, że stosując dwa systemy pracujące na zbliżonych częstotliwościach, narażamy się na zakłócenia.
  4. Ustawiamy prędkość transmisji – zasadniczo im wyższa prędkość, tym szybciej dane zostaną przesłane, jednak jednocześnie zwiększa się wtedy wpływ zakłóceń.
  5. Konfigurujemy parametry odbiornika – poziom sygnału, na jaki będzie reagował oraz rozpiętość zakresu częstotliwości, które będzie akceptował.
  6. Aktywujemy cyfrowe dekodowanie danych.
  7. Ustawiamy generowanie przerwania po odebraniu 8 bitów danych (wykorzystamy tę funkcjonalność w kolejnej części naszych zmagań) oraz ustawiamy wykorzystanie 2 bajtów synchronizacyjnych. Teraz do synchronizacji będziemy musieli przesłać 5 bajtów, 4 o stałych wartościach: 0xAA 0xAA 0xAA 0x2D oraz piąty, którego wartość będziemy potem definiować. Dzięki temu odbiór danych będzie rozpoczynany tylko po otrzymaniu tej sekwencji, a dodatkowy definiowany bajt możemy wykorzystać jako adres odbiorczy naszego układu.
  8. Konfigurujemy automatyczny kontroler częstotliwości.
  9. Ustawiamy maksymalną moc nadajnika i parametry modulacji.
  10. Konfigurujemy pętlę PLL, powielającą częstotliwość z rezonatora.
  11. Wyłączamy timer do wybudzania układu z drzemki, a także tryb oszczędzania energii.
  12. Ustawiamy wykrywanie zaniku zasilania na poziom 2,2V.

Ponadto przygotujmy jeszcze jedną funkcję, która podczas nadawania i odbierania umożliwi sprawdzenie, czy układ jest gotowy do zapisania kolejnego bajtu do nadania lub czy odebrany został już cały bajt i można go odczytać z bufora układu.

uint8_t Rfm_ready_wait(void){
	uint8_t i=0;
	
	CS_PORT &= ~(1<<CS_RFM);//załączam pin CS układu
	_delay_us(1);//czekam nieco aby układ mógł zareagować
	
	while(!((1<<SPI_MISO)&SPI_PIN)){//następnie co 1ms sprawdzam, czy układ jest wolny, tzn, czy wystawił na linii MISO 1.
		_delay_ms(1);
		if((++i)==200){
			return 1;//po ok. 200ms przerywam oczekiwanie i zwracam 1 - czyli sygnalizuję błąd
		}
	}
	return 0;//jeśli pętla zostanie przerwana z powodu wystąpienia stanu wysokiego na linii MISO to zwracam 0 - nie ma błędu
}

Funkcja ta na początku aktywuje układ RFM12B, a następnie oczekuje na wystąpienie stanu wysokiego na linii MISO – w ten sposób RFM sygnalizuje gotowość.

Ponadto, prezentowana funkcja nie będzie oczekiwała w nieskończoność. Jeśli układ RFM nie da sygnału o gotowości w przeciągu 200ms (gdyż np. nie odbierze w tym czasie żadnych danych, bo nikt do niego nie nadaje), funkcja zwróci wartość 1, co oznacza, że w tym czasie układ nie odpowiedział.

Pierwsze odbieranie

Teraz, kiedy wiemy już jak wstępnie skonfigurować moduł radiowy, przyszedł czas na napisanie oprogramowania dla odbiornika i nadajnika. Zacznijmy od tego pierwszego:

Rfm_spi_init();//inicjalizacja magistrali SPI
	uart_init(9600);//inicjalizacja USART
	sei();//włączamy przerwania do obsługi uart

	uart_puts("rnrnRFM12B - RECEIVERrn");//wyświetlamy powitanie
	
	Rfm_init();//inicjalizujemy układ RFM12B
	
	Rfm_xmit(SYNC_PATTERN|0xD4);
	//ustawiamy programowalny bajt synchronizacji na wartość 0xD4
	//wykorzystamy tę funkcjonalność do adresowania wielu układów
	
	//włączamy odbiornik
	Rfm_xmit(POWER|EN_RX|EN_BASEBAND|EN_OSC|DIS_CLKO);
	_delay_ms(5);
	
	while(1){
		//para komend powodująca w efekcie działania reset synchronizacji odbiornika
		Rfm_xmit(FIFO_RST|FIFO_IT_8|HS_RST_DIS);
		Rfm_xmit(FIFO_RST|FIFO_IT_8|EN_AFT_SYNC|HS_RST_DIS);
		
		uint8_t timeout=Rfm_ready_wait();//oczekujemy na odebranie przez układ danych
		if(timeout){//i w zależności od tego czy układ odpowiedział
			//albo wyświetlamy informacje o braku odebranych danych
			uart_puts("NO INCOMING DATArn");
		}else{
			//albo odbieramy dane z bufora
			uint8_t data=Rfm_xmit(FIFO_READ);
			//i wyświetlamy je
			sprintf(bufor,"INCOMING DATA:%drn",data);
			uart_puts(bufor);
		}
	}

Jak widać, program odbiornika jest niezwykle prosty:

  1. Po inicjalizacji układu ustawiamy wspomniany wcześniej bajt synchronizacji na wartość 0xD4.
  2. Włączamy tryb odbiornika i układ oscylatora.
  3. Ww pętli głównej na początku resetujemy synchronizację tak, aby kolejne dane układ zaczął odbierać dopiero po przesłaniu 5 bajtów synchronizacyjnych.
  4. Teraz musimy poczekać na odpowiedź układu RFM, który poinformuje nas, jeśli odbierze jakieś dane. W przeciwnym wypadku po ok. 200ms program wyświetli komunikat o braku danych.
  5. Jeśli dane zostaną odebrane, to wówczas odczytujemy 1 bajt z bufora układu RFM (tyle będzie nadawał nadajnik) i wyświetlamy jego wartość.

Nadawanie

Do czego byłby nam przydatny odbiornik, do którego nie miałby kto nadawać! W tym przypadku, w celach demonstracyjnych, oprócz podpiętego układu RFM12B, podłączmy do pinów PB0 i PB1 przyciski zwierające do masy i przyjrzyjmy się poniższemu programowi:

Rfm_spi_init();//inicjalizacja magistrali SPI
	
	Rfm_init();//wstępna konfiguracja układu RFM12B
	
	DDRB &= ~((1<<PB0)|(1<<PB1));//konfiguruję piny PB0-1 jako wejście
	PORTB |= (1<<PB0)|(1<<PB1);//i włączam podciąganie
	
	uint8_t data;
	
	while(1){
		//sprawdzam przyciski i ustawiam odpowiednie bity w bajcie do nadania
		data = 0;
		if(!(PINB&(1<<PB0))){
			data |= 1;
		}
		if(!(PINB&(1<<PB1))){
			data |= 2;
		}
		if(data==0)continue;//jeśli nic nie wciśnięto to rozpoczynamy pętlę od początku
		
		//włączamy nadajnik
		Rfm_xmit(POWER|EN_TRANSMISSION|EN_SYNTH|EN_OSC|DIS_CLKO);
		//nadajemy 3 bajty synchronizacji (0xAA)
		//dwa pierwsze są już domyślnie umieszczone w buforze nadawczym po komendzie włączającej nadajnik
		Rfm_ready_wait();
		Rfm_xmit(TX_WRITE|0xAA);
		//następnie kolejny bajt synchrnoizacji (0x2D)
		Rfm_ready_wait();
		Rfm_xmit(TX_WRITE|0x2D);
		Rfm_ready_wait();
		//oraz definiowalny bajt synchronizacji (czyli nasz adres)
		Rfm_xmit(TX_WRITE|0xD4);
		Rfm_ready_wait();
		Rfm_xmit(TX_WRITE|data);
		Rfm_ready_wait();
		//oraz pusty bajt - konieczny by poprawnie zakończyć trnasmisję
		Rfm_xmit(TX_WRITE|0xAA);
		Rfm_ready_wait();
		//następnie czekamy na zakończenie transmisji
		uint16_t status;
		do 
		{
			status=Rfm_xmit(STATUS_READ);
		} while (!(status&M_TX_READY));
		//i wyłączamy nadajnik
		Rfm_xmit(POWER|DIS_CLKO);
		_delay_ms(100);
	}

 

Program po inicjalizacji układu i konfiguracji pinów do obsługi przycisków, sprawdza, czy którykolwiek z przycisków został przyciśnięty. Jeśli tak, to wykonywane są instrukcje obsługi modułu radiowego:

  1. Włączamy tryb nadawania i oscylator, po czym czekamy chwilę na reakcję układu.
  2. Każdorazowo czekamy aż układ będzie gotowy do przyjęcia kolejnej porcji danych.
  3. Wysyłamy 3-krotnie bajt o wartości 0xAA (I część synchronizacji).
  4. Wysyłamy bajt o wartości 0x2D (II część synchronizacji).
  5. Wysyłamy bajt o wartości 0xD4 – jest to definiowalny bajt synchronizacji, który my wykorzystamy np. jako adres układu. Już teraz możecie sprawdzić, że zmiana tego bajtu na różne wartości w nadajniku i odbiorniku spowoduje całkowity brak komunikacji.
  6. Wysyłamy nasze dane – w tym przykładzie jeden bajt.
  7. Wysyłamy 1 bajt o jakiejkolwiek wartości, aby móc wyłączyć odbiornik w odpowiednim momencie.
  8. Czekamy, aż ostatnio wpisany bajt (u nas 0xAA) będzie nadawany (zwolni się miejsce w buforze, co zasygnalizuje odpowiedni bit w rejestrze statusu) i wyłączamy nadajnik.

Tym oto sposobem w terminalu podpiętym do układu MASTER (odbiornika) powinniśmy zobaczyć efekt podobny do tego:

02_terminal

Gdzie 1 - oznacza wciśnięcie pierwszego przycisku, 2 – drugiego, a 3 - obu.

W ten sposób wykonaliśmy prosty pilot radiowy, który informuje nas o wciśnięciu przycisków! Posiada on jednak kilka mniej lub bardziej istotnych wad, ale o tym porozmawiamy w kolejnej części – tymczasem możemy pobawić się w zdalne miganie diodami LED, odpowiednio modyfikując przedstawione programy.

« Poprzedni artykuł z seriiNastępny artykuł z serii »

Załączniki

avr, komunikacja, RFM12B, SPI

Trwa ładowanie komentarzy...