some help please

hi
i am trying to build a industrial plc with a couple arduino.
The first arduino uno have a load cell which constantly write results to a 7 seg display and send the data to a second arduino mega (here is the problem).

The code for the first arduino uno.

#include "HX711.h"
#include <SoftwareSerial.h>

#define calibration_factor 190 //This value is obtained using the SparkFun_HX711_Calibration sketch

#define DOUT  3
#define CLK  2
int Pin = 10;
int Pin1 = 11;
int Pin2 = 12;
int Pin3 = 13;
int val;

HX711 scale(DOUT, CLK);
SoftwareSerial Serial7Segment(7, 8); //RX pin, TX pin

void setup() {
 pinMode(Pin, OUTPUT);
 pinMode(Pin1, OUTPUT);
 pinMode(Pin2, OUTPUT);
 pinMode(Pin3, OUTPUT);
 Serial.begin(9600);
 Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
 Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
 scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
 scale.tare();  //Assuming there is no weight on the scale at start up, reset the scale to 0
}

void loop() {
 val = scale.get_units(),1;

 char tempString[10]; //Used for sprintf
 sprintf(tempString, "%4d", int (scale.get_units()));
 Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
 delay(200);

 if (val < 250 & val > 0){
   analogWrite (Pin, val);
   delay(10);}
 else if(val <500 & val>249){
   digitalWrite(Pin1, HIGH);
   analogWrite(Pin, val - 250);
   delay(10);}
 else if(val <750 & val>499){
   digitalWrite(Pin2, HIGH);
   analogWrite(Pin, val - 500);
   delay(10);}
 else if(val <1000 & val>749){
   digitalWrite(Pin1, HIGH);
   digitalWrite(Pin2, HIGH);
   analogWrite(Pin, val - 750);
   delay(10);}
 else if(val <1250 & val>999){
   digitalWrite(Pin3, HIGH);
   analogWrite(Pin, val - 1000);
   delay(10);}
 else if(val <1500 & val>1249){
   digitalWrite(Pin1, HIGH);
   digitalWrite(Pin3, HIGH);
   analogWrite(Pin, val - 1250);
   delay(10);}
 else if(val <1750 & val>1499){
   digitalWrite(Pin3, HIGH);
   digitalWrite(Pin2, HIGH);
   analogWrite(Pin, val - 1500);
   delay(10);}
 else {
   digitalWrite(Pin1, HIGH);
   digitalWrite(Pin2, HIGH);
   digitalWrite(Pin3, HIGH);
   analogWrite(Pin, val - 1750);
   delay(10);}
 digitalWrite(Pin1, LOW);
 digitalWrite(Pin2, LOW);
 digitalWrite(Pin3, LOW);
 analogWrite(Pin, 0
 );
}

the code for the second arduino mega

int Pin = A8;
int Pin1 = 52;
int Pin2 = 50;
int Pin3 = 48;
int zygisma = 0;
int apotelesmazygarias;
int x = 0;

void setup() {
 // put your setup code here, to run once:
 Serial.begin(9600);
 pinMode(Pin, INPUT); 
 pinMode(Pin1, INPUT);
 pinMode(Pin2, INPUT);
 pinMode(Pin3, INPUT);
 Serial.print('etoimos');
}

void loop() {
 // put your main code here, to run repeatedly:
 if (Pin1 == HIGH)
   {zygisma += 250;}
 if (Pin2 == HIGH)
   {zygisma += 500;}
 if (Pin3 == HIGH)
   {zygisma += 1000;}
 x = analogRead(Pin);
 Serial.print(x);
 Serial.print('\n');
 apotelesmazygarias = x + zygisma;
 Serial.print('apotelesmazygarias');
 Serial.print('\n');
 Serial.print(apotelesmazygarias);
 Serial.print('\n');
 delay(100);
 

}

if i manage to work it properly i will use python , tkinter and pyserial for a complete solution.
any ideas?
Thanks a lot

Step 1
Read How to use this forum - please read, specifically point 7 how to post code

