implementing wireless serial communication of strings with nanos and HC-12s

Greetings,

I have an LED display that displays text strings using the following code.
The code runs on a Nano and outputs the formatted strings with control characters over serial interface.

my intention is to convert the code to allow a wireless interface using two nanos talking via HC-12 wireless modules. the first storing the numerous strings and sending them periodically via the 1st HC-12. the second one receives the string and packages the string in the format for the display and sends it to the LED display using the dedicated serial input. drawing attached.

Here is the current working code that has no wireless ability and only sends the preexisting strings. basically i want this to accept wireless inputs.

#include <string.h>

char s[2]={0,0};
char buf[200]={0}; //make this larger than any anticipated string.

char scroll_txt[]={0x76,0x18,0x06,0x39,0};    //command for scrolling text, speed 0x30 - 0x39
char centre_txt[]={0x76,0x18,0x17,0};         //command for centred text 
char EOL_chars[]={0x0d,0};

char text[]="Why do they call it the novel coronavirus? It’s a long story…";

///////////////////////////////////////////////////////
void setup()
{
Serial.begin(1200,SERIAL_7E2);  //SERIAL_7E2
}

///////////////////////////////////////////////////////
unsigned char WB_Parity_Calc( char *str )
{
    unsigned char Par;
    Par = 0x00;
    while( *str )
      Par ^= *str++;
      Par = Par & 0x7F;                                                 
    return ~Par;         
}

///////////////////////////////////////////////////////
void loop() {

  memset(buf, '\0', sizeof(buf));               //clear output string
  strncat(buf,scroll_txt,sizeof(buf));        //scroll text or
  //strncat(buf,centre_txt,sizeof(buf));          //centre text
  strncat(buf,text,sizeof(buf));
  strncat(buf,EOL_chars,sizeof(buf));
  s[0]=WB_Parity_Calc(buf);                     //make a 1 character C-string with checksum
  strncat(buf,s,sizeof(buf));                   //concatenate checksum char
  Serial.println(buf);                          //transmit the resulting string

  delay(3000);

}

///////////////////////////////////////////////////////

here is the code i curently have for the transmitting nano #1

// Transmitter

#include <SoftwareSerial.h>
#define RX 2
#define TX 3
SoftwareSerial mySerial(RX, TX);
///////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
}
///////////////////////////////////////////
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  mySerial.write("Hello World");
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}
///////////////////////////////////////////

Here is the modified code for the receiving nano #2 that currently doesn't work. i get the following error:

incompatible types in assignment of 'int' to 'char [60]' when I try to save the incoming string which is guess is in integer form to a string of Characters.... problem is i have no idea ho to solve it.

// Receiver 
#include <string.h>
#include <SoftwareSerial.h>
#define RX 2
#define TX 3

char s[2]={0,0};
char buf[200]={0}; //make this larger than any anticipated string.

char scroll_txt[]={0x76,0x18,0x06,0x39,0};    //command for scrolling text, speed 0x30 - 0x39
char centre_txt[]={0x76,0x18,0x17,0};         //command for centred text 
char EOL_chars[]={0x0d,0};

char text[60]; 

SoftwareSerial mySerial(RX, TX);

///////////////////////////////////////////////////////
void setup() {
  Serial.begin(1200,SERIAL_7E2);  //SERIAL_7E2
  mySerial.begin(9600);
  pinMode(LED_BUILTIN,OUTPUT);
}
///////////////////////////////////////////////////////
unsigned char WB_Parity_Calc( char *str )
{
    unsigned char Par;
    Par = 0x00;
    while( *str )
      Par ^= *str++;
      Par = Par & 0x7F;                                                 
    return ~Par;         
}

///////////////////////////////////////////////////////
void loop() {
  if(mySerial.available())
{
  text = mySerial.read();
}
  memset(buf, '\0', sizeof(buf));               //clear output string
  strncat(buf,scroll_txt,sizeof(buf));        //scroll text or
  //strncat(buf,centre_txt,sizeof(buf));          //centre text
  strncat(buf,text,sizeof(buf));
  strncat(buf,EOL_chars,sizeof(buf));
  s[0]=WB_Parity_Calc(buf);                     //make a 1 character C-string with checksum
  strncat(buf,s,sizeof(buf));                   //concatenate checksum char
  Serial.println(buf);                          //transmit the resulting string
  digitalWrite(LED_BUILTIN, HIGH);
  delay(3000);
  digitalWrite(LED_BUILTIN, LOW);

}
///////////////////////////////////////////////////////

please help!

WIRELESS LED DISPLAY.pdf (381 KB)

