Add a HC-05 standard bluetooth port to a RFDuino (BLE)

 

RFduino connected to HC-05 bluetooth
RFduino connected to HC-05 bluetooth

I was looking for a system able to work with an iPhone (Bluetooth Low Emission – LBE) and a standard android (Standard bluetooth / rfcom). The RFDuino Arduino platform I have is perfect for BLE so, I decided to add a HC-05 module for the standard bluetooth.

 

Here is the description on how to make it !

 

 

 First step : cabling the two circuits

Coming soon …

Second step : writing initialization code

HC-05 bluetooth shield need to be initialized the first time. I don’t want to detail because there is another article on HC-05 and a lot of documentation on this component online.

But the main issue to manage is to be able to do this configuration online once on the first startup. This means we are able to store in the RFduino we already have make the configuration. The good thing is that we are able to write into the flash from the arduino code and store a flag to indicate that it has been done. My flag is the version, so if I upgrade the rfduino with a new version of code I will reconfigure the hc-05. (as this new version could change the configuration).

The second issue to manage is the software reset : once the hc-05 is configured, both rfduino and hc-05 have to be restarted to take the configuration into account. This can be done for the two calling the right reset function.

Here is the code to be used for this initialization:

// Map HC-05 Serial
#define blueToothSerial Serial
int key   = 4;

void setup() {
  pinMode(key,  OUTPUT);

  if ( ! isConfigured() ) {
     digitalWrite(key,HIGH);      // switch to command mode
     delay(500);
     if ( getHC05Connection() ) 
     {
       // Initial setup
       sendHC05AtCmd("AT+INIT",true);              // Init SPP
       delay(2000);
       sendHC05AtCmd("AT+NAME=MyName",true);    // BT displayed name
       sendHC05AtCmd("AT+PSWD=0000",true);         // pairing password is 0000
       sendHC05AtCmd("AT+UART=38400,0,0",true);    // serial over BT rate + Arduino rate (next restart)
       sendHC05AtCmd("AT+IAC=9e8b33",true);        // use a Password for pairing
       sendHC05AtCmd("AT+CMODE=1",true);           // connect to any address
       sendHC05AtCmd("AT+CLASS=40500",true);       // this bt device type ??
       delay(1000);
       // restart
       sendHC05AtCmd("AT+RESET",true);
       digitalWrite(key,LOW);                      // switch to DAT MODE
       delay(2000);
       saveConfigured();                           // Register configuration has been made
       RFduino_systemReset();                      // reset
       while(1);                                   
    }
    while (1);     // Error loop

  } else {
     digitalWrite(key,LOW);      // switch to DATA mode
     // Connect HC-05
     blueToothSerial.begin(38400);  

     // Bluetooth init
     RFduinoBLE.deviceName = "MyName";
     RFduinoBLE.advertisementData = "MyName";
     RFduinoBLE.advertisementInterval = MILLISECONDS(200);
     RFduinoBLE.txPowerLevel = -4;  // (-20dbM to +4 dBm)    
     RFduinoBLE.begin();
     delay(1000);
  }
}

/* =================================================================
 *                CONFIGURATION SUBROUTINE
 * =================================================================
 */
 #define VERSION 0x000100
 struct config_t {
   int version_number;
 };

#define CONFIG_PAGE  251 
struct config_t * config = (config_t*)ADDRESS_OF_PAGE(CONFIG_PAGE);

void saveConfigured() {
  flashPageErase(CONFIG_PAGE);
  struct config_t v;
  v.version_number = VERSION;
  flashWriteBlock(config, &v, sizeof(v)); 
}

bool isConfigured() {
   return ( config->version_number == VERSION );  
}

/* =================================================================
 *                HC-05 SUBROUTINE
 * =================================================================
 */

unsigned long rates[3]; 
#define hex2dec(x) ((x>'9')?10+x-'A':x-'0')
// -- Internal
#define COD_FAIL  30
#define BUFSZ 50

