Request Serial data

Serial communication at request.

I'm working on a project where I have 2 Arduino mega boaard.
One is meassuring the RPM with the interupts.
The other Mega is controlling the speed and display.

I want the RPM from one to the other Aruino but with the communication it misses bytes so the output is not correct.
How can I make the communcation so that the controller is requesting the data and the transmit is OK.
Test_Tacho_speed.ino (3.1 KB)
Test_Tacho_control.ino (8.0 KB)

Is there someone how can help??

Thank in advance...

Regards,

Hans

Hello Hans,
Please read the forum guidelines How to get the best out of this forum , particularly the bit about posting code. If you put the code in your post with code tags </> more people are likely to read it and help you.

Please also see Serial Input Basics - updated for advice on serial communications.

Thanks,

  Serial.available()<4;

what do you expect the above to do?

would have been nice if code were posted using </>. had to write a program to replace \r with \n. the linked code had no \ns

The use of 2 controllers, the way I understand it, is a disaster out of the fundamentals of control theory. The delay caused in the communication works as play in mechanics, a troubling factor in electronics. All serious difficulties.

Don’t tell NASA. :wink:

a7

I wont, have only been working for ESA......

Edit- BUT as @Railroader noted above splitting the control across two boards is not the way to go.
Measure and control on one board and if you need to display in the other
You can always send the setpoint back from the LCD board to the control board, if that is what is convenient.

Arduino to Arduino via Serial has some complete examples for send data between Arduino boards and some of the problem to look out for.
Serial RX buffer overflow often cause problems. So you could try reducing the Serial3 baudrate say 300 and once you get thing running you can increase it.

  Serial3.begin(300);

Also Serial3.flush(); is probably not doing what you want.
Check out Flushing the Input

Also as noted above Serial.available()<4; is not helpfull
Check out Arduino Software Solutions for methods of reading/parsing Serial.
And increase your Serial baud rate to Serial.begin(1125200); to help prevent Serial.prints( ) blocking your loop.
Arduino Serial I/O for the Real World has a lot more detail on this, but increasing the baud rate is the first step.

This project illustrate the concept if local control and remote display/setpoint setting.
BLE Temperature sensor Controlled Room Heater
The two way Serial connect sends out the current readings and control mode periodically to a WiFi board and when the setpoint or control mode is changed by the app they are sent back over the serial connection from the WiFi board to the control board where they are parsed and applied.

Who misses the bytes? I suspect the one that is measuring.

If so, implement a simple protocol. Send one byte of the command from the controller, let the slave echo it so the controller knows that it is received, send the next byte from the controller, let the slave echo it and so on. Once the complete command is transferred, controller can wait for reply.

Here is a simple echo test sketch. Open two copies of the IDE one for each board.

// https://forum.arduino.cc/t/i-need-help-with-this-serial-communiction-with-2-arduinos-and-to-put-3-more-sensors-ultrassom/875806
// uno/mega to uno/mega

// if using SoftwareSerial on Uno/Mega
#ifdef SOFTWARE_SERIAL
#include <SoftwareSerial.h>
#define SERIAL_RX 10
#define SERIAL_TX 9
SoftwareSerial softSerial(SERIAL_RX, SERIAL_TX);
#define comSerial softSerial

#else
// else for hardware Serial3
#define comSerial Serial3
#endif

void setup() {
  Serial.begin(115200);  // fast for debug
  for (int i = 10; i > 0; i--) {
    Serial.print(i); Serial.print(' ');
    delay(500);
  }
  Serial.println();
  comSerial.begin(4800);

}

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

If you want a system that waits for reply, the SerialComs class on Arduino Serial I/O for the Real World only lets one side send at a time and adds a check sum to the message.
Provided the whole message fits in the Serial RX buffer, SerialComs is tolerant of long delays on either side.

still no answer?

Hello, sorry for the delay. I do have to work so I'm able to come back as fast as I wanted to.
But I understood that the <4 indicates that there will be 4 bytes of data to receive.

Thanks

Hans

The arduino thats sending the data just send's it. But due to the interupts the data transmitting is not a constant string of bytes.

This couses th receing Arduino to mis some bytes.
Also it's hard to implement a delay due to the controller (still have to implement is) with a PID regulator.
This is to make the second motor match the speed of the first controller.

Regards,

Hans

but that statement isn't a conditional.

sounds like you want the following code to only execute "if" there are at least 4 bytes available. so perhaps

  if (Serial.available()<4)
      return;

There are some flaws in your Test_Tacho_speed.ino.

Variables that are used in both the main program (setup / loop / functions) and in an interrupt must be declared volatile; those are the variables Hall_xxx_tijd_y.

