Komunikace modulů RFM12B/868D

Jiří Dvořák, Libor Boleček
xdvora87stud.feec.vutbr.cz, xbolec01stud.feec.vutbr.cz 

Obsah:

  1. Úvod
  2. Realizace
  3. Závěr
  4. Soubory
  5. Literatura

Úvod

Cílem tohoto projektu je sestavení komunikace dvou mikrokontrolérů ATMega16, využívající bezdrátové digitální moduly RFM12B/868D v pásmu ISM. Výchozím vodítkem pro napsání programu je ukázkový kód zveřejněný výrobcem v datasheetu modulu. Jeden modul bude naprogramován do přijímacího módu a druhý modul bude v módu vysílacím. Komunikace modulů s mikrokontolérem probíhá přes rozhraní SPI. Moduly jsou vhodné pro dálkové řízení, přenos dat ze senzorů, zabezpečovací systémy aj.

Realizace

Modul RFM12B/868D komunikuje na frekvenci 868MHz. Rozsah pracovních napětí je 2,2V až 3,8V. Udávaná citlivost -102dBm, max. výkon 7dBm. Ostatní parametry možno najít v [1]. Základní piny modulu jsou VDD (kladný pól napájení), GND (zem), SDI (vstup data SPI), SDO (výstup data SPI), SCK (hodiny SPI), NSEL (chip select funkční jako povolovací pin v nízké úrovni), NIRQ (požadavek přerušení) Ostatní piny možno najít v [1]. Pouzdro modulu má piny vyvedené na kolíkovou lištu s nestandardní roztečí 2mm viz obr.1. Lišty pro připojení externích modulů na vývojové desce v laboratoři mají dutinky ve dvou řadách s roztečí 2,54mm. Prvním úkolem tedy bylo vyrobit pinovou redukci pro připojení na vývojovou desku.

Pouzdro

Obr.1: Pouzdro modulu převzato z [1].

Zároveň však bylo nutné doplnit redukci o usměrňovač na potřebných 3,8V pro provoz modulu a zajistit stejné napětí na vstupních a výstupních pinech předřadnými odpory. Schéma zapojení redukce je na obr.2 a předlohy pro oboustanou desku plošných spojů (měřítko 1:1) na obr.3.

Schéma

Obr.3: Schéma regukce.

Předlohy

Obr.3: Předlohy pro desku plošných spojů (top a bottom) zrcadlově 1:1.

Vyhotovené redukce, osazené moduly a připravené pro zapojení do vývojové desky jsou na obr.4.

Redukce

Obr.3: Předlohy pro desku plošných spojů (top a bottom) zrcadlově 1:1.

Redukce se připojuje do spodní části patice portu B na vývojové desce. Po zastrčení do desky je realizování propojení VDI, GND, SCK, SDO, SDI a NSEL. Jednotlivé funkční piny jsou pro modul RFM12B a ATMega16 popsány rozdílně. Schéma propojení je na obr.4. Propojení je tedy chápáno následovně:

Předlohy

Obr.3: Propojení s portem B vývojové desky (zastrčení) a propojení s portem D (drátově)

Zastrčením redukce do patice pro port B na vývojové desce a nadrátováním přerušení NIRQ na pin2 portu D tak vznikne potřebné zapojení.

Základní kód, ze kterého byl odvozen námi použitý kód je k nalezení v [1]. Tento kód dodávaný výrobcem však obsahoval chyby, které musely být odhaleny.

KÓD VYSÍLAČE

#include 
#include ".\avr\interrupt.h"


/* makra pro praci s SPI rozhrani */				
#define SCK 7 				/*SPI clock*/
#define SDO 5 				/*SPI data vystup*/
#define SDI 6 				/*SPI data vstup*/
#define CS 4 				/*SPI chip select*/
#define NIRQ 2 

/* vstupne-vystupni rizeni */
#define HI(x) PORTB |= (1<<(x))			/*nastaveni bitu x portu B do log. urovne 1*/	
#define LO(x) PORTB &= ~(1<<(x))		/*nastaveni bitu x portu B do log. urovne 0*/
#define WAIT_NIRQ_LOW() while(PIND & (1<<NIRQ))	/*kontrola preruseni na INT0*/

/* LED */
#define LED 6				
#define LED_ON() PORTD &= ~(1<<LED)	/*rozsviceni LED na bitu 6 portu D pomoci log. urovne 0*/
#define LED_OFF() PORTD |= (1<<LED)	/*zhasnuti LED na bitu 6 portu D pomoci log. urovne 1*/


/* standardni inicializace portu pro SPI */
void portInit() 
{
HI(CS);
HI(SDI);
LO(SCK);
DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);	/*definovani prislušných pinů portu B jako vystupnich*/
DDRD = (1<<LED);

}

