/*************************************************************************
copyright (c) 2011                              
Title:             RFM22B transciever simple example based on PIC C  
Current version:   v1.0 
Function:          Package send Demo 
Processor          PIC16F690S-20 
Clock:             8MHz internal RC 
Operate frequency: 434MHz/869M/915M 
Data rate:         2.4kbps/4.8kbps/9.6kbps 
Working mode:	   PH+FIFO
modulation:		   FSK
Package size:      17byte valid data 
Author:            Baiguang(ISA) 
Company:           Hope microelectronic Co.,Ltd. 
Contact:           +86-0755-82973805-846 
E-MAIL:            rfeng@hoperf.com   
Date:              2011-07-20  
************************************************************************/
/************************************************************************
In our code we use the IO port of MCU to control the TX_EN and RX_EN.
                	 ---------------
         	       |VDD         VSS|
 	   TXEN----    |RA5         RA0|	 ----SDN
       RXEN----    |RA4         RA1|	 ----
 	 	   ----    |RA3         RA2|     ----nIRQ
           ----    |RC5         RC0|     ----
  LED_GREEN----    |RC4         RC1|	 ----
 	       ----    |RC3         RC2|     ----
       nSEL----    |RC6         RB4|     ----SDI
        SDO----    |RC7         RB5|	 ----LED_RED
   	       ----    |RB7         RB6|	 ----SCK
			     	---------------
					pic16F690
You also could use the GPIOx pin of module to control the TX_EN and RX_EN.
GPIO0<--------->TX_EN
GPIO1<--------->RX_EN
The configure of the registers as following:
0x0bf2,						//	gpio0 for TX State (output) 
0x0cf5,						//	gpio1 for RX State (output) 
**************************************************************************/

#include<pic.h>
#include<math.h>

typedef unsigned char uchar;
typedef unsigned int  uint;
typedef unsigned char byte;
typedef unsigned int  word;

#define PACKET_LENGTH			30

#define RF22B_PWRSTATE_READY		0x0701
#define RF22B_PWRSTATE_TX			0x0709
#define RF22B_PWRSTATE_RX			0x0705
#define RF22B_PWRSTATE_POWERDOWN	0x0700
#define RF22B_PWRSTATE_SLEEP		0x0700

#define RF22B_PACKET_SENT_INTERRUPT				0x0504
#define RF22B_Tx_almost_empty_interrupt			0x0520
#define RF22B_Rx_almost_full_interrupt   		0x0510
#define RF22B_Rx_packet_received_interrupt   	0x0502


#define  nIRQ           	RA2
#define  TXEN           	RA4
#define  RXEN	        	RA5

#define  LED_GREEN			RC4
#define  nSEL				RC6
#define  SDO	        	RC7

#define  SDI           		RB4
#define  LED_RED			RB5
#define  SCK				RB6
#define  SDN                RA0

unsigned char count_50hz;
unsigned char ItStatus1, ItStatus2;
unsigned char RF_RXBUF[35];

typedef struct 
{
	unsigned char reach_1s				: 1;
	unsigned char reach_5hz				: 1;
	unsigned char flag_nIRQ				: 1;

}	FlagType;

FlagType	                Flag;

/***************MCU**********************/
void port_init(void);
void timer2_init(void);
void sub_program_1hz(void);

/************RF mode function***********/
void RF22B_init_parameter(void);
void GPIO_function_setting(void);
void frequency_setting(void);
void data_rate_setting(void);
void valid_data_packet_format_setting(void);
void tx_power_setting(void);
void tx_frequency_devation_setting(void);
void modulation_setting(void);
void to_rx_mode(void);
void to_tx_mode(void);
void clear_fifo(void);
void to_ready_mode(void);
void to_sleep_mode(void);