This will be really sluggish on the receive because of the 3 second delay().

void loop() {
  if(mySerial.available())
{
  text = mySerial.read();
}
  memset(buf, '\0', sizeof(buf));               //clear output string
  strncat(buf,scroll_txt,sizeof(buf));        //scroll text or
  //strncat(buf,centre_txt,sizeof(buf));          //centre text
  strncat(buf,text,sizeof(buf));
  strncat(buf,EOL_chars,sizeof(buf));
  s[0]=WB_Parity_Calc(buf);                     //make a 1 character C-string with checksum
  strncat(buf,s,sizeof(buf));                   //concatenate checksum char
  Serial.println(buf);                          //transmit the resulting string
  digitalWrite(LED_BUILTIN, HIGH);
  delay(3000);
  digitalWrite(LED_BUILTIN, LOW);

}

the LED display is quite old and has an incoming baud rate of 1200 and is already slow. it scrolls the text across the dospaly so needs some time before the arduino sends another string.

but i will adjust this time once i have received the string corectly int he first place.

i am currently playing around with the following to cast the incoming byte as a char. im getting this error

  • request for member 'concat' in 'text', which is of non-class type 'char [60]'*
//  if(mySerial.available())
//{
//  text = mySerial.read();
//}

while(Serial.available() > 0)
  {
     char incomingByte= mySerial.read();
     text.concat(incomingByte));
  }

You've probably heard the advice from others beforehand, but don't use "S"trings, use char arrays. If you do use "S"trings, you don't need to #include <string.h>.

Also, while it might be overkill, you can use SerialTransfer.h to automatically packetize and parse your data for inter-Arduino communication without the headace. The library is installable through the Arduino IDE and includes many examples.

Here are the library's features:

This library:

  • can be downloaded via the Arduino IDE's Libraries Manager (search "SerialTransfer.h")
  • works with "software-serial" libraries
  • is non blocking
  • uses packet delimiters
  • uses consistent overhead byte stuffing
  • uses CRC-8 (Polynomial 0x9B with lookup table)
  • allows the use of dynamically sized packets (packets can have payload lengths anywhere from 1 to 255 bytes)
  • can transfer bytes, ints, floats, and even structs!!

Example TX Arduino Sketch:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  myTransfer.txBuff[0] = 'h';
  myTransfer.txBuff[1] = 'i';
  myTransfer.txBuff[2] = '\n';
  
  myTransfer.sendData(3);
  delay(100);
}

Example RX Arduino Sketch:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
    Serial.println();
  }
  else if(myTransfer.status < 0)
  {
    Serial.print("ERROR: ");

    if(myTransfer.status == -1)
      Serial.println(F("CRC_ERROR"));
    else if(myTransfer.status == -2)
      Serial.println(F("PAYLOAD_ERROR"));
    else if(myTransfer.status == -3)
      Serial.println(F("STOP_BYTE_ERROR"));
  }
}

For theory behind robust serial communication, check out the tutorials Serial Input Basics and Serial Input Advanced.

Also, don't use "delay()" unless you have a really, really good reason (you don't right here)

Thanks PB.

I'll see if i can implement the SerialTransfer.h functions now.

Generally, i understand the need to minimise delays but in this code i dont understand how it can impact anything? i am only delaying so that the 3rd party LED display has time to process the incoming command and perform its display. Am i missing something that would negatively impact my code in this instance?

Thanks again.

OK so here is my latest attempt of implimenting "SerialTransfer.h" that I am struggling with;

The serial output to the LED display is "#9" which i do not understand at all.

any advice would be appreciated.

transmitter code:

// Transmitter

#include "SerialTransfer.h" 
#include <SoftwareSerial.h>
#define RX 2
#define TX 3
SoftwareSerial mySerial(RX, TX);
SerialTransfer myTransfer;

char SENDtext[]= "this is a test"; 

///////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  myTransfer.begin(mySerial);
}
///////////////////////////////////////////
void loop() {

 for(byte i = 0; i < myTransfer.bytesRead; i++){
  myTransfer.txBuff[i] = SENDtext[i];
  }  
  myTransfer.sendData(sizeof(SENDtext)/sizeof(char));
  
  
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}
///////////////////////////////////////////

Receiver code:

// Receiver 
#include <string.h>
#include <SoftwareSerial.h>
#include "SerialTransfer.h" 
#define RX 2
#define TX 3

char s[2]={0,0};
char buf[200]={0}; //make this larger than any anticipated string.

