What seems like it should be simple but I don't understand-serial communication between arduinos

Hi, I am trying too control 2 servo motors attached to a receiving arduino equipped with HC-12 wireless(which from my understanding is like serial communication), from a sending arduino equipped with 2 potentiometers and an HC-12 wireless module.
Basically, I want to send 2 different variables from the sender arduino to the receiver, and have the receiver set these values into 2 variables. Here is the code for the sender:

#include <SoftwareSerial.h>;
#define RX 0 //Connect to the TX pin of the HC-12
#define TX 1 //Connect to the RX pin of the HC-12
SoftwareSerial MySerial(RX, TX);

int Potentiometer1=0;
int Potentiometer2=0;
int Potentiometer1pin = A1;
int Potentiometer2pin = A2;

void setup() {
  MySerial.begin(2400);
  Serial.begin(9600);
  pinMode(Potentiometer1pin, INPUT);
  pinMode(Potentiometer2pin, INPUT);

}

void loop() { // run over and over
  readPotentiometerValue();
  sendValuesMySerial(); //send with start and end markers, each variable separated by a comma
  printValuesSerialMonitor();
}

void readPotentiometerValue(){
  Potentiometer1 = analogRead(Potentiometer1pin);
  Potentiometer2 = analogRead(Potentiometer2pin);
}

void sendValuesMySerial(){
  MySerial.write("<");
  MySerial.write(Potentiometer1);
  MySerial.write(",");
  MySerial.write(Potentiometer2);
  MySerial.write(">");
}

void printValuesSerialMonitor(){
  Serial.print("Potentiometer1 = ");
  Serial.println(Potentiometer1);
  Serial.print("Potentiometer2 = ");
  Serial.println(Potentiometer2);
}

Here is the receiver code and this is where I am stumped:

#include <SoftwareSerial.h>;
#include <Servo.h>;
#define RX 0 //Connect to the TX pin of the HC-12
#define TX 1 //Connect to the RX pin of the HC-12
SoftwareSerial MySerial(RX, TX);
int Potentiometer1=0;
int Potentiometer2=0;
int Servo1=0;
int Servo2=0;
int Comstate=0;
Servo servo_5;
Servo servo_6;

void setup() {
  Serial.begin(9600);
  MySerial.begin(2400);
  servo_5.attach(5);
  servo_6.attach(6);
}

void loop() { // run over and over
  if (MySerial.available()) {
    receiveWithStartEndMarkers();
    printReceivedVariablesSerialMonitor();
    adjustServosAccordingly();
    Comstate=1;  
  }else if(Comstate = 1){
    servo_5.write(Servo1);
    servo_6.write(Servo2);
  }else{
    servo_5.write(0);
    servo_6.write(0);
  }
}

void receiveWithStartEndMarkers(){
  ***//What do I put here to receive the values sent from***
***  //the first arduino set Potentiometer1 and Potentiometer2 to these values?***
}

void printReceivedVariablesSerialMonitor(){
  Serial.print("Potentiometer1= ");
  Serial.println(Potentiometer1);
  Serial.print("Potentiometer2= ");
  Serial.println(Potentiometer2);  
}

void adjustServosAccordingly(){
  Servo1 = map(Potentiometer1, 0, 1023, 0, 179);
  Servo2 = map(Potentiometer2, 0, 1023, 0, 179);
  servo_5.write(Servo1);
  servo_6.write(Servo2);
}

My question is how do I receive the 2 variables sent by the sender, and set the value of variables with the same name to these values on the receiver end?
Any help or suggestions is much appreciated.

Oops

This is so that if there is an interruption in the wireless signal, the servo stays in its previous position, unless it has not received the signal at all since powerup.

The tutorial which show you how to use this function is here
https://forum.arduino.cc/t/serial-input-basics-updated/382007

On the sending side you have two byte integer values for Potentiometer1 and Potentiometer2 but you are only sending one byte with the mySerial.write(PotentiometerN).

After you read the linked tutorial you may decide to send the potentiometer reading as text and convert to integers on the receiving end with atoi.

In that case, your sending function would be better written like this

void sendValuesMySerial(){
  MySerial.write('<'); //single quote marks to send one chare
  MySerial.print(Potentiometer1); //print all characters of the integer
  MySerial.write(',');
  MySerial.print(Potentiometer2);
  MySerial.write('>');
}

Will it still work when transmitting through HC-12 if I use MySerial.print instead of write?

