XBee interface with PIC18F4550

XBee interface with PIC18F4550

Introduction

XBee radios are based on IEEE 802.15.4 (technical standard which defines the operation of low-rate wireless personal area networks (LR-WPANs)) standard and it is designed for point to point, star etc. communication over the air.
Following are the major features of XBee radio devices ,
  • They work on 2.5GHz (Unlicensed Radio Band) radio frequency.
  • Low data rate (≈250Kbps).
  • Low power consumption (1mW, 6mW, 250mW etc.).
  • Over short distance (90m, 750m, 1mile etc.) wireless communication applications
Hence they are used in Home Automation, Wireless sensor n/w, Industrial control, Medical data collection, Building automation etc .
To know more about how Xbee module works, refer XBee Module.
XBee Module
XBee Module
Interfacing of XBee device with PIC18F4550
Here, we have connected the following to the XBee End Device
  • LM35 Temperature sensor as analog sample
  • Switch as digital sample
Now we request those analog and digital samples from XBee End Device using XBee Coordinator.
Now let’s program PIC18F4550 to request Analog and Digital samples from XBee end device through XBee coordinator. Both XBee are used API operating mode.
We are displaying status of the switch in digital form (0 for OFF and 1 for ON), and the LM35 temperature received by the XBee Coordinator Device on the 16x2 LCD connected to PIC18F4550 .
Note that ADC Vref is varying according to XBee Model. Refer ADC Voltages to find Vref of your model.
The XBee model we are using is based on ZigBee protocol and it has a fixed Vref of 1.2V.

Interfacing Diagram

XBee interface with PIC18F4550
XBee Interfacing with PIC18F4550
Note: In above example, we need to configure XBee End Device pins (AD1/DIO1 & AD2/DIO2) as Analog and Digital input. Refer configuring XBee pins section in XBee Module.
Need to know
Here we are using XBee in API mode so for basic communication purpose we are building some basic frames like
  • AT COMMAND FRAME: -
    • Using this frame, we can send AT command to XBee device.
  • REMOTE AT COMMAND FRAME: -
    • Using this frame, we can send AT command to XBee device located at remote location with their address specified in frame.
  • TRANSMIT REQUEST FRAME: -
    • Using this frame, we can transmit data string to XBee device with their address specified in frame.
  • IO DATA SAMPLE FRAME: -
    • Using this frame, we receive analog/digital data transmitted by XBee device located at remote location with their address specified in frame.
In below program, we are using functions that build the above-mentioned frames structure. API frame structure functions are lengthy, but easy to understand once we know each API Frame structure.
To be familiar with API frames and their structure refer API Frame Generator in X-CTU section in XBee Module.

Program

/*
 * PIC18F4550 interface with X-Bee 
 * http://www.electronicwings.com
 */


#include <pic18f4550.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "Configuration_header_file.h"
#include "LCD_16x2_Header_File.h"   /* Include LCD header file */
#include "USART_Header_File.h"      /* Include USART header file */

/* Define Required XBee Frame Type and Responses */
#define START_DELIMITER                     0x7E
#define AT_COMMAND_FRAME                    0x08
#define TRANSMIT_REQUEST_FRAME              0x10
#define REMOTE_AT_COMMAND_FRAME             0x17
#define IO_DATA_SAMPLE_FRAME                0x92
#define AT_COMMAND_RESPONSE_FRAME           0x88
#define REMOTE_AT_COMMAND_RESPONSE_FRAME    0x97
#define RECEIVE_PACKET_FRAME                0x90
#define TRANSMIT_STATUS_FRAME               0x8B

#define FRAME_ID                            0x01
#define REMOTE_AT_COMMAND_OPT               0x02
#define TRANSMIT_REQUEST_OPT                0x00
#define TRANSMIT_REQUEST_BROADCAST_RADIUS   0x00

#define Read                                0
#define Write                               1


#define BUFFER_SIZE       100
#define DIGITAL_BUFFER_SIZE      16
#define ANALOG_BUFFER_SIZE      8

uint8_t  ReceiveBuffer[BUFFER_SIZE];
int8_t  DigitalData[DIGITAL_BUFFER_SIZE];
int16_t  AnalogData[ANALOG_BUFFER_SIZE];
uint16_t BufferPointer = 0,
  LastByteOfFrame = 0; 
uint32_t Command_Value = 0;

bool   _IsContainsDigital = false,
   _IsContainsAnalog = false; 

bool Is_Data_Received()  /* Check wether data received or not  */
{
 for (uint8_t i = 0; i < BUFFER_SIZE; i++)
 {
  if (ReceiveBuffer[i] != 0 && i > 0)
   return true;
 }
 return false;
}