Those variables also need to be protected from changes in the interrupt while you access them in the main program; so you have to disable the interrupts, access the variable and enable the interrupts again.

Lastly Serial3.write(x) only sends a single byte. The variables that you transfer are however ints and will be truncated once the exceed the value 255 (0xFF).

And a flaw in Test_Tacho_control.ino.

You use Serial3.parseInt(); this expects text but you're not sending text, you're sending binary data with the Serial3.write(x) in Test_Tacho_speed.ino. Further parseInt() has a timeout while waiting for a non-digit or remaining data; I think it's 1 second.

If you want to use parseInt() at the receiver, the sender must use print(x) / println(x) instead of write(x). Be aware that print(x) / println(x) sends a text representation of the number so will send e.g. the text 255 (3 bytes) instead of the number 255 (one byte).

As mentioned earlier, you should post your code in a post, not as an attachment

Test_Tacho_control.ino

/*
  Dit programma is voor megatronica.
  Het is geschreven om 2 motoren te sturen.

  H. M. Sietsema
*/

// library voor 2,8" TFT scherm
#include <Adafruit_TFTLCD.h>
//  #include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#include <TouchScreen.h>
// library voor drukknoppen
#include <ezButton.h>
// generike library
#include <Wire.h>
#include <SPI.h>

//3.5 TFT scherm
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
//  #define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

//kleuren definieren
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

//omreken factoren die makkelijk kunnen zijn
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105

//bepalen pinnen voor motorsturing
#define Motor1Pin1 0
#define Motor1Pin2 1
#define Motor2Pin1 12
#define Motor2Pin2 13
#define Motor1Speed 10
#define Motor2Speed 11

float aHall_sensor_tijd_1[10];
float aHall_sensor_tijd_2[10];
float aHall_sensor_tijd_3[10];
float aHall_sensor_tijd_4[10];
float average_hall_1, average_hall_2, average_hall_3, average_hall_4;
int count_hall_1 = 0, count_hall_2 = 0, count_hall_3 = 0, count_hall_4 = 0, Hall_direction_tijd_1, Hall_direction_tijd_2;
int delay_Display = 0;
int delay_average = 0;
int newPosition, oldPosition, constPosition, gasPosition;
int Draairichting_1_gemeten, Draairichting_2_gemeten, RPM1, RPM2;

int Button1Status, Button2Status;
int Button1Var = 1;
int Button1Toggle = 1;

int pid_speed = 0;
float kp = 2.25;
float ki = 0.01;
float kd = 0.005;
int error = 0;
float PIDPosition = 0;                                                 //PID berekende gaspositie
int diff = 0;

ezButton button1(22);                                                   //wijs pin 22 aan drukknop 1 toe
ezButton button2(24);                                                   //wijs pin 24 aan drukknop 2 toe
char ButtonDisplayValue1[26];
char ButtonDisplayValue2[26];
char *Draairichting1;
char *Draairichting2;

int Potmeter1 = A5;
int PotValue = 0;
char PotDisplayValue[24];
char gasDisplayValue[24];
char PIDDisplayValue[24];
char TimeDisplayValue1[24];
char TimeDisplayValue2[24];
char Gemetenrichting1[26];
char Gemetenrichting2[26];
char TimeSpeedSensor1[24];
char TimeSpeedSensor2[24];


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

  // Zet de pinnen voor het correcte gebruik
  pinMode(Motor1Pin1, OUTPUT);
  pinMode(Motor1Pin2, OUTPUT);
  pinMode(Motor2Pin1, OUTPUT);
  pinMode(Motor2Pin2, OUTPUT);

  pinMode(Motor1Speed, OUTPUT);
  pinMode(Motor2Speed, OUTPUT);

  // initialisatie van het TFT display
  tft.begin(0x9486);
  tft.setRotation(0);
  tft.setTextSize(2);
  tft.setTextColor(WHITE, BLACK);

  //  iSetAchtergrondTFT(); //Subroutine voor het schrijven van de achtergrond van het TFT scherm
  tft.fillScreen(BLACK);  //set de achtergrond zwart
  tft.drawRect(0, 0, 320, 480, WHITE);


}