Also, for receiving the values, how do I write them into variables on the other end, because I did look at the tutorial you recommended, but I don't think that this would do that:

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

I want to receive the data, which comes as <pot1value, pot2value>, and write those values into variables on the receiver arduino. How do I do that? How does the receiver decode the 2 variables from the angle brackets and the comma?

Also, I am looking to do this with more than 2 variables, but I am thinking it should be easy to add more once I have 2 that work.

Yes.

while (Serial.available() > 0 && newData == false) {

You are reading the data from the HC12 and want to use mySerial instead of Serial in the reading routine.

I want to receive the data, which comes as <pot1value, pot2value>, and write those values into variables on the receiver arduino. How do I do that? How does the receiver decode the 2 variables from the angle brackets and the comma?

Read the tutorial more closely, where that is described in some detail.

You also should spend some time learning the difference between = and == and when to use each of them. While your use of if(Comstate = 1){ may do what you intend to default to previously written values, using = with a conditional statement is a bad habit to get into.

#include <SoftwareSerial.h>;
#define RX 0 //Connect to the TX pin of the HC-12
#define TX 1 //Connect to the RX pin of the HC-12
SoftwareSerial MySerial(RX, TX);

I just noticed this in your code. It is not correct to use software serial on the hardware serial pins.

I would recommend that you change the software serial instance to some different pins.

When the program is finished, you may choose to put the HC12's back on the hardware serial pins for the best reliablility, but for now, you will find it easier to develop the program and load code with the HC12s on different pins.

How do I use the serial without softwareserial on pins 0 and 1 for best reliability?

How do I use the serial without softwareserial on pins 0 and 1 for best reliability?

Connect the HC12's to the hardware serial pins. Disconnect the HC12's when you load new code. The serial monitor will be able to echo data sent or received by the HC12's but the Serial monitor can not serve as a source of serial input to the program.

Have you indeed configured the HC12's to run at 2400 baud?

Yes they are configured for 2400 with at commands.

Why is it necessary to unplug them?

Here's something I ran on my Mega for testing (so using Serial2 to simulate your HC-12). It's certainly not definitive but you can get a feel for what's going on and way(s) to approach things.

Also note that I commented out your RX and TX definitions (hardware Serial0) and instead used pins 10 and 11. If you're using an Uno (or whatever) you'll need to adjust these pins for your HC-12 connections. The pins you had used are not suitable as they're connected to another device.

Notice too in my test message code how I send the integer...

#include <SoftwareSerial.h>
#include <Servo.h>

#define BUFF_SIZE   8


//#define RX      0 //Connect to the TX pin of the HC-12
//#define TX      1 //Connect to the RX pin of the HC-12

#define K_SERVO_TIMEOUT     3000ul  //mS    3-seconds   message timeout for servo reset
#define TST_MSG_INTERVAL    1500ul  //mS    1.5-sec     test message interval

const uint8_t pinRX = 10;
const uint8_t pinTX = 11;
const uint8_t pinTestRX = 17;
const uint8_t pinTestTX = 16;
const uint8_t pinServo1 = 5;
const uint8_t pinServo2 = 6;

const int16_t kNumBytesPerInt = sizeof( int );

const int testVal1 = 478;
const int testVal2 = 1018;

SoftwareSerial mySerial(pinRX, pinTX);

int Potentiometer1=0;
int Potentiometer2=0;
int Servo1=0;
int Servo2=0;
int Comstate=0;

uint32_t
    tNow,
    tTestMessage = 0ul,     //times test messages
    tServoUpdate = 0ul;     //servo message timeout
    
Servo servo_1;
Servo servo_2;

uint8_t
    rxBuffer[BUFF_SIZE];

//test messages; simulates HC-12 transmitter to our softwareserial pins
//for bench testing on a Mega
HardwareSerial 
    *testSerial = (HardwareSerial *)&Serial2;

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

    pinMode( pinTestTX, OUTPUT );
    pinMode( pinTestRX, INPUT );
    testSerial->begin(2400);
    
    mySerial.begin(2400);
        
    servo_1.attach( pinServo1 );
    servo_2.attach( pinServo2 );
    
}//setup

void loop() 
{ 
    tNow = millis();
    
    //if we don't get a serial message within the timeout period, reset
    //the servos to '0'
    if( (tNow - tServoUpdate) >= K_SERVO_TIMEOUT )
    {
        servo_1.write(0);
        servo_2.write(0);        
        
    }//if

    //send a test message (simulates HC-12)
    if( (tNow - tTestMessage) >= TST_MSG_INTERVAL )
    {
        tTestMessage = tNow;
        testSerial->write( '<' );
        testSerial->write( testVal1 & 0xff );
        testSerial->write( (testVal1 >> 8) & 0xff );
        testSerial->write( ',' );
        testSerial->write( testVal2 & 0xff );
        testSerial->write( (testVal2 >> 8) & 0xff );
        testSerial->write( '>' );        
        
    }//if

    //process any message characters
    receiveWithStartEndMarkers();
    
}//loop

void receiveWithStartEndMarkers()
{
    static uint8_t
        state = 0,
        rxIndex;

    //if there is one or more characters waiting
    if( mySerial.available() )
    {
        //read one
        uint8_t ch = mySerial.read();
        switch( state )
        {
            case    0:
                //look for sync/opening character
                if( ch == '<' )
                {
                    //got the sync so reset the index and move
                    //to state where we receive integer values
                    rxIndex = 0;
                    state++;
                    
                }//if
                
            break;
            
            case    1:
                //receive two 2-byte ints plus a comma
                rxBuffer[rxIndex++] = ch;
                if( rxIndex == (kNumBytesPerInt * 2) + 1 )    //plus 1 for ',' separator
                    state++;
                    
            break;

            case    2:
                //next character should be the end-sync character
                if( ch == '>' )
                {
                    //extract the two integers
                    memcpy( &Potentiometer1, &rxBuffer[0], sizeof( int ) );
                    memcpy( &Potentiometer2, &rxBuffer[kNumBytesPerInt+1], sizeof( int ) );                    
                    
                    //print them
                    printReceivedVariablesSerialMonitor();
                    
                    //adjust them and update the servos
                    adjustServosAccordingly();                    
                    
                    //update the message timer
                    tServoUpdate = millis();
                    
                    //and go back to state zero ready for the next message
                    state = 0;
                    
                }//if
                
            break;
            
        }//switch
        
    }//if

}//receiveWithStartEndMarkers

void printReceivedVariablesSerialMonitor()
{
    Serial.print("Potentiometer1= ");
    Serial.println(Potentiometer1);
    Serial.print("Potentiometer2= ");
    Serial.println(Potentiometer2);  
    
}//printReceivedVariablesSerialMonitor

void adjustServosAccordingly()
{
    Servo1 = map(Potentiometer1, 0, 1023, 0, 179);
    Servo2 = map(Potentiometer2, 0, 1023, 0, 179);
    
    servo_1.write(Servo1);
    servo_2.write(Servo2);
    
}//adjustServosAccordingly

Because you can't load code from the ide over usb with the HC12's connected to pin 0 and pin 1. The HC12's block the code from being downloaded.

I got it to work with wires in between the arduinos instead of HC12. Here is the sender code:

#include <SoftwareSerial.h>;
SoftwareSerial HC12(2,3);
int Potentiometer1=0;
int Potentiometer2=0;
int Potentiometer1pin = A1;
int Potentiometer2pin = A2;

void setup() {
  HC12.begin(2400);
  Serial.begin(9600);
  pinMode(Potentiometer1pin, INPUT);
  pinMode(Potentiometer2pin, INPUT);

}

void loop() { // run over and over
  readPotentiometerValue();
  sendValuesHC12();
  printToMonitor();
  delay(10);
}

void readPotentiometerValue(){
  Potentiometer1 = analogRead(Potentiometer1pin);
  Potentiometer2 = analogRead(Potentiometer2pin);
}

void sendValuesHC12(){
  HC12.write('<');
  HC12.print(Potentiometer1);
  HC12.write(',');
  HC12.print(Potentiometer2);
  HC12.write('>');
}

void printToMonitor(){
  Serial.print("Potentiometer1 = ");
  Serial.println(Potentiometer1);
  Serial.print("Potentiometer2 = ");
  Serial.println(Potentiometer2);
}

Here is the receiver code:

#include <Servo.h>;
#include <SoftwareSerial.h>;
SoftwareSerial HC12(2,3);
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
int Potentiometer1 = 0;
int Potentiometer2 = 0;
int Servo1=0;
int Servo2=0;
Servo servo_5;
Servo servo_6;

boolean newData = false;

void setup() {
    Serial.begin(9600);
    HC12.begin(2400);
    servo_5.attach(5);
    servo_6.attach(6);
}


void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
        adjustServos();
    }
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (HC12.available() > 0 && newData == false) {
        rc = HC12.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    Potentiometer1 = atoi(strtokIndx); // copy it to Potentiometer1
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    Potentiometer2 = atoi(strtokIndx);     // Copy second part to Potentiometer2

}