boolean getHC05Connection() { 
  rates[0] = 38400;
  rates[2] = 115200;
  rates[3] = 9600;
  int numRates = sizeof(rates)/sizeof(unsigned long);
  int recvd = 0;
  char _buffer[128];
  int _bufsize = sizeof(_buffer)/sizeof(char);

  for(int rn = 0; rn < numRates; rn++)
  {
    blueToothSerial.begin(rates[rn]);
    blueToothSerial.setTimeout(200);
    blueToothSerial.write("AT\r\n");
    delay(200);
    recvd = blueToothSerial.readBytes(_buffer,_bufsize);
    if (recvd > 0) {
      return true;
    } 
  }
  return false;
}

/* --- Send AT Command and get Error code back
 * immediate : when true directly read result, do not wait them to come
 *            make sense when you are not waiting for a remote device answer
 *
 */
int sendHC05AtCmd(char * atcmdstr, boolean imediate) {
  int recvd = 0;
  char _buffer[128];
  int _bufsize = sizeof(_buffer)/sizeof(char);
  int ret=-1;

  blueToothSerial.print(atcmdstr);
  blueToothSerial.print("\r\n"); 
  delay(200);
  while ( ( recvd = blueToothSerial.readBytes(_buffer,_bufsize) ) == 0 && (! imediate) ) delay(100);

  if (recvd >= 2) {
     if ( _buffer[0] == 'O' && _buffer[1] == 'K' ) ret=-1;     
     else if ( _buffer[0] == 'E' ) {
       // Get Error number if _buffer[8] = ')' then 1 digit error code, else 2 digit
       if ( recvd >= 9 ) {
         ret = ( _buffer[8] != ')' )?16*(hex2dec(_buffer[7]))+(hex2dec(_buffer[8])):hex2dec(_buffer[7]);
         print_debug2(" * Error code : ",ret);
       }
    } else if ( _buffer[0] == 'F' ) {
       ret=COD_FAIL;
    }
  }
  // Other cases : consider as valid command
  return ret;  
}

Third step : manage reception from both bluetooth devices

RFduino and HC-05 are working differently. RFduino is using callback function working with interrupts, Serial port, basically works with polling. To simplify my code I chose to work in ASCII mode with both. HC-05 uses lines (finishing by “\r\n”) LBE mode uses byte array.

/* =====================================================
 *  LBE -  Communication subroutine
 * =====================================================
 */
void RFduinoBLE_onReceive(char *data, int len)
{
  uint8_t _blebuff[256];
  int i=0;
  while ( i < len && i < 254 ) {
    _blebuff[i] = data[i];
    i++;
  }    
  _blebuff[i] = 0;
  uint8_t ret = proceedline(_blebuff, i);

  RFduinoBLE.sendByte(ret);
}

/* =====================================================
 *  HC-05 -  Communication subroutine
 * =====================================================
 */
uint8_t   hc05_buffer[256];
int       hc05_max = 250;
int       hc05_count = 0;
void hc5Receive() {
    char  hc05_ret[4];
    int   v;
    while ( blueToothSerial.available() > 0 ) {
      
        v = blueToothSerial.read();
        if ( v == -1 ) break;
        if ( hc05_count >= hc05_max ) {
           hc05_count = 0;
           continue;
        }
        if ( (char)v == '\n' ) {
           hc05_buffer[hc05_count]=0;  // end of line
           hc05_count++;               // to count \n
           hc05_ret[0] = proceedline(hc05_buffer, hc05_count);
           hc05_ret[1] = '\r'; hc05_ret[2]='\n'; hc05_ret[3] = 0;
           send_hc_05(hc05_ret);    
           hc05_count=0;
        } else {
           hc05_buffer[hc05_count]=(uint8_t)(v);
           hc05_count++;
        }
    }        
}

The proceedline function executes the process you want on the received data from both bluetooth connection

 

 

 

This entry was posted in Hardware and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.