/************RF module reset****************/
void software_reset(void);
void hardware_reset(void); 
/********SPI timing function***********/
void Write0( void );
void Write1( void );
void send_read_address(unsigned char address);
unsigned char read_8bit_data(void);
void spi_write(unsigned int command);
unsigned char spi_read(unsigned char address);
/****************delay function***************/
void power_on_delay(void);
void delay_50ms(void);
void delay_200ms(void);
void delay_25ms(void);
void delay_5ms(void);
void delay_1ms(void);
/*****************RF parameter table****************/
const word GPIO_function_setting_table[3]={
					/****GPIO pin control*****/
					0x0bf4,						//	gpio0 for received data output
					0x0cef,						//	gpio 1 TX/RX data clk output
					0x0d00						//	gpio 2 micro-controller clk output,for test
				};
const word frequency_table[7]={
					/********frequency setting**********/
					0x7300,
					0x7400,						//No offset .Frequency offset could be use as Frequency compensation.(0x73\0x74)
					0x7553,
					0x7664,
					0x7700,						//434M center frequency settting (0x75\0x76\0x77)
				  	/*0x7573,
					0x7670,
					0x7780,*/					//869M center frequency settting (0x75\0x76\0x77)
				  /*0x7575, 
					0x76bb, 
					0x7780,*/					//915M center frequency settting (0x75\0x76\0x77)
					/*********frequency hopping*********/
					0x7900,
					0x7a00						//no hopping(0x79/0x7a)
				};
const word data_rate_table[11]={
					/*****Tx data_rate****/
				    0x6e13,
					0x6fa9,						//2.4kbps
				  /*0x6e27,
					0x6f52,*/					//4.8kbps
			      /*0x6e4e,
					0x6fa5,*/					//9.6kbps
			/**************************************************/					
					/********RX data rate--2.4k******/
				    0x1c1d,
					0x1d40,						// enable afc
					0x2041,
					0x2160,						
					0x2227,						
					0x2352,
					0x2400,
					0x2506,
					0x2a1e						//2.4kbps, receive bandwide setting
					/********RX data rate--4.8k******/
				  /*0x1c1d,
					0x1d40,						// enable afc
					0x20a1,
					0x2120,						
					0x224e,						
					0x23a5,
					0x2400,
					0x2513,
					0x2a1e*/					//4.8kbps, receive bandwide setting
					/********RX data rate--9.6k******/
				  /*0x1c1e,
					0x1d40,						// enable afc
					0x20d0,
					0x2100,						
					0x229d,						
					0x2349,
					0x2400,
					0x2545,
					0x2a20*/					//9.6kbps, receive bandwide setting
				};
const word valid_data_packet_format_table[23]={
					0x7020,						//	disable manchest Please take attention to the txdtrtscale(5) bit  This bit should be set for Data Rates below 30 kbps. 
					/********PH*************/
					0x308c,						//	enable packet handler, msb first, enable crc,
						   						//	0x31 only readable	
					0x32ff,						//   0x32address enable for headere byte 0, 1,2,3, receive header check for byte 0, 1,2,3
					0x3342,						//	header 3, 2, 1,0 used for head length, fixed packet length, synchronize word length 3, 2,
					/*******2byte synchronize word******/
					0x362d,						//0x2d
					0x37d4,						//0xd4
					0x3800,
					0x3900,
			/***********************************************************/
					//****set Tx preamble length*****/
					0x3464,						//32byte preamble
					/*****set TX header*****/
					0x3a73,						//'s'
					0x3b6f,						//'o'
					0x3c6e,						//'n'
					0x3d67,						//'g'
					/*****set	Tx valid data length****/
					0x3e11,						//valid data 17byte	
			/************************************************************/
					0x3520,						//0x35 set the length of the detect preamble.(need to detect 16bit preamble)
					/******set RX_header**********/
					0x3f73,						//'s'
					0x406f,						//'0'
					0x416e,						//'n'
					0x4267,						//'g'
					0x43ff,						// all the bit to be checked
					0x44ff,						// all the bit to be checked
					0x45ff,						// all the bit to be checked
					0x46ff						// all the bit to be checked					
				};
const word tx_power_table[1]={
					/*****set power*****/
					0x6d0f						//max power 20dbm
				};
const word tx_frequency_devation_table[1]={
					/****set Modulation frequency Deviation*****/
					0x7238						//35khz,
												/*Please take attention to config the receive bandwide.
												When calculate the receive bandwide,the value of transmite frequency deviation will more than the really value.
												For example in our code the really frequency deviation is 35khz,
												but When we calculate the receive bandwide,the value of transmite frequency deviation is 45khz.
												Do this ,the sensitivity of the receiver will be higher.*/
				};