char scroll_txt[]={0x76,0x18,0x06,0x39,0};    //command for scrolling text, speed 0x30 - 0x39
char centre_txt[]={0x76,0x18,0x17,0};         //command for centred text 
char EOL_chars[]={0x0d,0};

char text[200]; 

SoftwareSerial mySerial(RX, TX);
SerialTransfer myTransfer;

///////////////////////////////////////////////////////
void setup() {
  Serial.begin(1200,SERIAL_7E2);  //SERIAL_7E2
  mySerial.begin(9600);

  myTransfer.begin(mySerial);
  
  pinMode(LED_BUILTIN,OUTPUT);
}
///////////////////////////////////////////////////////
unsigned char WB_Parity_Calc( char *str )
{
    unsigned char Par;
    Par = 0x00;
    while( *str )
      Par ^= *str++;
      Par = Par & 0x7F;                                                 
    return ~Par;         
}

///////////////////////////////////////////////////////
void loop() {

if(myTransfer.available())
  {
    
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      text[i] = myTransfer.rxBuff[i];
    
  }
  else if(myTransfer.status < 0)
  {
    mySerial.print("ERROR: ");

    if(myTransfer.status == -1)
      mySerial.println(F("CRC_ERROR"));
    else if(myTransfer.status == -2)
      mySerial.println(F("PAYLOAD_ERROR"));
    else if(myTransfer.status == -3)
      mySerial.println(F("STOP_BYTE_ERROR"));
  }





//////////////////////////////////////////////
  memset(buf, '\0', sizeof(buf));               //clear output string
  strncat(buf,scroll_txt,sizeof(buf));        //scroll text or
  //strncat(buf,centre_txt,sizeof(buf));          //centre text
  strncat(buf,text,sizeof(buf));
  strncat(buf,EOL_chars,sizeof(buf));
  s[0]=WB_Parity_Calc(buf);                     //make a 1 character C-string with checksum
  strncat(buf,s,sizeof(buf));                   //concatenate checksum char
  Serial.println(buf);                          //transmit the resulting string
//  digitalWrite(LED_BUILTIN, HIGH);
//  delay(3000);
//  digitalWrite(LED_BUILTIN, LOW);

}
///////////////////////////////////////////////////////

@OP
The transmitter sketch of Post#1 shows that this is the string: "Hello World" which you want to transfer from NANO-1 to NANO-2 using HC12 Modules.

Have you been successful in doing that?

 for(byte i = 0; i < myTransfer.bytesRead; i++){
  myTransfer.txBuff[i] = SENDtext[i];
  }

Why are you using ".bytesRead" to stuff the transmit buffer? It's only used to read the receive buffer.

Try this instead:

myTransfer.txObj(SENDtext, sizeof(SENDtext));
myTransfer.sendData(sizeof(SENDtext));

Good morning,

Sorry for the seemingly silly mistakes. I am still a noob and really appreciate the help.

I am trying your suggestion now.

I don't mean to be discouraging - I hope it works for you

hi PB,

thanks heaps! It works! pic attached.

The only issue is that it seems the strings are limited to 25 characters in length.

For example SENDtext2 displays as "this virus sucks... I wan" do you have any ideas how i can increase this?

Here is the code:

// Transmitter

#include "SerialTransfer.h" 
#include <SoftwareSerial.h>
#define RX 2
#define TX 3
SoftwareSerial mySerial(RX, TX);
SerialTransfer myTransfer;

char SENDtext[]= "BRILLIANT!!! IT WORKS!!!"; 
char SENDtext2[]= "this virus sucks... I wanted Zombies!"; 
char SENDtext3[]= "this is a test"; 


///////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  myTransfer.begin(mySerial);
}
///////////////////////////////////////////
void loop() {

myTransfer.txObj(SENDtext, sizeof(SENDtext));
myTransfer.sendData(sizeof(SENDtext));
delay(1000);  
myTransfer.txObj(SENDtext2, sizeof(SENDtext));
myTransfer.sendData(sizeof(SENDtext2));
delay(1000);  
myTransfer.txObj(SENDtext3, sizeof(SENDtext));
myTransfer.sendData(sizeof(SENDtext3));
delay(1000);  
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}
///////////////////////////////////////////

Hi PB,

No offence taken and you are far from discouraging!

I just wanted to be sure to show my appreciation for your patience and help!

myTransfer.txObj(SENDtext2, sizeof(SENDtext));

Did you mean,

myTransfer.txObj(SENDtext2, sizeof(SENDtext2));

?

YES!!!

thanks! I was literally typing my response now.

another silly mistake :slight_smile:

If you had used a two dimensional array for the strings, that couldn't have happened, and your source code size would shrink by about 40%.

Thanks for the advice.

I am looking to make some improvements now. because the display is not quite working as I want.

Hi guys,

back into this project after a few days.

the LED display internal configuration is to scroll any message sent over the serial interface twice. this is ok and for my application its acceptable and for now i cant see any way to modify the display firmware to limit the message scroll to once.

However, currently the display is showing a single string 10+ times before moving to the next string. this number is a bit unpredictable because the timing of the send and timing of the display processing the received string are always a bit off so it can miss an incoming string.

What i am trying to do now is to constantly receive the incoming strings and only send them to the display if they are different.

This should give the display more time to process and it should also mean that it will only display each of the incoming strings once (technically twice as described above).

Here is what i have written to compare incoming strings with the previously sent strings and chose to display it or not... but it is not working and currently I have no working output to the display.

As always any help would be appreciated.

// Receiver 

#include <string.h>
#include <SoftwareSerial.h>
#include "SerialTransfer.h" 
#define RX 2
#define TX 3

char s[2]={0,0};
char buf[300]={0}; //make this larger than any anticipated string.

char scroll_txt[]={0x76,0x18,0x06,0x32,0}; 
//char scroll_txt[]={0x76,0x18,0x06,0x37,0};      //command for scrolling text, speed 0x30 - 0x39 ....char scroll_txt[]={0x76,0x18,0x06,0x39,0}; 
char centre_txt[]={0x76,0x18,0x17,0};             //command for centred text 
char EOL_chars[]={0x0d,0};

char text[300]; 
char text_compare[]= "Null";                      // first time = null


SoftwareSerial mySerial(RX, TX);                  //setup serial 
SerialTransfer myTransfer;

///////////////////////////////////////////////////////
void setup() {
  Serial.begin(1200,SERIAL_7E2);                  //SERIAL_7E2 config for LED display 
  mySerial.begin(9600);                           // config for wireless serial

  myTransfer.begin(mySerial);
  
  pinMode(LED_BUILTIN,OUTPUT);
}
///////////////////////////////////////////////////////
// calculate parity for text string
unsigned char WB_Parity_Calc( char *str )
{
    unsigned char Par;
    Par = 0x00;
    while( *str )
      Par ^= *str++;
      Par = Par & 0x7F;                                                 
    return ~Par;         
}

///////////////////////////////////////////////////////
void loop() {

if(myTransfer.available())
  {
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      text[i] = myTransfer.rxBuff[i];
  }
  else if(myTransfer.status < 0)
  {
    mySerial.print("ERROR: ");

    if(myTransfer.status == -1)
      mySerial.println(F("CRC_ERROR"));
    else if(myTransfer.status == -2)
      mySerial.println(F("PAYLOAD_ERROR"));
    else if(myTransfer.status == -3)
      mySerial.println(F("STOP_BYTE_ERROR"));
  }


// if text != text_compare 
      // send it to display 
      // make text = text_compare

  if (strcmp(text,text_compare)== 1) {          // strcmp 0 if strings are equal
    
      // compile and send it once to display 
      memset(buf, '\0', sizeof(buf));               //clear output string
      strncat(buf,scroll_txt,sizeof(buf));          //scroll text or
      //strncat(buf,centre_txt,sizeof(buf));        //centre text
      strncat(buf,text,sizeof(buf));                // add the strings
      strncat(buf,EOL_chars,sizeof(buf));           // add the strings
      s[0]=WB_Parity_Calc(buf);                     //make a 1 character C-string with checksum
      strncat(buf,s,sizeof(buf));                   //concatenate checksum char
      Serial.println(buf);    

   // make it the same so it only sends once. until the incomming text changes 
      strcpy(text_compare,text);

   //   Serial.print("TEXT:  ");  //some debug 
   //   Serial.println(text); 
      
  }
}
//////////////////////////////////////////////
// KEEP ME FOR LATER
//  memset(buf, '\0', sizeof(buf));               //clear output string
//  strncat(buf,scroll_txt,sizeof(buf));          //scroll text or
//  //strncat(buf,centre_txt,sizeof(buf));        //centre text
//  strncat(buf,text,sizeof(buf));                // add the strings
//  strncat(buf,EOL_chars,sizeof(buf));           // add the strings
//  s[0]=WB_Parity_Calc(buf);                     //make a 1 character C-string with checksum
//  strncat(buf,s,sizeof(buf));                   //concatenate checksum char
//  Serial.println(buf);                          //transmit the resulting string
///////////////////////////////////////////////////////