bool Is_Checksum_Correct() /* Check wether received data is correct */
{
 uint16_t checksum = 0;
 for(uint8_t i = 3; i < LastByteOfFrame; i++)
  checksum = checksum + ReceiveBuffer[i];
 checksum = 0xFF - checksum;
 if(ReceiveBuffer[LastByteOfFrame] == (uint8_t)checksum &&
  LastByteOfFrame > 0)
  return true;
 else
  return false;
}

/* Sample function for parsing received buffer as per frame type */
void sample()
{
    uint8_t Frame_Type, Is_Analog;
    uint16_t Length, Is_Digital, Digital_Value;
 
    _IsContainsAnalog = false;
    _IsContainsDigital = false;

    /* 2 byte Frame length is at 1st and 2nd position of frame */
    Length = ((int)ReceiveBuffer[1]<<8) + ReceiveBuffer[2];
    /* 1 byte Frame type is at 3rd position of frame */
    Frame_Type = ReceiveBuffer[3];

    switch (Frame_Type)
     {
 case (IO_DATA_SAMPLE_FRAME): /* Parse received I/O data sample frame */
   if(Is_Data_Received() == false || Is_Checksum_Correct() == false) break;
   Is_Digital = ((int)ReceiveBuffer[16]<<8) + ReceiveBuffer[17];
   Is_Analog = ReceiveBuffer[18];
   Digital_Value = ((int)ReceiveBuffer[19]<<8) + ReceiveBuffer[20];
 
   if(Is_Analog != 0)
    _IsContainsAnalog = true;
   if(Is_Digital != 0)
    _IsContainsDigital = true;
/****** Check For whether sample contains Analog/Digital Sample *********/  

   for (uint8_t i = 0; i < DIGITAL_BUFFER_SIZE; i++)
    {
  if(((Is_Digital >> i) & 0x01) == 1 && ((Digital_Value>>i) & 0x01) != 0)
   DigitalData[i] = 1;
  else if(((Is_Digital >> i) & 0x01) == 1 && ((Digital_Value>>i) & 0x01) == 0)
   DigitalData[i] = 0;
  else
   DigitalData[i] = -1;
    }
   
   for (uint8_t i = 0, j = 0; i < ANALOG_BUFFER_SIZE; i++)
    {
     if(((Is_Analog >> i) & 0x01) == 1)
      {
  if(Is_Digital != 0)
  AnalogData[i] = 256 * ReceiveBuffer[21+(j*2)] + ReceiveBuffer[22+(j*2)];
  else
  AnalogData[i] = 256 * ReceiveBuffer[19+(j*2)] + ReceiveBuffer[20+(j*2)];
  j++;
      }
     else
      {
  AnalogData[i] = -1;
      }
    }

 case (TRANSMIT_STATUS_FRAME):/* Parse received Transmit status frame */
   if(Is_Data_Received() ==false || Is_Checksum_Correct() ==false) break;
   break; /* Check whether frame is correctly received or not */
 case (RECEIVE_PACKET_FRAME):
   if(Is_Data_Received() ==false || Is_Checksum_Correct() ==false) break;
   break;
 case (REMOTE_AT_COMMAND_RESPONSE_FRAME):
   if(Is_Data_Received() ==false || Is_Checksum_Correct() ==false) break;
   break;
 case (AT_COMMAND_RESPONSE_FRAME):
   if(Is_Data_Received() ==false || Is_Checksum_Correct() ==false) break;
   break;
 default:
   break;
     }
}

bool Get_Sample() /* Get sample function */
{
 MSdelay(200); /* Wait for response */
 for (uint16_t count = 0; Is_Data_Received() == false; count++)
 {
  if(count>15000)
  {
   return false;
  }
 }
     INTCONbits.GIE=0; /* Disable global interrupt to parse received data */
 sample();  /* Parse data in sample function */
 memset(ReceiveBuffer,0,BUFFER_SIZE);/* Clear ReceiveBuffer */
     INTCONbits.GIE=1; /* Enable Global Interrupt */
 return true;  /* Return success value */
}

