It was a long time I dealt with sending and receiving data through bluetooth communication. This short article is going to show some basics that are good to handle in the code. I use the bluetooth (BT) module HC-05.
To understand Serial.available() and Serial.read()Serial.available() returns the number of bytes that are prepared in the BT buffer for reading.
Serial.read() reads bytes from the BT buffer. We can call Serial.read() if there are no data in the BT buffer too.
Here we start with an easy Arduino code that reads bytes from the BT buffer if there are any:
void loop() {
ReceiveBT();
}
byte receivedValue;
void ReceiveBT() {
if (Serial.available() > 0) {
receivedValue = Serial.read();
}
}
The transmitter side is something like this:
void Send(byte x) {
Serial.write(x);
}
Packaging dataLet's consider an example when we want to receive some red, green and blue value for the led stripe OR to receive an order to turn the lamp ON or OFF in the same code. First we must know what data we receive for, if it is for the led stripe or for the lamp. So we wrap these data into a package that starts and ends with a predefined value. It will look like this:
predefined value - data - predefined value
We will create predefined values rgbColor and lampOnOFF. The transmitter side can be something like this:
#define rgbColor 80
#define lampOnOFF 81
void SendRGBColor(byte red, byte green, byte blue) {
Serial.write(rgbColor);
Serial.write(red);
Serial.write(green);
Serial.write(blue);
Serial.write(rgbColor);
}
void SendLampOnOFF(bool b) {
Serial.write(lampOnOFF);
if (b) Serial.write(1); else Serial.write(0);
Serial.write(lampOnOFF);
}
And the receiver side:
void loop() {
ReceiveBT();
}
#define rgbColor 80
#define lampOnOFF 81
byte receivedValue;
void ReceiveBT() {
if (Serial.available() > 0) {
receivedValue = Serial.read();
if (receivedValue == rgbColor) {
byte red = Serial.read();
byte green = Serial.read();
byte blue = Serial.read();
receivedValue = Serial.read();
if (receivedValue == rgbColor) SetLedStripe(red, green, blue);
}
if (receivedValue == lampOnOFF ) {
bool b = (Serial.read() == 1);
receivedValue = Serial.read();
if (receivedValue == lampOnOFF) SetLamp(b);
}
}
}
The first "if (receivedValue == rgbColor)" tells the code what data we are going to receive. The second "if (receivedValue == rgbColor)" is an assurance that we received all data correctly so we can execute a function.
Waiting for dataThe code above would usually not work. The problem is that we read bytes from the BT buffer quicklier than they arrive. We just need to wait for them. We add a function WaitForData(x) that will wait for x bytes to come to the BT buffer:
void loop() {
ReceiveBT();
}
void WaitForData(byte x) {
while (Serial.available() < x) {
}
}
#define rgbColor 80
#define lampOnOFF 81
byte receivedValue;
void ReceiveBT() {
if (Serial.available() > 0) {
receivedValue = Serial.read();
if (receivedValue == rgbColor) {
WaitForData(4);
byte red = Serial.read();
byte green = Serial.read();
byte blue = Serial.read();
receivedValue = Serial.read();
if (receivedValue == rgbColor) SetLedStripe(red, green, blue);
}
if (receivedValue == lampOnOFF ) {
WaitForData(2);
bool b = (Serial.read() == 1);
receivedValue = Serial.read();
if (receivedValue == lampOnOFF) SetLamp(b);
}
}
}
But it is still not perfect. If there is a problem with the BT communication and bytes just do not come, the code will stop in the while cycle of the function WaitForData. To treat this we add a function WaitMillis() that returns TRUE after a set amount of the time. If the data not arrive, let's say in 3 seconds, we will stop the while cycle:
void loop() {
ReceiveBT();
}
bool WaitMillis(unsigned long* t, long waitMillis) {
unsigned long actualTime = millis();
if ((actualTime - *t) > waitMillis) {
*t = actualTime;
return true;
}
if (actualTime < *t) *t = actualTime; //this row treats overflow of millis()
return false;
}
void WaitForData(byte x) {
unsigned long waitForData = millis();
while (Serial.available() < x) {
if (WaitMillis(&waitForData, 3000)) return; //wait max 3 seconds
}
}
#define rgbColor 80
#define lampOnOFF 81
byte receivedValue;
void ReceiveBT() {
if (Serial.available() > 0) {
receivedValue = Serial.read();
if (receivedValue == rgbColor) {
WaitForData(4);
byte red = Serial.read();
byte green = Serial.read();
byte blue = Serial.read();
receivedValue = Serial.read();
if (receivedValue == rgbColor) SetLedStripe(red, green, blue);
}
if (receivedValue == lampOnOFF ) {
WaitForData(2);
bool b = (Serial.read() == 1);
receivedValue = Serial.read();
if (receivedValue == lampOnOFF) SetLamp(b);
}
}
}
Non-blocking versionThe code above is suitable if we don't mind that the code stops for milliseconds or seconds sometimes when it is waiting for BT data.
If we need to solve other stuff while data are coming, the code can look like following. We set flags rgbData and lampData that cares about receiving suitable data:
void loop() {
ReceiveBT();
DoOtherStuff();
}
bool WaitMillis(unsigned long* t, long waitMillis) {
unsigned long actualTime = millis();
if ((actualTime - *t) > waitMillis) {
*t = actualTime;
return true;
}
if (actualTime < *t) *t = actualTime; //this row treats overflow of millis()
return false;
}
#define rgbColor 80
#define lampOnOFF 81
byte receivedValue;
bool rgbData = false;
bool lampData = false;
unsigned long waitForData;
const long treshold = 3000; //3 seconds
void ReceiveBT() {
if (rgbData) {
if (Serial.available() >= 4) {
rgbData = false;
byte red = Serial.read();
byte green = Serial.read();
byte blue = Serial.read();
receivedValue = Serial.read();
if (receivedValue == rgbColor) SetLedStripe(red, green, blue);
}
if (WaitMillis(&waitForData, treshold)) rgbData = false;
return; //jumps from the ReceiveBT();
}
if (lampData) {
if (Serial.available() >= 2) {
lampData = false;
bool b = (Serial.read() == 1);
receivedValue = Serial.read();
if (receivedValue == lampOnOFF) SetLamp(b);
}
if (WaitMillis(&waitForData, treshold)) lampData = false;
return; //jumps from the ReceiveBT();
}
if (Serial.available() > 0) {
receivedValue = Serial.read();
if (receivedValue == rgbColor) {
rgbData = true;
waitForData = millis();
}
if (receivedValue == lampOnOFF ) {
lampData = true;
waitForData = millis();
}
}
}
Comments
Please log in or sign up to comment.