Go Down

Topic: Read received bluetooth string in a while loop (Read 358 times) previous topic - next topic

helium97

Hi guys, I'm a beginner of Arduino and of coding too. I'm designing a product for a university project that requires bluetooth communication with a bridge app connected to a ProtoPie app prototype.
I've coded most of the code, but I really need your help.....
Once a button is pressed on the app, it sends a string to my Arduino Nano 33 BLE through a bridge app that starts a while loop with a defined duration. I'd like to exit from this while loop when another string is sended by the application, but the problem is that when it enters in the loop, Arduino doesn't read the bluetooth strings anymore until the defined time has elapsed and it exit from the while loop.
You can find the while loop in the "BREATHING MODE ACTIVATION" section, while all the bluetooth parameters are in the "BLUETOOTH" section just after the loop function.
(I had to cut some parts of the code, because of the characters limit)

Code: [Select]
#include <Adafruit_NeoPixel.h>
#include <CapacitiveSensor.h>
#include <ArduinoBLE.h>

int LDR = A0;
int LDRread = 0;
int BUTTON = 2;
int BUTTONstate = 0;
int brBUTTON = 4;
int brBUTTONstate = 0;

///////////////BLUETOOTH////////////////
BLEService protopieService("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
BLEStringCharacteristic protopieCharacteristic("beb5483e-36e1-4688-b7f5-ea07361b26a8", BLERead | BLEWrite | BLENotify, 20 );

long timePass = 0;

///////////////TURN ON LIGHT VARIABLES////////////////
int currVal = 0;
int lastVal = 0;

bool lowLight = false;

///////////////BREATHING MODE VARIABLES////////////////
bool breathingModeActivation = false;
int curbrVal = 0;
int lastbrVal = 0;

int ColorR = 0, ColorG = 0, ColorB = 0;

int interval;

#define PIN 6
#define NUMPIXELS 24

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
  pinMode(LDR, INPUT);
  pinMode(BUTTON, INPUT);
  pinMode(brBUTTON, INPUT);
  pixels.begin();
  pixels.show();

// bluetooth startup
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while(1); //stop execution if BLE error
  }
  Serial.println("Blueooth ok");
  //Initialize BLE with name and characteristics
  BLE.setLocalName("HUGY"); //Change your device name
  BLE.setAdvertisedService(protopieService);
  protopieService.addCharacteristic(protopieCharacteristic);

  BLE.addService(protopieService);

  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  protopieCharacteristic.setEventHandler(BLEWritten, protopieCharacteristicWritten);
 
  //Set initial value on characteristic and turn on bluetooth advetising
  protopieCharacteristic.writeValue("");
  // start advertising
  BLE.advertise();
}

//ccommand to send/receive between Arduino and Protopie
String BREATHINGMODE10 = "BREATHINGMODE10";
String BREATHINGMODE30 = "BREATHINGMODE30";
String OFF = "OFF";
int toggle = 0;

void loop() {
  // put your main code here, to run repeatedly:

  LDRread = analogRead(LDR); //it is the value red from the photoresistor (LDR)
  BUTTONstate = digitalRead(BUTTON);
  brBUTTONstate = digitalRead(brBUTTON);
  //Serial.println(LDRread);
  val = TouchSensor.capacitiveSensor(30);

  delay(50); //delay of checking light intensity

  //Check ble
  BLE.poll();

//every time the light intensity (LDRread) goes under a value (200), it turns on the Nepoixel ring, otherwhise it stay, or switch it off

  if (!lowLight) { //if the light is off, check for environmental light value
    lightSense();
  }

  if (BUTTONstate == HIGH){ //if button is pressed, the light sense code starts to run again
    lowLight = false;
  }

  if (lowLight) {
    changeColor();
  }
}

///////////////BLUETOOTH///////////////
void blePeripheralConnectHandler(BLEDevice central) {
  //This is executed when connect
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  //This is executed when disconnect
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void protopieCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  //Here I received from ProtoPie
  Serial.println("Characteristic received");

  String val;
  val = protopieCharacteristic.value();
  if (lowLight){
    if (val=="BREATHINGMODE10") {
      Serial.println(val);
      interval = 10000;
      breathingMode();
    }
     

    else if (val== "BREATHINGMODE30") {
      Serial.println(val);
      interval = 30000;
      breathingMode();
    }
     
   
    else if (val=="OFF")
      Serial.println(val);
  }
}



///////////////BREATHING MODE ACTIVATION///////////////
void breathingMode() {
 
  colorWipe(pixels.Color(255, 0, 0), 50); //when breathing mode is activated, wipe to this color
  unsigned long startMillis = millis(); //millis when the action is triggered
 
  while (breathingModeActivation = true) {
     
    unsigned long currentMillis = millis();
   
    if ((unsigned long)(currentMillis - startMillis) <= interval) { //if time elapsed (currentMillis - startMillis) is lower than breathing mode duration, repeat
      updateBreath();
      } else if ((unsigned long)(currentMillis - startMillis) > interval) { //if time elapsed (currentMillis - startMillis) is higher than breathing mode duration, turn off breathing mode
        breathingModeActivation = false;
        colorWipe(pixels.Color(255, 255, 255), 50);
        break;
        }
  }
}

