i actually communicate between 2 Nanos using HM-10 BLE modules, in an independent Bluetooth 4.0 network.
My aim is to make some measures using a Nano with slave HM-10, lets say every 200ms, and send packets of data , lets say 1 to 3 bytes, independently at this rate, to another Nano with master HM-10.
Actually, all i can do is all grouped data arrive to Master after a moment :-/
As if HM-10 is waiting for a calm moment before sending the data !
So is my question :
does anybody know how to fix the length of a packet, or force HM-10 to send its buffer ?
Thanks for your help, and my apologies about my poor english, i don't use it so much :-/
So, if you send data from the Serial Monitor app that the slave is connected to, it sends some data to the master. Seems a strange interpretation of the terms master and slave.
The "packet" of data that you send now consists of 4 characters - two digits, a carriage return, and a line feed.
I don't really understand what the problem is. I also can not understand why you are using the readString() method or why your code is littered with delay()s.
@Thierryev, you have used the QUOTE button for your code. Please modify your post and use the CODE button </> so your code looks like this and is easy to copy to a text editor. See How to use the Forum Your code is too long for me to study quickly without copying to a text editor.
@Robin2 :
sorry, I didn't saw the CODE button, even it was the first one !
now edited, seems fine...
@PaulS :
So, if you send data from the Serial Monitor app that the slave is connected to, it sends some data to the master. Seems a strange interpretation of the terms master and slave.
MAster ans Slave just refer to HM-10 parameters, and i must enter AT+START in Master HM-10 to open the connection between HM-10s.
This is the method i found to launch the process, probably not a pure one, but it works, because it's just for testing the communication and my attention was not there...
I spent some hours before understand how to start the 2 HM-10 without having them connected immediately !
The "packet" of data that you send now consists of 4 characters - two digits, a carriage return, and a line feed.
yes, that's ok
I don't really understand what the problem is.
I need the data to arrive sequentially, "packets" of 4 characters as you previously said.
Using the actual code, the whole data arrive in a single "packet" #38x4 bytes long, once the loop is done !
I also can not understand why you are using the readString() method or why your code is littered with delay()s.
I use Arduino for many years (and I don't consider I'm as an expert !), but I'm a real newbe in Bluetooth, just discovering for a fun project !
My starting point was reading many examples using quite the same code...
I just tried some different values for delay, until 5ms, to improve reactivity !
The flush() method seems to be necessary too, but I'll try to remove it...
Could/may i use a better method than readString() ?
I modified the delay in my loop to 1s, and the output is now partially packed :
I don't see anything that prints "recu: ", so it's hard to understand what the relationship is between the code shown and the output.
readString() is a blocking function. You might consider other methods, instead, like readStringUntil(). While readStringUntil() is a also a blocking function, it WILL return sooner than readString(), because it stops reading when the appropriate character arrives, such as the carriage return or line feed.
Thanks PaulS for your patience with me !
About "recu:", my original test progs are commented in french, I translate while pasting here, and I made a fault : "recu:" must have been translated to "ble:" for data received by Slave BLE module...
Thanks too for the link to Serial input basics, i took some time to read (again) in the case i missed something
My last Slave code don't do anything but waiting the data, so i'm not actually annoyed about blocking function, and as long as I can understand, and tested with or without CR and/or LF, only the delay() function in my loop changes the fact that BLESerial.readString() returns 38 times only 1 character (2000ms), x times some (1000ms) or the whole data in one 'final' shot (100ms).
I guess using some artifact like < or > character with 100ms delay will be taken into account only after the whole data is received by Slave HM-10, because i suspect the problem comes from the Master HM-10, waiting for some quiet moment to send the buffer (supposing the data is less than buffer size)... in the actual configuration, and i don't know if i can change this config or force the Master HM-10 to send each character separately !
only the delay() function in my loop changes the fact that BLESerial.readString() returns 38 times only 1 character (2000ms), x times some (1000ms) or the whole data in one 'final' shot (100ms).
There is some data in the incoming serial buffer. How much depends on how long you have your head in the sand. readString() returns all data in the buffer, when the function is called, along with whatever arrives during the timeout period.
If you bury your head in the sand for short periods of time, very few (often only one) characters will arrive. if yiu stuff your head in the sand for a long time, more data will arrive.
The key is to not stick your head in the sand at all. Read the data as it arrives, as Robin2 illustrates. Or, use the readStringUntil() method to only read one packet. You KNOW what constitutes a packet, so stop pretending that "everything in the buffer" is a single, complete packet. It could be less than one packet, exactly one packet (highly unlikely), or more than one packet.
Whaou !
Your "head in the sand" image, PaulS, is a perfect one, and i feel a bit blind understanding what you're explaining : I had my head in the sand !
So i must thank you a lot, once again, for your patience and explanations !
I'll investigate this way, and guess i'll find the solution
hope to be able to post here soon the final running code, because i searched in multiple ways on the net without finding such example of 2 HM-10 (or either BLE or WiFi, i imagine) exchanging together, independently of any network...
// code for testing data transfer between 2 Arduino MiniPro or Nano
// with HM-10 BLE modules
// Master HM-10 part
#include <SoftwareSerial.h>
#define BLEvcc 2
#define BLEgnd 3
#define BLErx 4
#define BLEtx 5
SoftwareSerial BLESerial(BLErx, BLEtx);
#define wait 5
String rep;
const byte numBytes = 3;
byte receivedBytes[numBytes];
byte numReceived = 0;
boolean newData = false;
void setup() {
// init
Serial.begin(115200);
Serial.println();
Serial.println("Starting BLE...");
pinMode(BLEgnd,OUTPUT);
digitalWrite(BLEgnd,LOW);
pinMode(BLEvcc,OUTPUT);
digitalWrite(BLEvcc,HIGH);
delay(500);
BLESerial.begin(57600);
BLESerial.write("AT");
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
if (rep == "OK") {
Serial.println("Detected");
Serial.print("Mode :");
BLESerial.write("AT+MODE2");
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
Serial.print("Role :");
BLESerial.write("AT+ROLE1"); // Master
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
Serial.print("IMME :");
BLESerial.write("AT+IMME1"); // wait for AT+START
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
Serial.println("enter anything for starting");
}
else {
Serial.print("unable to send AT command");
BLESerial.end();
}
}
void loop() {
static boolean recvInProgress = false;
static byte ndx = 0;
byte startMarker = 0x3C; // <
byte endMarker = 0x3E; // >
byte rb;
// read from BLE (HM-10)
// recvBytesWithStartEndMarkers() : Robin2 example 6
while (BLESerial.available() > 0 && newData == false) {
rb = BLESerial.read();
if (recvInProgress == true) {
if (rb != endMarker) {
receivedBytes[ndx] = rb;
ndx++;
if (ndx >= numBytes) {
ndx = numBytes - 1;
}
}
else {
receivedBytes[ndx] = '\0'; // terminate the string
recvInProgress = false;
numReceived = ndx; // save the number for use when printing
ndx = 0;
newData = true;
}
}
else if (rb == startMarker) {
recvInProgress = true;
}
}
// showNewData() // from Robin2 example 6
if (newData == true) {
Serial.print("BLE : ");
for (byte n = 0; n < numReceived; n++) {
Serial.print(receivedBytes[n],DEC);
//Serial.print(' ');
}
Serial.println();
newData = false;
}
// read from USB (Arduino Terminal)
// just needed to launch the BLE connection on demand
// then send a message to Slave HM-10 to start transfer
if (Serial.available())
{
delay(10);
rep = Serial.readString();
Serial.println(rep);
Serial.println("Starting HM-10 connection...");
BLESerial.write("AT+START");
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
BLESerial.write("Go !"); // send signal to Slave to start
delay(100); // some delay for the connection to start
}
}
Slave part :
// code for testing data transfer between 2 Arduino MiniPro or Nano
// with HM-10 BLE modules
// Slave HM-10 part
#include <SoftwareSerial.h>
#define BLEvcc 14 // pin A0
#define BLEgnd 15 // pin A1
#define BLEtx 16 // pin A2
#define BLErx 17 // pin A3
SoftwareSerial BLESerial(BLErx, BLEtx);
#define wait 5
String rep;
void setup()
{
Serial.begin(115200); // USB (choose 115200 in terminal)
Serial.println();
Serial.println("starting BLE...");
pinMode(BLEgnd,OUTPUT);
digitalWrite(BLEgnd,LOW);
pinMode(BLEvcc,OUTPUT);
digitalWrite(BLEvcc,HIGH);
delay(500);
BLESerial.begin(57600);
BLESerial.write("AT");
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
if (rep == "OK")
{
Serial.println("Detected");
Serial.print("Mode :");
BLESerial.write("AT+MODE2");
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
Serial.print("Role :");
BLESerial.write("AT+ROLE0"); // Slave
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
Serial.print("IMME :");
BLESerial.write("AT+IMME0"); // start immediately
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
Serial.print("waiting...");
}
else
{
Serial.print("unable to start");
BLESerial.end();
}
}
void loop()
{
// read from BLE (HM-10)
if (BLESerial.available()) // something received from Master
{
delay(5);
Serial.write("ble: ");
rep = BLESerial.readString();
Serial.println(rep);
Serial.println("GO !");
BLESerial.write("AT+START");
BLESerial.flush();
delay(wait);
rep = BLESerial.readString();
Serial.println(rep);
for (byte i=1;i<21;i++)
{
char str[4] = {'<',i,'>'};
BLESerial.write(str);
Serial.println(i,DEC);
delay(100); // may be reduced, even removed
}
}
}
the ouput window for Master :
Starting BLE...
Detected
Mode :OK+Set:2
Role :OK+Set:1
IMME :OK+Set:1
enter anything for starting
GO !
Starting HM-10 connection...
OK+START
BLE : 1
BLE : 2
BLE : 3
BLE : 4
BLE : 5
BLE : 6
BLE : 7
BLE : 8
BLE : 9
BLE : 10
BLE : 11
BLE : 12
BLE : 13
BLE : 14
BLE : 15
BLE : 16
BLE : 17
BLE : 18
BLE : 19
BLE : 20
You really don't need the comments, or to access an ASCII chart, if you write the code like so:
byte startMarker = '<';
byte endMarker = '>';
char str[4] = {'<',i,'>'};
BLESerial.write(str);
Despite it's name, str is NOT a string. Though there is room in the array for a NULL terminator, you do not have one. So, the behavior, when you pass that array to the write() method is undefined. You may get lucky, and the uninitialized element of the array contains a NULL. You may not.
Don't depend on luck.
char str[4] = {'<', i, '>', '\0'};
BLESerial.write(str);