Remote_AT_Command(uint32_t Long_Address_MSB, uint32_t Long_Address_LSB, 
    uint16_t Short_Address, const char* ATCommand, bool action)
{
 uint16_t Length,Checksum;
 if (action == Write)
 {
  /* Define parameter value depend frame length */
  if(Command_Value > 0x00FFFFFF) Length = 19;
  else if(Command_Value > 0x00FFFF) Length = 18;
  else if(Command_Value > 0x00FF) Length = 17;
  else Length = 16;
 }
 else
  Length = 15;

 Checksum = REMOTE_AT_COMMAND_FRAME + FRAME_ID;/* Calculate Checksum */
 for (int8_t i = 24; i >= 0; i = i-8) 
  Checksum = Checksum + (Long_Address_MSB >> i);
 for (int8_t i = 24 ; i >= 0; i = i-8) 
  Checksum = Checksum + (Long_Address_LSB >> i);
 
 Checksum = Checksum + (Short_Address >> 8) + Short_Address 
     + REMOTE_AT_COMMAND_OPT + ATCommand[0] + ATCommand[1];
 if (action == Write)
 Checksum = Checksum + (Command_Value >> 24) + (Command_Value >> 16)
     + (Command_Value >> 8) + Command_Value ;

 /* Subtract checksum lower byte from 0xFF to get 1 byte checksum */
 Checksum = 0xFF - Checksum;

 USART_TxChar(START_DELIMITER); /* Send frame start with 1 byte Delimiter */
 USART_TxChar(Length >> 8); /* Send 2 byte length */
 USART_TxChar(Length);
 USART_TxChar(REMOTE_AT_COMMAND_FRAME); /* Send 1 byte frame type */
 USART_TxChar(FRAME_ID);   /* Send 1 byte frame ID */
 for (int8_t i = 24 ; i >= 0 ; i = i-8) /* Send 32-bit long destin address MSB */
  USART_TxChar(Long_Address_MSB >> i);
 for (int8_t i = 24 ; i >= 0 ; i = i-8) /* Send 32-bit long destin address LSB */
  USART_TxChar(Long_Address_LSB >> i);
 USART_TxChar(Short_Address >> 8); /* Send 16-bit long destination address */
 USART_TxChar(Short_Address);
 USART_TxChar(REMOTE_AT_COMMAND_OPT); /* Send Option */
 USART_SendString(ATCommand);  /* Send AT command */

 if(action == Write)
 {
  if(Length == 19)  /* Send value */
  {
   USART_TxChar(Command_Value >> 24);
   USART_TxChar(Command_Value >> 16);
   USART_TxChar(Command_Value >> 8);
  }
  if(Length == 18)
  {
   USART_TxChar(Command_Value >> 16);
   USART_TxChar(Command_Value >> 8);
  }
  if(Length == 17) 
   USART_TxChar(Command_Value >> 8);
  USART_TxChar(Command_Value);
 }
 USART_TxChar(Checksum);   /* Send Checksum */
}

void AT_Command(const char* ATCommand, bool action)
{
 uint16_t Length,Checksum;

 if (action == Write)
 {
  if(Command_Value > 0x00FFFFFF) Length = 8;
  else if(Command_Value > 0x00FFFF) Length = 7;
  else if(Command_Value > 0x00FF) Length = 6;
  else Length = 5;
 }
 else
  Length = 4;

 Checksum = AT_COMMAND_FRAME + FRAME_ID + ATCommand[0] + ATCommand[1];
 if (action == Write)
 Checksum = Checksum + (Command_Value >> 24) + (Command_Value >> 16)
     + (Command_Value >> 8) + Command_Value ;
 Checksum = 0xFF - Checksum;

 USART_TxChar(START_DELIMITER);
 USART_TxChar(Length >> 8);
 USART_TxChar(Length);
 USART_TxChar(AT_COMMAND_FRAME);
 USART_TxChar(FRAME_ID);
 USART_SendString(ATCommand);

 if(action == Write)
 {
  if(Length == 8)  /* Send value */
  {
   USART_TxChar(Command_Value >> 24);
   USART_TxChar(Command_Value >> 16);
   USART_TxChar(Command_Value >> 8);
  }
  if(Length == 7)
  {
   USART_TxChar(Command_Value >> 16);
   USART_TxChar(Command_Value >> 8);
  }
  if(Length == 6) 
   USART_TxChar(Command_Value >> 8);
  USART_TxChar(Command_Value);
 }
 USART_TxChar(Checksum);
}

void Transmit_Request(uint32_t Long_Address_MSB, uint32_t Long_Address_LSB,
        uint16_t Short_Address, char* str)
{
 uint16_t Length,Checksum;
 Length = 14 + strlen(str);

 Checksum = TRANSMIT_REQUEST_FRAME + FRAME_ID;/* Calculate Checksum */
 for (int8_t i = 24; i >= 0; i = i-8) 
  Checksum = Checksum + (Long_Address_MSB >> i);
 for (int8_t i = 24 ; i >= 0; i = i-8) 
  Checksum = Checksum + (Long_Address_LSB >> i);
 Checksum = Checksum + (Short_Address >> 8) + Short_Address;
 for (int8_t i=0;str[i]!=0;i++)
  Checksum = Checksum + str[i];
 Checksum = 0xFF - Checksum;

 USART_TxChar(START_DELIMITER);
 USART_TxChar(Length >> 8);
 USART_TxChar(Length);
 USART_TxChar(TRANSMIT_REQUEST_FRAME);
 USART_TxChar(FRAME_ID);
 for (int8_t i = 24 ; i >= 0 ; i = i-8)
  USART_TxChar(Long_Address_MSB >> i);
 for (int8_t i = 24 ; i >= 0 ; i = i-8)
  USART_TxChar(Long_Address_LSB >> i);
 USART_TxChar(Short_Address >> 8);
 USART_TxChar(Short_Address);
 USART_TxChar(TRANSMIT_REQUEST_BROADCAST_RADIUS);
 USART_TxChar(TRANSMIT_REQUEST_OPT);
 USART_SendString(str);
 USART_TxChar(Checksum);
}