const word modulation_table[1]={
					0x7122						//fsk, fd[8] =0, no invert for Tx/Rx data, fifo mode
				};							
const word to_tx_mode_table[2]={
					/****open Tx interrupt and open tx****/
					RF22B_PWRSTATE_TX,			//0x0709-----to tx mode
					RF22B_PACKET_SENT_INTERRUPT	//0x0504-----packet send over interrupt
				};
const word to_rx_mode_table[2]={
					/****open Rx interrupt and open rx****/
					RF22B_PWRSTATE_RX,			//0x0705----to rx mode
					RF22B_Rx_packet_received_interrupt//0x0502----packet received interrupt
				};
const word clear_fifo_table[2]={
					/*****clear fifo**********/
					0x0803,
					0x0800,						//clear fifo, disable multi packet
				};
const word to_ready_mode_table[3]={
					0x0600,
					0x0500,
					0x0701
				};
const word to_sleep_mode_table[3]={
					0x0600,
					0x0500,
					0x0700
				};

const word tx_buf_table[17] = {	0x7f30,0x7f31,0x7f32,0x7f33,
							   	0x7f34,0x7f35,0x7f36,0x7f37,
								0x7f38,0x7f39,0x7f3a,0x7f3b,
								0x7f3c,0x7f3d,0x7f3e,0x7f3f,0x7f78
							  };               //valid data

__CONFIG(0x3FF4);

void main()
{ 
	unsigned char  i, j, chksum;

	OSCCON = 0X70;					// 8M internal RC
	WDTCON = 0X00;
	
	power_on_delay();  				
	port_init();  	
	timer2_init();
	
	count_50hz = 0;
	Flag.reach_1s = 0;
	Flag.flag_nIRQ = 0;

	INTCON = 0xc0;   				// enable interrupt
	
	RF22B_init_parameter();
	to_rx_mode();

	while(1)
	{		
		sub_program_1hz();				
	
		if(!nIRQ)
		{ 		
			send_read_address(0x7f);
			for(i = 0; i<17; i++)
			{
				RF_RXBUF[i] = read_8bit_data();
			}				
			chksum = 0;  
        	for(i=0;i<16;i++)
        		chksum += RF_RXBUF[i];  
        			
     		if(( chksum == RF_RXBUF[16] )&&( RF_RXBUF[0] == 0x30 ))
     		{
        		LED_GREEN ^= 1;
        		//to_tx_mode();
        	}
        	else
        	{
				to_rx_mode();  	 // module reset to rx mode when packet wrong
        	}	
		}	
	}	
}