void loop() {

  Serial.available() < 4;

  Draairichting_1_gemeten = Serial3.parseInt();
  Draairichting_2_gemeten = Serial3.parseInt();
  RPM1 = Serial3.parseInt();
  RPM2 = Serial3.parseInt();

  Serial.println(Draairichting_1_gemeten);
  Serial.println(Draairichting_2_gemeten);
  Serial.println(RPM1);
  Serial.println(RPM2);

  iUitleesPotmeter();

  iButUitlezen();

  iMotorControl();

  //  iPID();

  if (delay_Display == 9) {
    iDisplay();
    delay_Display = 0;
  }
  else {
    if (delay_Display < 9) {
      delay_Display ++;
    }
  }

  /*  if(Hall_direction_tijd_1 < 20){
      Draairichting_1_gemeten = "Rechts";
    }
    else{
      Draairichting_1_gemeten = "Links ";
    }

    if(Hall_direction_tijd_2 < 20){
      Draairichting_2_gemeten = "Rechts";
    }
    else{
      Draairichting_2_gemeten = "Links ";
    }


    //  RPM1 = (1/ (Hall_sensor_tijd_1 / 500000));
    //  RPM2 = (1/ (Hall_sensor_tijd_3 / 500000));

  */
}

////////////      Functions    ////////////

void iPID(void) {
  error = Draairichting_1_gemeten - Draairichting_2_gemeten;

  diff += error;
  pid_speed = kp * error; + ki*diff;

  pid_speed = (int)pid_speed;
  if (pid_speed > 0) {
    if (pid_speed < 255)
      PIDPosition = 255;
    else
      PIDPosition = pid_speed;
  }
  if (pid_speed < 0) {
    if (pid_speed < -255)
    {
      PIDPosition = 0;
    }
    else
    {
      pid_speed = abs(pid_speed);
      PIDPosition = 255 - pid_speed;
    }
  }

}

void iUitleesPotmeter(void) {
  PotValue = analogRead(Potmeter1);
  Serial.println(PotValue);
  gasPosition = 0;
  gasPosition = map (PotValue, 0, 1023, 0, 255);

}

void iButUitlezen(void) {
  button1.loop(); // MUST call the loop() function first

  Button1Status = button1.getState();
  if (Button1Status == 0 && Button1Var == 1) {
    if (Button1Toggle == 0) {
      Button1Toggle = 1;
    }
    else {
      Button1Toggle = 0;
    }
  }
  Button1Var = Button1Status;
}

void iAverage(void) {
  int i = 0, j = 0;
  average_hall_1 = 0;
  average_hall_2 = 0;
  while (i < 10) {
    aHall_sensor_tijd_1[i] += average_hall_1;
    i++;
  }
  average_hall_1 / 10;

  while (j < 10) {
    aHall_sensor_tijd_2[j] += average_hall_2;
    j++;
  }
  average_hall_2 / 10;
  delay_average = 0;
}

void iMotorControl(void) {

  //Controlling speed (0 = off and 255 = max speed):
  analogWrite(Motor1Speed, gasPosition); //ENA pin
  analogWrite(Motor2Speed, gasPosition); //ENB pin

  //Controlling spin direction of motors:

  if (Button1Toggle == 1) {
    digitalWrite(Motor1Pin1, HIGH);
    digitalWrite(Motor1Pin2, LOW);
  }
  else {
    digitalWrite(Motor1Pin1, LOW);
    digitalWrite(Motor1Pin2, HIGH);
  }

  if (Draairichting_1_gemeten == "Rechts") {
    digitalWrite(Motor2Pin1, HIGH);
    digitalWrite(Motor2Pin2, LOW);
  }
  else {
    digitalWrite(Motor2Pin1, LOW);
    digitalWrite(Motor2Pin2, HIGH);
  }
}

////////////      Visualisatie    ////////////

void iDisplay(void) {
  tft.setCursor(10, 10);
  snprintf(PotDisplayValue, 24, "Potmeter waarde = %4i",  PotValue);
  tft.print(PotDisplayValue);

  tft.setCursor(10, 30);
  if (Button1Toggle == 0) {
    Draairichting1 = "Rechts";
  }
  else {
    Draairichting1 = "Links ";
  }
  snprintf(ButtonDisplayValue1, 26, "Draairichting M1 = %s\n",  Draairichting1);
  tft.print(ButtonDisplayValue1);

  tft.setCursor(10, 50);
  if (Button1Toggle == 0) {
    Draairichting2 = "Rechts";
  }
  else {
    Draairichting2 = "Links ";
  }
  snprintf(ButtonDisplayValue2, 26, "Draairichting M2 = %s\n",  Draairichting2);
  tft.print(ButtonDisplayValue2);

  tft.setCursor(10, 80);
  snprintf(gasDisplayValue, 24, "Motor M1 waarde = %4i",  gasPosition);
  tft.print(gasDisplayValue);

  tft.setCursor(10, 100);
  snprintf(PIDDisplayValue, 24, "Motor M2 waarde = %4i",  PIDPosition);
  tft.print(PIDDisplayValue);

  tft.setCursor(10, 120);
  snprintf(TimeDisplayValue1, 24, "Toerental M1 = %4i",  RPM1);
  tft.print(TimeDisplayValue1);

  tft.setCursor(10, 140);
  snprintf(TimeDisplayValue2, 24, "Toerental M2 = %4i",  RPM2);
  tft.print(TimeDisplayValue2);

  tft.setCursor(10, 160);
  snprintf(Gemetenrichting1, 26, "Draairichting M1 = %s\n",  Draairichting_1_gemeten);
  tft.print(Gemetenrichting1);

  tft.setCursor(10, 180);
  snprintf(Gemetenrichting2, 26, "Draairichting M2 = %s\n",  Draairichting_2_gemeten);
  tft.print(Gemetenrichting2);

  tft.setCursor(10, 300);
  snprintf(TimeSpeedSensor1, 24, "M1 tijd sensor = %6i",  Hall_direction_tijd_1);
  tft.print(TimeSpeedSensor1);


  tft.setCursor(10, 320);
  snprintf(TimeSpeedSensor2, 24, "M2 tijd sensor = %6i",  Hall_direction_tijd_2);
  tft.print(TimeSpeedSensor2);
}