///////////////BREATH///////////////
// breathing pixel variables
unsigned long startTime = 0;
int colorR = 0, colorG = 0, colorB = 0;
int breathTime = 6000; // 6000ms = six seconds; breathing speed
float breathTimeFloat = breathTime;
float pi = 3.14;

void updateBreath(){
  const float pi = 3.14;
  float frac; // ratio of color to use, based on time
  int r, g, b;

  // calculate a brightness fraction, based on a sine curve changing over time from 0 to 1 and back
  frac = (sin((((millis() - startTime) % breathTime)/breathTimeFloat - 0.25f) * 2.0f * pi) + 1.0f)/2.0f;

  // multiply each color by the brightness fraction
  r = 255 * frac;
  g = 0 * frac;
  b = 0 * frac;

  setPixelColor(pixels.Color(r, g, b), 50);
  BLE.poll();
}



Robin2

You can find the while loop in the "BREATHING MODE ACTIVATION" section, while all the bluetooth parameters are in the "BLUETOOTH" section just after the loop function.
I'm not familiar with BLE but I suspect the answer to the problem is to use IF rather than WHILE and allow loop() to do the iteration.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

helium97

I tried to change "while" with "if", but I need that when the code in the while loop runs, everything else (except the bluetooth reading) doesn't run.

Robin2

I tried to change "while" with "if", but I need that when the code in the while loop runs, everything else (except the bluetooth reading) doesn't run.
You need to post the updated version of your program. It's not as simple as replacing the word "while" with the word '"if"

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

helium97

Ok, this is it. I've changed the while with the if and added the modeActive bool in order to avoid everything else when the BREATHING MODE function is activated. The problem is that now, when the function is called, the LEDs remain stucked to the initial color, without doing the "breathing effect".

This is the updated code:

Code: [Select]
#include <Adafruit_NeoPixel.h>
#include <CapacitiveSensor.h>
#include <ArduinoBLE.h>

int LDR = A0;
int LDRread = 0;
int BUTTON = 2;
int BUTTONstate = 0;
int brBUTTON = 4;
int brBUTTONstate = 0;

///////////////BLUETOOTH////////////////
BLEService protopieService("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
BLEStringCharacteristic protopieCharacteristic("beb5483e-36e1-4688-b7f5-ea07361b26a8", BLERead | BLEWrite | BLENotify, 20 );

long timePass = 0;

///////////////TURN ON LIGHT VARIABLES////////////////
int currVal = 0;
int lastVal = 0;

bool lowLight = false;

///////////////RELAXING MODE VARIABLES////////////////
bool northernLightsModeActivation = false;
bool sunsetModeActivation = false;
bool nebulaModeActivation = false;

///////////////BREATHING MODE VARIABLES////////////////
bool breathingModeActivation = false;
int curbrVal = 0;
int lastbrVal = 0;

int ColorR = 0, ColorG = 0, ColorB = 0;

int interval; // duration of the different "modes"
bool modeActive = false;

#define PIN 6
#define NUMPIXELS 24

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

///////////////CAPACITIVE TOUCH SENSOR VARIABLES////////////////
CapacitiveSensor TouchSensor = CapacitiveSensor(11, 12);
long val;
int pos;
int showType = 0;

///////////////////////////////////////////////////////////
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(LDR, INPUT);
  pinMode(BUTTON, INPUT);
  pinMode(brBUTTON, INPUT);
  pixels.begin();
  pixels.show();

// bluetooth startup
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while(1); //stop execution if BLE error
  }
  Serial.println("Blueooth ok");
  //Initialize BLE with name and characteristics
  BLE.setLocalName("HUGY"); //Change your device name
  BLE.setAdvertisedService(protopieService);
  protopieService.addCharacteristic(protopieCharacteristic);

  BLE.addService(protopieService);

  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  protopieCharacteristic.setEventHandler(BLEWritten, protopieCharacteristicWritten);
 
  //Set initial value on characteristic and turn on bluetooth advetising
  protopieCharacteristic.writeValue("");
  // start advertising
  BLE.advertise();
}

//ccommand to send/receive between Arduino and Protopie
String BREATHINGMODE10 = "BREATHINGMODE10";
String BREATHINGMODE30 = "BREATHINGMODE30";

void loop() {
  // put your main code here, to run repeatedly:

  LDRread = analogRead(LDR); //it is the value red from the photoresistor (LDR)
  BUTTONstate = digitalRead(BUTTON);
  brBUTTONstate = digitalRead(brBUTTON);
  //Serial.println(LDRread);
  val = TouchSensor.capacitiveSensor(30);

  if (!lowLight) {
    delay(50); //delay of checking light intensity
  }

  //Check ble
  BLE.poll();

//every time the light intensity (LDRread) goes under a value (200), it turns on the Nepoixel ring, otherwhise it stay, or switch it off

  if (!lowLight) { //if the light is off, check for environmental light value
    if (!modeActive) {
      lightSense();
    }
  }

  if (BUTTONstate == HIGH){ //if button is pressed, the light sense code starts to run again
    lowLight = false;
  }

  if (lowLight) {
    if (!modeActive) {
      changeColor();
      }
    }
}

