Two way communication with HC-12 modules with “interrupt”

Hi,
This is my first post on this forum, so I will try to be as clear as I can and sorry if I make something wrong.

So I will first explain my situation (my project) and then my problem.

I have two Arduino boards (specifically an Arduino UNO and an Arduino MEGA). The Arduino Uno is connected to my PC where I have a custom program made in Visual Studio and the Arduino Mega is placed on a rover and is reading data from all of its sensors.

The Arduino Mega reads data from the sensors and sends a string with all the data to the Arduino Uno that feeds the string to the PC software trough a serial port. Sometimes the PC software will send a command to the rover, like “ACTIVATE”... . The comma separated string that the Mega send looks something like “Lat, Lng, Battery, Speed”.

Now, sensor readings and motor control is all okay and working. But I can not establish a good bluetooth communication between the two boards. I will explain myself better:
If I attach the Arduino Mega (that’s like if I had attached the Rover directly to my PC) directly to my PC with a USB cable, the board communicates just fine with the software. The PC software reads the string and does all of its calculations and stuff. The problem is that i don’t want to have my rover attached to my PC so my idea is to send this communication string to the Arduino Uno with a HC-12 bluetooth module. The Arduino Uno will receive it and feed that string (without changing anything) to the PC software. I managed to achieve this part.

The problem comes now. I also need to send some commands (not often, only when the user presses some buttons on the PC software) from the PC to the Rover, passing from the UNO. The problem I encounter is that the Mega is constantly sending these update strings to the PC so the UNO can not send something back, and if it somehow manages to send the command, the received command on the Mega is junk. For example if I send a command “ACTIVATE” the Mega will receive “AIVT?” If it even receives something.

Here is where I need help in the code. In the Arduino UNO code I want to be able to recognize when a command in the serial port is being sent from the PC software and immediately stop listening from the incoming strings until the incoming command is sent to the Mega, once that is done the UNO has to restart reading those strings.
On the Mega code I need to receive the full command, elaborate it (I already have the code for the command separation and stuff...) and once the full command is read restart sending those update strings.
It’s like if I had a “normal” operating status that is just the Mega sending strings to the UNO, but If the UNO has a command, this has a higher priority and needs to be sent to the Mega, like a sort of interrupt.
I will attach a “diagram” to try to explain myself a little bit better.

This is the code that I have for the communication. It doesn’t work as intended but I hope to get the idea of what I want to achieve:

On the Arduino UNO

#include <SofwareSerial.h>  
SoftwareSerial HC12(10, 11);   //I have my module connected to those pins (TX, RX)

void setup(){
Serial.begin(9600);
HC12.begin(9600);
}
void loop(){

if(Serial.available())    //That would mean that we have a command incoming from the serial port
{
   HC12.write(Seria.read());   //Write the incoming command to the module
}else                          //We have not a command incoming
{
   Serial.println(HC12.read());    //Write to the Serial port the incoming string
}

}

On the Arduino Mega

#include <SofwareSerial.h>  
SoftwareSerial HC12(10, 11);   //I have my module connected to those pins (TX, RX)
String IncomingCommand = “”;
void setup(){
Serial.begin(9600);
HC12.begin(9600);
}
void loop(){

if(HC12.available())         //That would mean a command is being received
{
   IncomingCommand = HC12.read();    //Save the incoming command to be processed
}else                              //No incoming command, send the update string 
{
   HC12.println(“String”);      //The string is different but just for the test I sent that string
}

}

Ps: I know that SoftwareSerial is not that good, I’m using it just for testing. I don’t think that this library is my problem, but if you think let me know.

Thanks to all of those who have read my “poem” and to everyone that wants to help me. If I have made something wrong or if you haven’t understood something please let me know :slight_smile:

Thanks,
Stefano

(I am Italian so if I made some mistakes writing please forgive me :slight_smile: )

Given the UNO is just passing data through, you want to just shuffle bytes from one interface to the other, e.g.

#include <SoftwareSerial.h>

SoftwareSerial HC12(10, 11);

void setup() {
  Serial.begin(9600);
  HC12.begin(9600);
}

void loop() {
  if (Serial.available()) {
    HC12.write(Serial.read());
  }

  if (HC12.available()) {
    Serial.write(HC12.read());
  }
}

I wouldn't (personally) try to prioritise one port over the other: all that will do is end up losing characters once the buffer for the lower priority port fills up. You'll then need to somehow re-synchronise when the lower priority port is serviced again.

If the Uno genuinely cannot keep up with the the data rate using this approach you'll have to come up with a more sophisticated scheme, but try this first IMO.

To be clear: the key differences between this and your earlier example:

  1. Each port is serviced each time round the loop if it has data available
  2. Each byte read in using read() is written out using write() rather than println(). The latter will just add extra carriage return and line feed noise per byte and probably confuse the peer.

The Mega's code is going to be a bit more involved, because it needs to manage reading and writing serial data while also dealing with other events/activities (i.e. is it time to read my sensor(s)? Have I received a full command from the UNO? Do I need to drive some outputs?, etc, etc).

Since you're only providing an example on the Mega side it's hard to guess about how this looks. When I've done similar things in other projects I've used this kind of structure:

#include <SoftwareSerial.h>

SoftwareSerial HC12(10, 11);

void setup() {
  HC12.begin(9600);
}

void loop() {
  while (HC12.available()) {
    // read in command, do stuff 
  }

  // read sensors, send updates over HC12, etc, etc
}

However, I did this using single-byte commands, so I could be confident that the while loop would only block for a short period of time. If I had wanted to implement a more sophisticated command protocol, I would probably do so by buffering input bytes until I had a full command, and then acting on that command. That is to say: I would not block while receiving the full command on HC12.

Also note this: arduino uno - Non-blocking SoftwareSerial.Write - Arduino Stack Exchange

Double check how much data the Mega is sending -- if you are sending gobs of data at a time, the SoftwareSerial.write() method may be blocking, which may prevent you servicing the input buffer in a timely manner.

Thanks a lot!

I am now pretty busy for school, I will try your suggestions as soon as I can and let you know, I can even attach some “read sensors” code. In particular I read data from a GPS sensor (Ublox M8N), so timing and non-blocking code is a big problem (At least for what I know, if I am wrong please correct me).

Thanks again for the very informative reply :smile: :sun_with_face:
Stefano

Would it be easier to connect directly the Mega to the PC via Bluetooth? This saves you the hassle of using SoftwareSerial on the UNO. You should be able to find USB Bluetooth dongle (if your PC doesnt come with Bluetooth). Your Mega's Bluetooth would show up like a regular COM port if connected

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.