Pulling my hair out over my projects' HC-06 communication

Hello,

I have made a remote data logger for aquatics using atlas scientific equipment, and have added bluetooth functionality for calibrating the probes. Both the data logging and calibration code work great, however the issue lies in selecting which section of code to run upon startup. I am aiming to have the program wait 10 seconds on startup to receive a command via bluetooth which will enter the calibration function. If no command is received then it runs the data logging function.

I have been having an issue with sending data from my bluetooth serial on my phone to my arduino project. With the current code, the serial recieves data sent just fine, but my code is not processing the data sent back. I know that the HC-06 module is working fine as I have tested it with examples and the RX & TX work just fine. I have also stipped my code down to just the bluetooth send/recieve data and that also works fine. I therefore assume that something in the complete code is causing some sort of interference, though cannot for the life of me work it out.

A little disclaimer: I’m still relatively new to arduino so my code is probably not the most efficient, but I am getting there :stuck_out_tongue: Any advice would be much appreciated.

Below I have pasted the project code (minus the other functions as it was too many characters) as well as the barebones HC-06 code which works fine. The full code is an attachment.

(Post was too long)

Project Code

#include <Wire.h>                     // enable I2C.
#include <LiquidCrystal_I2C.h> // Library for LCD
//LiquidCrystal_I2C lcd(0x27, 20, 4);
char sensordata[30];     
// A 30 byte character array to hold incoming data from the sensors
byte sensor_bytes_received = 0;       // We need to know how many characters bytes have been received

byte code = 0;                        // used to hold the I2C response code.
byte in_char = 0;                     // used as a 1 byte buffer to store in bound bytes from the I2C Circuit.

#define TOTAL_CIRCUITS 4              // <-- CHANGE THIS | set how many I2C circuits are attached to the Tentacle shield(s): 1-8

int channel_ids[] = {97, 98, 99, 102};// <-- CHANGE THIS.
// A list of I2C ids that you set your circuits to.
// This array should have 1-8 elements (1-8 circuits connected)

char *channel_names[] = {"DO", "ORP", "PH", "RTD"}; // <-- CHANGE THIS.
// A list of channel names (must be the same order as in channel_ids[]) 
// it's used to give a name to each sensor ID. This array should have 1-8 elements (1-8 circuits connected).
// {"PH Tank 1", "PH Tank 2", "EC Tank 1", "EC Tank2"}, or {"PH"}

int DO;
double ORP;
double PH;
double RTD;
int z;
String SDO;
String SORP;
String StrPH;
String STemp;
String Content;
float data[] = {1,2,3,4};
int var;
#include <SPI.h>
#include <WiFiNINA.h>


#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "192.168.1.171";    // name address for Google (using DNS)

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiClient client;

unsigned long lastConnectionTime = 0;            // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 60000; // delay between updates, in milliseconds


#if defined (ARDUINO_SAM_DUE)            // On Arduino Due the standard I2C pins are Wire1, not Wire.
#define WIRE Wire1
#else
#define WIRE Wire
#endif

#if defined (ARDUINO_SAM_DUE) || defined (ARDUINO_SAMD_ZERO)
#define I2C_ONLY 1
#endif

#if !defined(I2C_ONLY)
#include <SoftwareSerial.h>              //Include the software serial library  

SoftwareSerial sSerial(11, 10);          // RX, TX  - Name the software serial library sSerial (this cannot be omitted)
// assigned to pins 10 and 11 for maximum compatibility
SoftwareSerial Bluetooth(3, 2);
const int s0 = 7;                        //Arduino pin 7 to control pin S0
const int s1 = 6;                        //Arduino pin 6 to control pin S1
const int enable_1 = 5;                   //Arduino pin 5 to control pin E on shield 1
const int enable_2 = 4;                  //Arduino pin 4 to control pin E on shield 2

#endif


//Cal stuff



byte computer_bytes_received = 0;        //We need to know how many characters bytes have been received
int channel;                             //INT pointer for channel switching - 0-7 serial, 8-127 I2C addresses
char *cmd;                               //Char pointer used in string parsing
int retries;                             // com-check functions store number of retries here
boolean answerReceived;                  // com-functions store here if a connection-attempt was successful
byte error;                              // error-byte to store result of Wire.transmissionEnd()

String stamp_type;                       // hold the name / type of the stamp
char stamp_version[4];                   // hold the version of the stamp

char computerdata[20];                   //we make a 20 byte character array to hold incoming data from a pc/mac/other.
int computer_in_byte;
boolean computer_msg_complete = false;

byte i2c_response_code = 0;              //used to hold the I2C response code.
                 

#if !defined (I2C_ONLY)
const long validBaudrates[] = {          // list of baudrates to try when connecting to a stamp (they're ordered by probability to speed up things a bit)
  38400, 19200, 9600, 115200, 57600
};
long channelBaudrate[] = {               // store for the determined baudrates for every stamp
  0, 0, 0, 0, 0, 0, 0, 0
};
#endif

boolean I2C_mode = false;                //bool switch for serial/I2C
int option;
void(* resetFunc) (void) = 0;//declare reset function at address 0
//Cal stuff end

//SCREEN

#include <hd44780.h>
#undef hd44780_h // undefine this so the example sketch does not think hd44780 is being used.