/**************************************
system power on delay
**************************************/
void power_on_delay(void)
{
	unsigned int i;
	for(i = 0; i<1000; i++)
	{
		delay_1ms();
	}	
}
/*************************************
init MCU port
*************************************/
void port_init(void) 
{ 
 	ANSEL = 0;
 	ANSELH = 0;
 	WPUA = 0;	// NO PULL UP
 	IOCA = 0;  // NO INTERRUPT ON CHANGE
	TRISA = 0x04;  // nIRQ input , RXEN TXEN OUTPUT
  	TRISB = 0x00;  // 
  	WPUB = 0x00; // 
  	TRISC = 0b10000000;
  	TXEN = RXEN = 0;
  	LED_GREEN = LED_RED = 0;
}		
/*************************************
init timer
**************************************/
void timer2_init(void)
{
	T2CON = 0x7f; // timer2 on and 16 pre, postscale
	PR2 = 156;  // 50hZ, 4m/4/16/16/50
	TMR2IE = 1;
}
/************************************
interrupt 
*************************************/
void interrupt ISR_timer(void)
{
 //	di();
 	unsigned char i;
	if(TMR2IF)
   	{
		count_50hz++;
    	if(count_50hz==50)  // REACH 1S
     	{
       		count_50hz=0;
       		Flag.reach_1s = 1;
       			
     	}		
     	else if(count_50hz == 5)
     	{
			Flag.reach_5hz = 1;
     	}	
     		
    	TMR2IF=0;
	}
	
}
/*************************************
1s deal
**************************************/  
void sub_program_1hz(void)
{
	if(Flag.reach_1s)
	{
		Flag.reach_1s = 0;
		to_tx_mode();	// TRANSIMITTE DATA
	}		
}
/***********************************
spi write 0
************************************/
void Write0(void)
{
  	SCK=0;  
  	NOP();
  	
  	SDI=0;
  	NOP();
  	
  	SCK=1;  
  	NOP();	
}
/***********************************
spi write 1
************************************/
void Write1(void)
{
	SCK=0;  
  	NOP();
  	
  	SDI=1;
  	NOP();
  	
  	SCK=1;  
  	NOP();
}
/***********************************************
When reading register,write address of register
***********************************************/
void send_read_address(unsigned char address)
{
	unsigned char n=8;
	
	address &= 0x7f;

  	nSEL = 1;
  	SCK=0;
  	nSEL=0;
  	while(n--)
   	{
     	if(address&0x80)
      		Write1();
     	else
      		Write0();
		
		address = address << 1;
   	}
  	SCK=0;
}	
/**********************************************************
When reading register,read the 8bit value of the register
***********************************************************/
unsigned char read_8bit_data(void)
{
	unsigned char Result,j;
	
	SCK=0;
	Result=0;
  	for(j=0;j<8;j++)
  	{                    //read fifo data byte
  	 	Result=Result<<1;
  	 	SCK=1;
  	 	NOP();
  	 	if(SDO)
  	 	{
  	 		Result|=1;
  	 	}
  	 	
  	 	SCK=0;
  	 	NOP();
  	}
  	return(Result);
}		
/*************************************
write value to register
**************************************/
void spi_write(unsigned int command)
{
	unsigned char n=16;

	command |= 0x8000;

  	nSEL = 1;
  	SCK=0;
  	nSEL=0;
  	while(n--)
   	{
     	if(command&0x8000)
      		Write1();
     	else
      		Write0();   
     
		command = command << 1;
   	}
  	SCK=0;
	NOP();
	nSEL = 1;	
}

/************************************
read value from register
*************************************/
unsigned char spi_read(unsigned char address)
{
	unsigned char result;

	send_read_address(address);
	result = read_8bit_data();	
	nSEL = 1;

	return(result);
}		
/******************************************
RFM22B parameter init
*******************************************/
void RF22B_init_parameter(void)
{
	unsigned char j;

	software_reset();

	RXEN = 0;
	TXEN = 0;
	
	to_ready_mode();
	GPIO_function_setting();
	frequency_setting();
	data_rate_setting();
	valid_data_packet_format_setting();
	tx_power_setting();
	tx_frequency_devation_setting();
	modulation_setting();	
}
/*******************************************
GPIO function setting
*******************************************/
void GPIO_function_setting(void)
{
	unsigned char j;
	
	for(j=0;j<3;j++) 
		spi_write(GPIO_function_setting_table[j]);	
}
/******************************************
frequency setting
******************************************/
void frequency_setting(void)
{
	unsigned char j;
	
	for(j=0;j<7;j++) 
		spi_write(frequency_table[j]);	
}
/******************************************
data rate setting
******************************************/
void data_rate_setting(void)
{
	unsigned char j;
	
	for(j=0;j<11;j++) 
		spi_write(data_rate_table[j]);	
}
/****************************************
valid data packet format setting
******************************************/
void valid_data_packet_format_setting(void)
{
	unsigned char j;

	for(j=0;j<23;j++) 
		spi_write(valid_data_packet_format_table[j]);	
}
/*****************************************
tx power setting
******************************************/
void tx_power_setting(void)
{
	spi_write( tx_power_table[0]);
}
/****************************************
tx_frequency_devation_setting
****************************************/
void tx_frequency_devation_setting(void)
{
	spi_write(tx_frequency_devation_table[0]);
}
/****************************************
modulation setting
*****************************************/
void modulation_setting(void)
{
	spi_write(modulation_table[0]);
}
/******************************************
go to rx mode
*******************************************/		
void to_rx_mode(void)
{		
	unsigned char j;

	to_ready_mode();
	
	TXEN = 0;
	RXEN = 1;
	//delay_50ms();

	clear_fifo();
	
	for(j=0;j<2;j++)
		spi_write(to_rx_mode_table[j]);	
}
/******************************************
go to tx mode
*******************************************/	
void to_tx_mode(void)
{
	unsigned char j,k;

	to_ready_mode();

loop:
	RXEN = 0;
	TXEN = 1;
	//delay_50ms();
	clear_fifo();

	for (k=0;k<17;k++)
		spi_write(tx_buf_table[k]);						//write the data to the TX FIFO register

	for(j=0;j<2;j++)
		spi_write(to_tx_mode_table[j]);					//to tx mode


	LED_RED  ^= 1;

	for(k=0;k<200;k++)								   //The length of time_out more than the time of transmitting one packet data.
	{
		for(j=0;j<200;j++)
		{
			if(!nIRQ)
			{
				Flag.flag_nIRQ = 1;
				break;
			}
		}
		if(k==199)
		{
			software_reset();          					//module software reset 
			delay_5ms();              					//delay 5ms,then re_Initialization the module
			
			RF22B_init_parameter();
			goto loop;
		}
		if(Flag.flag_nIRQ)
		{
			Flag.flag_nIRQ = 0;
			break;
		}
	}		
	//while(nIRQ);
	
	RXEN = 0;
	TXEN = 0;						
	to_rx_mode();	
	
}
/*************************************
clear the fifo
**************************************/
void clear_fifo(void)
{
	unsigned char j;

	for(j=0;j<2;j++)
		spi_write(clear_fifo_table[j]);
}
	