/* SPI posilani 16-bitoveho cmd */
unsigned int writeCmd(unsigned int cmd) {
unsigned char i;
unsigned int recv;
recv = 0;
LO(SCK);					/*CLK v urovni low*/
LO(CS);						/*CHIP SELECT v urovni low = aktivace obvodu vysilace na SPI*/
for(i=0; i<16; i++) {				/*smycka pro zasilani 16-bit dat*/
if(cmd&0x8000) HI(SDI); else LO(SDI);
HI(SCK);					/*CLK v urvni high = puls hodin*/
recv<<=1;
if( PINB&(1<<SDO) ) {
recv|=0x0001;
}
LO(SCK);					/*CLK v urovni low = ukonceni pulsu*/
cmd<<=1;					/*posuv na dalsi bit dat*/
}
HI(CS);						/*CHIP SELECT v urovni high = deaktivace obvodu vysilace na SPI - ukonceni komunikace*/
return recv;					
}

/*inicializace modulu vysilace dle manualu*/
void rfInit() {
writeCmd(0x80E7); //EL,EF,868band,12.0pF
writeCmd(0x8239); //!er,!ebb,ET,ES,EX,!eb,!ew,DC
writeCmd(0xA640); //frequency select
writeCmd(0xC647); //4.8kbps
writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR
writeCmd(0xCED4); //SYNC=2DD4 , AG
writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
writeCmd(0x9850); //!mp,90kHz,MAX OUT
writeCmd(0xCC17); //OB1 , ACOB0, LPX,Iddy,CDDIT,CBW0
writeCmd(0xE000); //NOT USED
writeCmd(0xC800); //NOT USED
writeCmd(0xC040); //1.66MHz,2.2V
}

/*fce zaslani dat vysilaci*/
void rfSend(unsigned char data)
{
while(PIND & (1<<NIRQ))
	writeCmd(0xB800 + data);

	char lcd_vystup[16];
	lcd_init();				/*inicializace displeje*/
	lcd_clrscr();				/*vymazani displeje*/
	sprintf(lcd_vystup,"%d",data);		/*formatovani pro displej*/
	lcd_puts(lcd_vystup);			/*vystup na displej*/
}

int main()
{
volatile unsigned int i,j;
asm("cli");
for(i=0;i<1000;i++)for(j=0;j<123;j++);		/*startovaci prodleva*/
portInit();					/*inicializace portu*/
rfInit();					/*inicializace vysilace*/
while(1)
	{
	LED_OFF();				/*vypnuti LED*/
	writeCmd(0x0000);			/*vycteni status registru*/
	rfSend(0xAA); 				/*zaslani hlavicky zpravy - dle datasheetu*/
	rfSend(0xAA);
	rfSend(0xAA);
	rfSend(0x2D); 				/*synchronizace*/
	rfSend(0xD4);
	for(i=0; i<16; i++)
		{
		rfSend(0x30+i);			/*vysilana data*/
		}
	rfSend(0xAA); 				/*3 volitelne byty na zaver*/
	rfSend(0xAA);
	rfSend(0xAA);
	LED_ON();				/*rozsviceni LED*/
	for(i=0; i<10000; i++) 
	for(j=0; j<123; j++); 			/*prodleva po kazdem vysilani*/
	}
}




KÓD PŘIJÍMAČE

#include 
#include ".\avr\interrupt.h"
#include "lcd_h.h"

/* makra pro praci s SPI rozhrani */
#define SCK 7 				/*SPI clock*/
#define SDO 5 				/*SPI data vystup*/
#define SDI 6 				/*SPI data vstup*/
#define CS 4 				/*SPI chip select*/
#define NIRQ 2 

/* vstupne-vystupni rizeni */
#define HI(x) PORTB |= (1<<(x))			/*nastaveni bitu x portu B do log. urovne 1*/
#define LO(x) PORTB &= ~(1<<(x))		/*nastaveni bitu x portu B do log. urovne 0*/
#define WAIT_NIRQ_LOW() while(PIND&(1<<NIRQ))	/*kontrola preruseni na INT0*/

/* LED */
#define LED 6
#define LED_ON() PORTD &= ~(1<<LED)		/*rozsviceni LED na bitu 6 portu D pomoci log. urovne 0*/
#define LED_OFF() PORTD |= (1<<LED)		/*zhasnuti LED na bitu 6 portu D pomoci log. urovne 1*/

#define BAUDRATE 25  				/*Baud rate 19200 at 8MHz*/

/*inicalizace RS232*/
void rsInit(unsigned char baud) {
UBRRL = baud;					/*nastaveni Baud rate dle zadane baud*/
UCSRC = (1<<UCSZ0) | (1<<UCSZ1); 		/*nastaveni formatu 8bitu data, 1 stop bit*/
UCSRB = (1<<RXEN) | (1<<TXEN); 			/*povoleni vysilani i prijimani*/	
}

/*zaslani dat po RS232*/
void rsSend(unsigned char data) {
while( !(UCSRA & (1<<UDRE)));
UDR = data;					/*ulozeni dat do vysilaciho registru RS232*/
}

/*cteni dat z RS232*/
unsigned char rsRecv() {
while( !(UCSRA & (1<<RXC)));
return UDR;					/*vycteni dat z prijimaciho registru RS232*/
}