//============

void showParsedData() {
    Serial.print("Potentiometer1 = ");
    Serial.println(Potentiometer1);
    Serial.print("Potentiometer2 = ");
    Serial.println(Potentiometer2);
}

void adjustServos(){
  Servo1=map(Potentiometer1, 0, 1023, 0, 179);
  Servo2=map(Potentiometer2, 0, 1023, 0, 179);
  servo_5.write(Servo1);
  servo_6.write(Servo2);
}

However, this is with 2 wires going between the arduinos instead of HC12s.

Would this same code and configuration work if I were to plug pin 2 on each into the tx of HC12 and pin 3 into the RX?
I wish I could try it out but can't because in this process I fried my HC12s

I got it to work with wires in between the arduinos instead of HC12.

Well done. You have learned one of the key lessons in developing code for Serial based wireless communications in that you can usually develop and test the code independently from the radios.

SoftwareSerial HC12(2,3); //RX,TX

Would this same code and configuration work if I were to plug pin 2 on each into the tx of HC12 and pin 3 into the RX?

Yes. The Software Serial constructor is from the point of view of the Arduino and the way to connect two devices for communication is RX>TX and TX>RX. That is, they are cross connected.

I wish I could try it out but can't because in this process I fried my HC12s

I'm sorry to hear about the mishap with your units.