/*************************************
the module into ready mode 
**************************************/
void to_ready_mode(void)
{
	unsigned char j;
	ItStatus1 = spi_read(0x03);		
	ItStatus2 = spi_read(0x04);
	
	for(j=0;j<3;j++)
		spi_write(to_ready_mode_table[j]);
	
}
/*************************************
the module into sleep mode 
**************************************/
void to_sleep_mode(void)
{
	unsigned char j;
	ItStatus1 = spi_read(0x03);		
	ItStatus2 = spi_read(0x04);
	
	for(j=0;j<3;j++)
		spi_write(to_sleep_mode_table[j]);	
}
/*************************************
the reset of software 
**************************************/
void software_reset(void)
{
	unsigned char j;
	spi_write(0x0780);
	for(j=0;j<250;j++)					//200us~600us
	{
		if(!nIRQ)
		{
			ItStatus1 = spi_read(0x03);		
			ItStatus2 = spi_read(0x04);
			break;
		}
		if(j==249)
		{
			hardware_reset();			//hardware reset
		}	
	}
}
/*************************************
the reset of hardware
**************************************/
void hardware_reset(void)
{
	unsigned char k;

	SDN = 1;
	delay_5ms();
	SDN = 0;
	for(k=0;k<250;k++)
	{
		if((!nIRQ)&&(k>=249))
		{
			break;				//
		}
		else if((!nIRQ)&&(k<=249))
		{
			delay_25ms();		//delay some time,then re_Initialization the module
			break;
		}
	}			
}
/***********************************
delay 200ms
************************************/
void delay_200ms(void)
{
	unsigned char j;
	for(j = 0; j<40; j++)
	{
		delay_5ms();	
	}	
}
/***********************************
delay 50ms
************************************/	
void delay_50ms(void)
{
	unsigned char  j;
	for(j = 0; j<10; j++)
	{
		delay_5ms();	
	}	
}
/***********************************
delay 25ms
**************************************/
void delay_25ms(void)
{
	unsigned char  j;
	for(j = 0; j<5; j++)
	{
		delay_5ms();	
	}
}
/***********************************
delay 5ms
************************************/
void delay_5ms(void)
{
	unsigned int i;
	for(i = 0; i<650; i++)
	{
		;
	}	
}	
/***********************************
delay 1ms
************************************/
void delay_1ms(void)
{
	unsigned char i;
	for(i = 0; i<130; i++)
	{
		;
	}	
}

  