// cols and rows don't have to be exact to still get accurate transfer numbers
#define LCD_COLS 20
#define LCD_ROWS 4

// declare the lcd object
// Note: The i2c address and pin mappings must match the backpack
const uint8_t i2cAddr = 0x27;
const int rs=0, rw=1, en=2, db4=4, db5=5, db6=6, db7=7, bl=3, blpol=POSITIVE;
LiquidCrystal_I2C lcd(i2cAddr, en, rw, rs, db4, db5, db6, db7, bl, blpol);
#define HD44780_LCDOBJECT

void setup() {                      // startup function
  Serial.begin(9600);              // Set the hardware serial port.
  Bluetooth.begin(9600);
  Wire.begin();         // enable I2C port.
   //Initialize serial and wait for port to open:
   lcd.begin(20,4);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
createConnection();



//Cal Stuff

#if !defined (I2C_ONLY)
  pinMode(s1, OUTPUT);                   //Set the digital pin as output.
  pinMode(s0, OUTPUT);                   //Set the digital pin as output.
  pinMode(enable_1, OUTPUT);             //Set the digital pin as output.
  pinMode(enable_2, OUTPUT);             //Set the digital pin as output.
#endif

 
  while (!Serial) ;                      // Leonardo-type arduinos need this to be able to write to the serial port in setup()
#if !defined (I2C_ONLY)
  sSerial.begin(38400);                  // Set the soft serial port to 38400
  
#endif
  WIRE.begin();                          // enable I2C port.

  stamp_type.reserve(16);                // reserve string buffer to save some SRAM
 

Bluetooth.println("Press 1 for Calibration");
delay(5000);
 
option = Bluetooth.read();

lcd.clear();
lcd.print(option);
Bluetooth.print(option);

if(option == 49){
  intro();         // display startup message
}
}
  //Cal stuff end
void loop() {


if(option == 49){
  

  calibration();
}

else {

  dataLogging();
}

}

  }

Bluetooth Barebones Code

#include <SoftwareSerial.h>  
SoftwareSerial Bluetooth(3, 2);
int option;
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);              // Set the hardware serial port.
  Bluetooth.begin(9600);
  delay(2000);
  Bluetooth.println("Press 1 for Calibration");
delay(5000); 
option = Bluetooth.read();

}

void loop() {
  // put your main code here, to run repeatedly:
Serial.print(option);
delay(1000);
}

m_c.ino (39 KB)

With the current code, the serial recieves data sent just fine, but my code is not processing the data sent back.

Not at all clear. Please explain what should happen, and what happens instead. Post output examples.

Hi,

Sorry, So when the code starts up it sends a message through the HC-06 to my android serial terminal saying "press 1 for calibration".

The number that is sent back from the android serial terminal is then stored as int option. So if 1 was to be sent back it would come up as 49 as the int value (presumably ASCII?). The code then states 'IF number = 49, run this code, else run that code". However when I send a 1 back from the terminal it is not being stored as the int, so the code always runs the second option.

So the code prints int option in the bluetooth terminal and the serial monitor after a 10 second delay. Every time it comes up as -1, regardless of what I input from my phone. However, when I run the second set of code posted, it does print whatever input into the serial monitor. I can not see any difference in the code though. In fact, the code that I posted second is just select parts of my project code copied and pasted out, so is exactly the same in both.

Thanks

Where are the output examples?

You are getting the second option because your reading of input is more by faint hope than competence. Have alook at

Also you might find the following background notes useful.

Dropbox - BT_2_WAY.ino - Simplify your life to cover other likely sins
There is also a crude input section in a longer code example.

A normal way of working out what is causing the issue, is starting from the barebones sketch that works, abd gradually adding parts again, to find out what is causing the issue.

#if defined (ARDUINO_SAM_DUE)            // On Arduino Due the standard I2C pins are Wire1, not Wire.
#define WIRE Wire1
#else
#define WIRE Wire
#endif

unless you are actually going to use that particular board, you can simplify this for the new sketch that you are building

while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

same here.

#if defined (ARDUINO_SAM_DUE) || defined (ARDUINO_SAMD_ZERO)
#define I2C_ONLY 1
#endif

so unless it is either of these 2 boards, I2C_ONLY == !defined !
and i knew i had seen it somewhere, but with all the comments and compiler directives it was not even easy to find back.

#if !defined (I2C_ONLY)
  sSerial.begin(38400);                  // Set the soft serial port to 38400
 
#endif

i am fairly sure that defining another swSerial is probably your issue. and adding

Bluetooth.listen();

below these few lines may fix your issue.
Or just move the begin for the sSerial, to the very end of setup() after your enquiry via Bluetooth
It has nothing to do with your ‘String’ use, but issues from that may arise later.

Hi Deva,

Many thanks for your reply,

Yes, adding Bluetooth.listen() has solved the issue, thank you so much. Now to go and do some reading as to why (Nick, thank you so much for listing those resources).

Yes I believe I ran into those string issues you were talking about a few months ago when I started, hence the very crude reset function as a quick fix. Much to work on still but getting there slowly!

Thanks again.

Now to go and do some reading as to why

Quite simply put, you can only 'listen' to one swSerial object at one time, and the object that is initialized last is the one listened to. There is ways around this using for instance 2 different swSerial libraries (like using AltSoftSerial & SoftwareSerial) for 2 different ports, but all of course at the expense of reliability.