/* standardni inicializace portu pro SPI */
void portInit() {
HI(CS);
HI(SDI);
LO(SCK);
DDRB = (1<<CS) | (1<<SDI) | (1<<SCK);
DDRD = (1<<LED);
}

/* SPI posilani 16-bitoveho cmd */
unsigned int writeCmd(unsigned int cmd) {
unsigned char i;
unsigned int recv;
recv = 0;
LO(SCK);					/*CLK v urovni low*/
LO(CS);						/*CHIP SELECT v urovni low = aktivace obvodu prijimace na SPI*/
for(i=0; i<16; i++) {				/*smycka pro zasilani 16-bit dat*/
if(cmd&0x8000) HI(SDI); else LO(SDI);
HI(SCK);					/*CLK v urvni high = puls hodin*/
recv<<=1;
if( PINB&(1<<SDO) ) {
recv|=0x0001;
}
LO(SCK);					/*CLK v urovni low = ukonceni pulsu*/
cmd<<=1;					/*posuv na dalsi bit dat*/
}
HI(CS);						/*CHIP SELECT v urovni high = deaktivace obvodu prijimace na SPI - ukonceni komunikace*/
return recv;
}

/*inicializace modulu vysilace dle manualu*/
void rfInit() 
{
writeCmd(0x80E7); //EL,EF,868band,12.0pF
writeCmd(0x8299); //er,!ebb,ET,ES,EX,!eb,!ew,DC (bug was here)
writeCmd(0xA640); //freq select
writeCmd(0xC647); //4.8kbps
writeCmd(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm
writeCmd(0xC2AC); //AL,!ml,DIG,DQD4
writeCmd(0xCA81); //FIFO8,SYNC,!ff,DR (FIFO level = 8)
writeCmd(0xCED4); //SYNC=2DD4;
writeCmd(0xC483); //@PWR,NO RSTRIC,!st,!fi,OE,EN
writeCmd(0x9850); //!mp,90kHz,MAX OUT
writeCmd(0xCC17); //!OB1,!OB0, LPX,!ddy,DDIT,BW0
writeCmd(0xE000); //NOT USE
writeCmd(0xC800); //NOT USE
writeCmd(0xC040); //1.66MHz,2.2V
}

/*prijimani dat prijimacem*/
unsigned char rfRecv() 
{
unsigned int data;
	while(1)
		{
		data = writeCmd(0x0000);		/*vycteni status registru prijimace*/
		if ( (data&0x8000) )			/*kontrola nastaveni MSB status registru*/
			{
			data = writeCmd(0xB000);	/*vycteni dat z fifo*/
			return (data&0x00FF);		
			}
		}
}

/*reset FIFO zasobniku prijimace dle Datasheetu*/
void FIFOReset() 
{
	writeCmd(0xCA81);
	writeCmd(0xCA83);
}

int main(void)
{
unsigned char data, i;
char lcd_vystup[16];
portInit();
rfInit();					/*inicializace SPI*/
rsInit(BAUDRATE);				/*inicializace RS232*/
FIFOReset();					/*reset FIFO zasobniku prijimace*/
lcd_init();					/*inicializace displeje*/
lcd_clrscr();					/*vymazani displeje*/

while(1) {
//waitForData();
LED_ON();					/*rozsviceni LED*/
for (i=0; i<16; i++)				/*vycteni prijatych dat polling metodou*/
	{
	data = rfRecv();
        sprintf(lcd_vystup,"%d",data);		/*formatovani pro displej*/
	lcd_puts(lcd_vystup);			/*vypis na displej*/
	LED_OFF();				/*zhasnuti LED*/
	//rsSend(data);
	}
	
FIFOReset();					/*reset FIFO zasobniku prijimace*/

}
return 0;
}

Závěr

Kód by zkomlipován bez chyb a nahrán do mikrokontrolérů. U vysílače jsou na LCD displeji zobrazeny data posílaná do modulu a průběh odesílání je signalizován LED diodou. Nepodařilo se ověřit, zda-li jsou data správně zpracovávány modulem a jsou-li vysílána. U přijímače by se na LCD měla zobrazovat přijatá data, ale k tomu nedochází. Není jisté, zda je funkce přijímače správná a data nejsou vysílána, nebo jsou vysílána, ale přijímač nepracuje správně. Bohužel až pozdě byla objevena stránka s návodem jak modul rozchodit. V oficiální dokumentaci se pravděpodobně vyskytují chyby.

Soubory

Deska plošných spojů - bottom
Deska plošných spojů - top
Kód přijímače
Kód vysílče

Literatura

[1] HOPE RF. Universal ISM band FSK tranciever modula RFM12b [online]. [citováno 20.5.2009]. Dostupný z WWW: <http://zefiryn.tme.pl/dok/wd1/rfm12b.pdf>
[2] RFM12b and AVR - quick start [online]. [citováno 20.5.2009]. Dostupný z WWW:
<http://zenburn.net/~goroux/rfm12b/rfm12b_and_avr-%20quick_start.pdf>