void Write_AT_Command(char* ATCommand, uint32_t _CommandValue)
{
 Command_Value = _CommandValue;
 AT_Command(ATCommand, Write);
}

void Read_AT_Command(char* ATCommand)
{
 AT_Command(ATCommand, Read);
}

void Write_Remote_AT_Command(uint32_t Long_Address_MSB, uint32_t Long_Address_LSB,
    uint16_t Short_Address, char* ATCommand, uint32_t _CommandValue)
{
 Command_Value = _CommandValue;
 Remote_AT_Command(Long_Address_MSB, Long_Address_LSB, Short_Address, ATCommand, Write);
}

void Read_Remote_AT_Command(uint32_t Long_Address_MSB, uint32_t Long_Address_LSB,
    uint16_t Short_Address, char* ATCommand, uint32_t _CommandValue)
{
 Remote_AT_Command(Long_Address_MSB, Long_Address_LSB, Short_Address, ATCommand, Read);
}

void interrupt ISR()  /* Receive ISR routine */
{
    char received_char;
    if(RCIF==1){
        received_char = RCREG;
 /* check if any overrun occur due to continuous reception */
        if(RCSTAbits.OERR)
        {           
            CREN = 0;
            NOP();
            CREN=1;
        }
        if (received_char == START_DELIMITER)
        {
            LastByteOfFrame = BufferPointer;
            BufferPointer = 0;
            ReceiveBuffer[BufferPointer] = received_char;
        }
        else
        {
            BufferPointer++;
            ReceiveBuffer[BufferPointer] = received_char;
        }
    }
}

void SetTo_Broadcast()
{
 MSdelay(500);
 Write_AT_Command("DH", 0x00000000);
 MSdelay(500);
 Write_AT_Command("DL", 0x0000FFFF);
 MSdelay(500);
 Read_AT_Command("WR");
 MSdelay(1000); 
}

int main(void)
{
    char _buffer[25];
    double Temperature;
    uint32_t Remote_Address_DH = 0x0013A200;
    uint32_t Remote_Address_DL = 0x41241CB2;

    OSCCON=0x72;  /* set internal clock to 8MHz */
    USART_Init(9600);  /* Initiate USART with 9600 baud rate */
    LCD_Init();   /* Initialize LCD */
    LCD_String_xy(1, 0, "X-Bee Network ");
    LCD_String_xy(2, 0, "Demo..!!");
    MSdelay(20000);
    LCD_Clear();
    INTCONbits.GIE=1;  /* enable Global Interrupt */
    INTCONbits.PEIE=1;  /* enable Peripheral Interrupt */
    PIE1bits.RCIE=1;  /* enable Receive Interrupt */ 

    LCD_String_xy(1, 0, "Setting X-Bee to");
    LCD_String_xy(2, 0, "Broadcast mode  ");
    SetTo_Broadcast();  /* Set XBee coordinator to broadcast mode */
    LCD_Clear();
 
    LCD_String_xy(1, 0, "Request Samples ");
    /* Request Samples from remote X-Bee device at 100ms Sample rate */
    Write_Remote_AT_Command(Remote_Address_DH, Remote_Address_DL, 0xFFFE, "IR", 100);
    MSdelay(1500);
    LCD_Clear();

    while (1)
 {
  Get_Sample();
  if (_IsContainsDigital)
  {
   if(DigitalData[2] >= 0)/* Switch status on DIO2 pin */
   {
     sprintf(_buffer, "Switch = %d   ", DigitalData[2]);
     LCD_String_xy(1, 0, _buffer); /* print on 1st row */
     memset(_buffer, 0, 25); /* Clear Buffer */
   }
  }
  if (_IsContainsAnalog)
  {
              Temperature = (double)AnalogData[1] * 0.1171875;
   if(AnalogData[1] >= 0)/* LM35 value on AIN1 pin */
   {
     sprintf(_buffer, "Temp = %0.1f C  ", Temperature);
     LCD_String_xy(2, 0, _buffer);/* print on 2nd row */
     memset(_buffer, 0, 25); /* Clear Buffer */
   }
  }
 }
}

No comments:

Post a Comment