///////////////BLUETOOTH///////////////
void blePeripheralConnectHandler(BLEDevice central) {
  //This is executed when connect
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  //This is executed when disconnect
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void protopieCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  //Here I received from ProtoPie
  Serial.println("Characteristic received");

  String val;
  val = protopieCharacteristic.value();
  if (lowLight){

      if (val=="BREATHINGMODE10") {
        modeActive = true;
        Serial.println(val);
        interval = 10000; // duration
        breathingMode();
      }
   
   
      if (val=="BREATHINGMODE30") {
        modeActive = true;
        Serial.println(val);
        interval = 30000; // duration
        breathingMode();
      }


     if (modeActive) {
      if (val=="OFF") {
        modeActive = false;
        Serial.println(val);
        }
      }

///////////////BREATHING MODE ACTIVATION///////////////
void breathingMode() {
 
  colorWipe(pixels.Color(255, 0, 0), 50); //when breathing mode is activated, wipe to this color
  unsigned long startMillis = millis(); //millis when the action is triggered
 
  if (breathingModeActivation == true) {
     
    unsigned long currentMillis = millis();
   
    if ((unsigned long)(currentMillis - startMillis) <= interval) { //if time elapsed (currentMillis - startMillis) is lower than breathing mode duration, repeat
      updateBreath();
      } else if ((unsigned long)(currentMillis - startMillis) > interval) { //if time elapsed (currentMillis - startMillis) is higher than breathing mode duration, turn off breathing mode
        breathingModeActivation = false;
        colorWipe(pixels.Color(255, 255, 255), 50);
        modeActive = false;
        }
  }
}

///////////////BREATH EFFECT///////////////
// breathing pixel variables
unsigned long startTime = millis();
int colorR = 0, colorG = 0, colorB = 0;
int breathTime = 6000; // 6000ms = six seconds; breathing speed
float breathTimeFloat = breathTime;
float pi = 3.14;

void updateBreath(){
  const float pi = 3.14;
  float frac; // ratio of color to use, based on time
  int r, g, b;

  // calculate a brightness fraction, based on a sine curve changing over time from 0 to 1 and back
  frac = (sin((((millis() - startTime) % breathTime)/breathTimeFloat - 0.25f) * 2.0f * pi) + 1.0f)/2.0f;

  // multiply each color by the brightness fraction
  r = 255 * frac;
  g = 0 * frac;
  b = 0 * frac;

  setPixelColor(pixels.Color(r, g, b), 50);
}

void setPixelColor(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<pixels.numPixels(); i++) { //  ******i=0 - 0 is the start pixel
pixels.setPixelColor(i, c);       // *****change i to led\pixel number

//delay(wait);  // ************ removing eliminated the chase effect
  }
  pixels.show();
}

Robin2

#5
Nov 21, 2020, 07:45 pm Last Edit: Nov 21, 2020, 07:46 pm by Robin2
I see this line in your program
Code: [Select]
 if (breathingModeActivation == true) {
but I don't see any code that actually sets that value to true.

Quote
and added the modeActive bool in order to avoid everything else when the BREATHING MODE function is activated
That is not what the code does. Read your code carefully.

More importantly the reason for using IF rather than WHILE is to ensure that everything else can work. If you really do need to prevent other things from happening then WHILE may be appropriate.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

helium97

I see this line in your program
Code: [Select]
if (breathingModeActivation == true) {
but I don't see any code that actually sets that value to true.
Thank you, I forgot to insert the code that sets the value to true. This is it:
Code: [Select]
     if (val=="BREATHINGMODE10") {
        modeActive = true;
        breathingModeActivation = true;
        Serial.println(val);
        interval = 10000; // duration
        breathingMode();
      }



More importantly the reason for using IF rather than WHILE is to ensure that everything else can work. If you really do need to prevent other things from happening then WHILE may be appropriate.
That's the point. I think that the WHILE loop is appropriate in order to achieve the "breathing effect", and it works. The problem is that when Arduino enters in the WHILE loop, it stops to check the bluetooth connection, but I need it to keep checking (only) the bluetooth connection when it is in the "Breathing Mode", because I want it to be able to receive the "OFF" command (and then exit the loop).

Robin2

Thank you, I forgot to insert the code that sets the value to true. This is it:
Snippets without the complete program are no use.


Quote
That's the point. I think that the WHILE loop is appropriate in order to achieve the "breathing effect", and it works. The problem is that when Arduino enters in the WHILE loop, it stops to check the bluetooth connection, but I need it to keep checking (only) the bluetooth connection when it is in the "Breathing Mode", because I want it to be able to receive the "OFF" command (and then exit the loop).
I think it's time for you to describe in English (not code) what this project is required to do.

Personally I see no conflict between using IF (properly) so that other parts of the code can be checked even if the main action should be confined to a particular area.

Have a look at how the code is organized in Several Things at a Time

Note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Go Up