What did you do that "fried" them? How do you know they are bad? Were they ever working properly with each other? I know that you have been into the AT command mode because you have set the baud rate to 2400 and perhaps they are not configured correctly.

When I got them yesterday I soldered them and then used a code I found online to set them up. I conversed with both units through the serial monitor of a nano, and the AT commands worked. Now, when I try to use these same AT commands with that code, they don't respond.

Just to clarify, if I were to buy new HC12s and keep the setup I have right now, could I replace the wires connecting RX>TX and TX>RX with an HC12 on each end?
I am just wondering whether I should order new HC12s, or if I should look for another wireless module.

Also, I am unclear on if the HC12 communication requires the library because I have seen it being used in some other hc12 projects I saw online?

It's not clear to me if the modules are now set to 2400 baud whether that applies to AT mode now or not. Try your AT coms at 2400. If that doesn't work, See this data sheet and read page 7 about how to enter AT mode in a way which should ensure that AT mode is at 9600 baud. I would keep working with the modules before you declare them damaged.

Just to clarify, if I were to buy new HC12s and keep the setup I have right now, could I replace the wires connecting RX>TX and TX>RX with an HC12 on each end?

I do not think that the new modules will work at 2400 baud unless you change them from default settings. I think that you could change the code to use Software Serial at 9600 baud and the new modules should work as delivered.

whether I should order new HC12s, or if I should look for another wireless module.

One issue with the HC12 is that there are clone modules which do not work well. It is important to get factory originals sourced from the hc01 factory in China.

There is a very long thread about all the issues with the clones here https://www.thebackshed.com/forum/ViewTopic.php?TID=10443.
There is a video about possibly fixing a bad one here
https://www.youtube.com/watch?v=ZfBuEAH-Q8Y

I would think that Bluetooth HC05 modules could work for your application but then you will have the issue of configuring one as a master and binding it to the other one. The HC12's have much better range.
There are plenty of other wireless solutions, but most if them will be more complex to use (and will require libraries) than those which use a serial protocol to communicate with the Arduino.

Also, I am unclear on if the HC12 communication requires the library because I have seen it being used in some other hc12 projects I saw online?

What library are you talking about?

You do need to use SoftwareSerial.h is you are using software serial between the module and the Arduino. As discussed earlier, you can use hardware serial between the module and the Arduino and then no libraries are needed to use the HC12.

The wire.h library. Sorry, I had put this in the first time but it was between angle brackets like in code and didn't post to the forum correctly. Also, what does it mean by low level for the set pin of HC12? I have been putting it on the GND, is that right?

Also, what does it mean by low level for the set pin of HC12? I have been putting it on the GND, is that right?

Correct.

Wire.h is not required to use the HC12's.