Step 2
Read How to use this forum - please read, point 11:

  • describe the problem in detail
  • how everything is connected; in this case connection between Mega and Uno

Note:
Nowhere in your codes seems to be something that indicates communication between Uno and Mega.

 if (Pin1 == HIGH)
    {zygisma += 250;}

Pin1 does not contain the current state of the pin - it contains the pin number. To get whether it is HIGH or LOW, you need to read the pin using the digitalRead function

 if (digitalRead(Pin1) == HIGH)
    {zygisma += 250;}

Also, attempting to use analogWrite and analogRead to transfer an analog value from one arduino to another will probably not work well, because an analog pin doesn't really hold a variable voltage. At any given time, it holds either HIGH or LOW, but these are switched back and forth very fast (pulse-width encoding). You'd need some electronics to make this work (to filter out the HF component), and it probably wouldn't be accurate.

on the 7 seg , i get exactly and correct what i need, the problem is that i use softwareserial on the 7 seg and i can't use it again to communicate again with the second arduino so i have to find another way ,
i can send 0 - 255 with analogWrite with a map function to the second arduino but it wouldn't be accurate.

So the idea was that if i want to send from (1 to 2000 kilos 'data') to second arduno.
i send pin 1 - 2 - 3 low
0 0 0 = 0
+analogRead 0 -255

another example , i want to send 800 kilos :
uno send 1high - 2high- 3low
250 500 0 = 750
+analogRead 50
the sum is 800

a last one , 1600
uno send 1low, 2high, 3high
0 500 1000
+analogRead 100
the sum is 1600

i will try in a while to change the code with the suggestion of Paul, there are another way?, really sorry for everything i am begginer and this is the first post in here

The problem is that if you have one arduino output with analogRead(somePin, 127), and then try to read that with another Arduino you aren't going to see 2.5V. You're going to get 0V part of the time and 5V part of the time.

The only way you could communicate by analogWrite like that would be to measure pulse widths. That's ay more work than you need to do to get communication between two boards. Why don't you use Serial? Or I2C? Or SPI?

Perhaps what needs to be said here is that the OP is discovering exactly why there are a number of different protocols for sending data from one thing to another thing. If you have some wires that are either grounded or at +5v, using those wires to get bytes from one place to another is actually not straightforward. It’s the reason for layer 1 of the OSI model (I think it’s layer 1, right? Framing).

Delta_G mentions Serial, I2C, SPI. I would tend to go for i2c, because it’s not timing dependent - you don’t need a UART - and because I don’t know much about SPI :slight_smile: . You need three wires: SDA, SCL, and ground. One of the arduinos would act as master, the other as slave.The master is the one that initiates the communication, so either the load cell sends data when appropriate, or the receiver of the data periodically requests data to be sent as a reply. You’d use the <Wire.h> library.

There are other protocols. Morse code comes to mind - another solution to the same problem.

Thank you guys , yours suggestions were what i needed, i2c library , but i am stuck again , the master arduino reads the data from the slave uno but i can’t terminate it.

#include <Wire.h>
boolean replay = true;

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  while (replay == true){
    Wire.requestFrom(2, 4);    // request 4 bytes from slave device #2

    while (Wire.available()) { // slave may send less than requested
      char c = Wire.read(); // receive a byte as character
      Serial.print(c); // print the character
      if (1000 <= int(c)){replay == false;}
  }

  delay(200);
}}

slave

#include "HX711.h"
#include <SoftwareSerial.h>
#include <Wire.h>

#define calibration_factor 190 //This value is obtained using the SparkFun_HX711_Calibration sketch

#define DOUT  3
#define CLK  2

int val;

HX711 scale(DOUT, CLK);
SoftwareSerial Serial7Segment(7, 8); //RX pin, TX pin
boolean replay = true;

void setup() {
  Serial.begin(9600);
  Wire.begin(2);
  Wire.onRequest(requestEvent);
  Serial7Segment.begin(9600); //Talk to the Serial7Segment at 9600 bps
  Serial7Segment.write('v'); //Reset the display - this forces the cursor to return to the beginning of the display
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare();  //Assuming there is no weight on the scale at start up, reset the scale to 0
}