Test_Tacho_speed.ino

/*
  Dit programma is voor megatronica.
  Het is geschreven om 2 motoren te sturen.

  H. M. Sietsema
*/

// generike library
#include <Wire.h>
#include <SPI.h>

//ingangen voor de snelheidssensoren.
#define MotorHall1  18
#define MotorHall2  19
#define MotorHall3  20
#define MotorHall4  21

byte last_channel_1, last_channel_2, last_channel_3, last_channel_4;
double Hall_sensor_tijd_1, Hall_sensor_tijd_2, Hall_sensor_tijd_3, Hall_sensor_tijd_4;
unsigned long timer_1, timer_2, timer_3, timer_4;
int Hall_direction_tijd_1, Hall_direction_tijd_2;
int RPM1, RPM2;

int Draairichting_1_gemeten, Draairichting_2_gemeten;

void setup() {

  Serial.begin(9600);
  Serial3.begin(9600);

  Serial3.flush();

  //interupt setup
  attachInterrupt(digitalPinToInterrupt(18), HallPuls1, RISING);
  attachInterrupt(digitalPinToInterrupt(19), HallPuls2, RISING);
  attachInterrupt(digitalPinToInterrupt(20), HallPuls3, RISING);
  attachInterrupt(digitalPinToInterrupt(21), HallPuls4, RISING);
}

void loop() {

  if (Hall_direction_tijd_1 < 20) {
    Draairichting_1_gemeten = 1;
  }
  else {
    Draairichting_1_gemeten = 0;
  }
  Serial3.write(Draairichting_1_gemeten);
  //Serial3.write(Draairichting_1_gemeten%256);


  if (Hall_direction_tijd_2 < 20) {
    Draairichting_2_gemeten = 1;
  }
  else {
    Draairichting_2_gemeten = 0;
  }
  Serial3.write(Draairichting_2_gemeten);
  //Serial3.write(Draairichting_2_gemeten%256);


  RPM1 = (1 / (Hall_sensor_tijd_1 / 500000));
  RPM2 = (1 / (Hall_sensor_tijd_3 / 500000));
  Serial3.write(RPM1);
  Serial3.write(RPM2);
}

////////////      Functions    ////////////

void HallPuls1(void) {                                                  // this function will run if a pin change is detected on portB
  //Tacho 1=====================================================
  if (last_channel_1 == 0) {                     // Input 8 changed from 0 to 1
    last_channel_1 = 1;                                             // Remember current state
    timer_1 = micros();                                             // Set timer_1 to micros()
  }
  else if (last_channel_1 == 1) {             // Input 8 changed from 1 to 0
    last_channel_1 = 0;                                            // Remember current state
    Hall_sensor_tijd_1 = micros() - timer_1;                  // Calculate total micros()
  }
}

void HallPuls2(void) {
  if (RPM1 < 25) {
    Hall_direction_tijd_1 = micros() - timer_1;
  }
}

void HallPuls3(void) {
  //Tacho 2=====================================================
  if (last_channel_3 == 0) {                     // Input 8 changed from 0 to 1
    last_channel_3 = 1;                                             // Remember current state
    timer_3 = micros();                                             // Set timer_1 to micros()
  }
  else if (last_channel_3 == 1) {             // Input 8 changed from 1 to 0
    last_channel_3 = 0;                                            // Remember current state
    Hall_sensor_tijd_3 = micros() - timer_3;                  // Calculate total micros()
  }
}

void HallPuls4(void) {
  if (RPM2 < 25) {
    Hall_direction_tijd_2 = micros() - timer_2;
  }
}

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