void loop() {
  val = scale.get_units(),1;

  char tempString[10]; //Used for sprintf
  sprintf(tempString, "%4d", int (scale.get_units()));
  Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
  delay(200);

}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
  if (replay == true){
    char tempString[10]; //Used for sprintf
    sprintf(tempString, "%4d", int (scale.get_units()));
    Serial7Segment.print(tempString); //Send serial string out the soft serial port to the S7S
    Wire.write(tempString); // respond with message of 4 as expected by master
    delay(200);
    ///if (tempString >= 1000){       i tried here to kill i2c connection on the slave side but no success
      ///replay = false;}
      }
}

Any ideas for finishing i2c and use it in a while without problems.

the ideal solution would be , arduino mega to write the address of the slave , the required kilos and then read and display till slave finished , the slave reads his adress , read and keep the required kilos and then open a pin and sending data throught i2c till it is what mega have sent and of course turn the pin off (it would be a motor or a door of a silo).

while (Wire.available()) { // slave may send less than requested
      char c = Wire.read(); // receive a byte as character
      Serial.print(c); // print the character
      if (1000 <= int(c)){replay == false;}
  }

read() does return an int, but the values you get from it are all going to be 0 - 255 or -1. The only reason it is an int is so they can return -1 for nothing to read. The data you would read would all be char sized. You actually realize this because you store it in the char c.

Since c is a char, it will never ever ever ever be greater than 1000, so this while loop will never end.

You may also like to revisit the use of
analogWrite(Pin, val - 1750); in various places.
val (or a proxy of it) should be scaled within the required range for 'analogWrite()'
All that subtraction while not a problem, makes the code less readable - and will bite you in the future for changes in the code.

actually @lastchance, you found a terrible bug.

Look at how val is defined:

val = scale.get_units(),1;

which is equivalent to

val = 1;

So val is being set to 1. And 1 - 1750 will be WAY out of range for an analogWrite.

Not sure what the OP is thinking with the , 1 in there.

i’m so good, i wasn’t even looking !

Delta_G:

val = scale.get_units(),1;

which is equivalent to

val = 1;

No. The comma operator has the lowest precedence of all.
The value of the whole expression is 1 (which is then discarded), but the assignment is only a part of it.

      if (1000 <= int(c)){replay == false;}

Comparing the value of replay to false, and not caring one way or the other is also pointless.

More = is better, right? 8)

MorganS:
More = is better, right? 8)

You :=== bet! 8)

Delta_G:
actually @lastchance, you found a terrible bug.

Look at how val is defined:

val = scale.get_units(),1;

which is equivalent to

val = 1;

So val is being set to 1. And 1 - 1750 will be WAY out of range for an analogWrite.

Not sure what the OP is thinking with the , 1 in there.

i will try to find the instructions for the "1" part.
It converts val to a int so it can be displayed to the 7 seg display or at least this is the suggestion.

oqibidipo:
No. The comma operator has the lowest precedence of all.
The value of the whole expression is 1 (which is then discarded), but the assignment is only a part of it.

i have tried this and it returns negative values , if i press the load cell on the other side .
so this is not the lowest acceptable value.

PaulS:

      if (1000 <= int(c)){replay == false;}

Comparing the value of replay to false, and not caring one way or the other is also pointless.

after a search on the google how to end the void loop or the void requestEvent , this was the major response,
where is exactly my mistake, i can’t see it.

Last but not least , i tried triple = but still is not working (and of course single).

Well at least the single = did something. The line as you have it written right now is not doing anything. The triple equal was a joke that apparently you missed.

Delta_G:
Well at least the single = did something. The line as you have it written right now is not doing anything. The triple equal was a joke that apparently you missed.

and some videos on youtube, and try this one

void loop() {
while (replay == true){
........
if ( int(c)>=1000){replay = false;}}

now that i read it once more , i think i can't end void loop but end another void ... end return to void loop(or i am again wrong?)

I haven't missed the joke :slight_smile: