PC to fast / Serial Call and Response with Arduino

Dear all,

I'm building a dew controller for my telescope which is heating the mirror to keep it 1-2 degrees above dew point if needed.

As the humidity, temperature, dew point data are available anyway I dont want to waise them but track them overnight as the telescope is in automated, unattened imaging session.

There is some special astronomy software / application for tracking these data using Com-Port.

This software ist sending via COM-port a 1st the string "SWHOIS" as command.
I'm managing via Serial.println to answer

"##22.37/22.62/23.35/50.77/12.55/0/0/0/0/0/0/2/2/0/0/4**"

The string presents the different temperatures (ambient, scope, dewpoint, humidity etc.)

Straight after the software is sending the string "SGETAL" which is the normal status call.

All commands send by the software are exactly 6 bytes but no start/end markers.

I m managing to send the fist reply but not to answer to the 2nd and following as it seems it is send simply to quickly by the software.

It's a quite superficial description for the moment but maybe someone of you has a thought-provoking impulse for me.

Thanks in advance and kind regards,
Alex

Hi,

can you program both ends of the connection to include start and stop characters...

to compile a checksum of what it's sending...

and to re-send if it doesn't get a confirmation code in return to whatever it's just sent?

Without this you'll likely have to play around with Com Port Speed (slow it down, maybe) and delays while either end allows time for the other end to catch up.

Peter

astroalex:
I m managing to send the fist reply but not to answer to the 2nd and following as it seems it is send simply to quickly by the software.

The serial port has a buffer for incoming traffic of 64 bytes. Doesn't matter how slow you are to pick the second command up, it will be there waiting for you. You have some other problem in your code. Speaking of which, for better help, post it.

astroalex:
There is some special astronomy software / application for tracking these data using Com-Port.

Please post a link to the datasheet that describes the communication prototcol

I m managing to send the fist reply but not to answer to the 2nd and following as it seems it is send simply to quickly by the software.

If you are not already doing so I suggest you write a short program that does nothing except collect the data.

If your Arduino is connected to your PC (and thus to the astronomy program) with the USB cable it will not be possible to view the results on the Serial Monitor without some extra hardware.

You could connect another serial port (Hardware serial if you are using a Mega, or SoftwareSerial on an Uno) to the PC with a USB-TTL cable and use that to display debug messages on the Serial Monitor.

...R

Dear all,

thanks for your swift replies.
For the software there is unfortunately no datasheet describing the communication / protocol.

The program is a Windows exe , standalone, no config file, etc. and the serial connection is set with 19.200 baud, 81N1 and cannot be changed, only the com port can be choosen.

From an indi driver I know following about the communication protocol.

First command send by the software when connection button pressed:
UDP_IDENTIFY_CMD "SWHOIS"

followed by UDP_STATUS_CMD "SGETAL" which then is re-send once a second.

// All commands are exactly 6 bytes, no start/end markers
UDP_CMD_LEN 6

// Responses also include "\n\r"

// Status response is like:
// ##22.37/22.62/23.35/50.77/12.55/0/0/0/0/0/0/2/2/0/0/4**

UDP_STATUS_RESPONSE "##%f/%f/%f/%f/%f/%u/%u/%u/%u/%u/%u/%u/%u/%u/%u/%u**"
UDP_STATUS_START "##"
UDP_STATUS_SEPARATOR "/"
UDP_STATUS_END "**"

// Fields are in order:
// temperature ch 1
// temperature ch 2
// temperature ambient
// relative humidity
// dew point
// output ch 1
// output ch 2
// output ch 3
// calibration ch 1
// calibration ch 2
// calibration ambient
// threshold ch 1
// threshold ch 2
// auto mode
// outputs ch 2 & 3 linked
// aggressivity

Please find underneath the code in an ino file. will send it as plain text in another message also.

Please be kind with me as surly my coding looks horrible.
I m hobby astronomer / photographer on first place :slight_smile:

Thanks for your support again,
Alex

Dew_controller_02.ino (7.73 KB)

here the code as text.

To watch the serial port I m using a program called "device monitoring studio" which shows the communication of the com-port.

//
#include <UTFT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <dht.h>

#define DHT11_PIN 7 // DHT11 data pin

#define heat_pin 3

OneWire ds(2);

dht DHT;

extern uint8_t SmallFont[]; // Declare which fonts we will be using

// Usage: myGLCD(, SDA, SCL, CS, RST[, RS]);

// connection of the TFT pins to ARDUINO pins
// GND
// BL +3.3
// VCC
// CLK 13
// DIN 11
// DC 9
// CS 10
// RST 8

UTFT myGLCD(ST7735, 11, 13, 10, 8, 9);

// used variables

String inputString = "";
bool stringComplete = false;

int delta = 2; // temperature delta mirrow vs. dew point in °C

int scope = 0; // index for the DS18x20 (mirror/scope temperature

int chk = 0; // for the DHT11 requests

float temperatureAir, humidity, temperatureScope, dewPoint;

// heating on/off
int heating_on = 0;

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

pinMode(heat_pin, OUTPUT);

// Setup the LCD
myGLCD.InitLCD();
myGLCD.setFont(SmallFont); //SmallFont

int buf[158];
int x, x2;
int y, y2;
int r;

//Clear the screen and draw
myGLCD.clrScr();
delay(100);
myGLCD.setColor(30, 30, 30);
myGLCD.fillRect(0, 0, 159, 13);
myGLCD.setColor(30, 30, 30);
myGLCD.fillRect(0, 114, 159, 127);
myGLCD.setColor(0, 0, 255);
myGLCD.setBackColor(30, 30, 30);
myGLCD.print("Dew Controller v0.1", CENTER, 1);
myGLCD.setBackColor(30, 30, 30);

myGLCD.setColor(0, 0, 255);
}

void check_heating( float TS, float TA) {
// 127 = 50%
// 191 = 75%
// 255 = 100&
float diff = TS - (TA + delta);

if (TS < (TA + delta)) {

if (diff < -2.00) {
analogWrite(heat_pin, 255);
}

else if (diff < -1.25) {
analogWrite(heat_pin, 200);
}
else if (diff < -0.75) {
analogWrite(heat_pin, 170);
}
else if (diff < -0.45) {
analogWrite(heat_pin, 65);

}
else {
analogWrite(heat_pin, 35);
}

heating_on = 1;

} else if (diff < 0.15) {
analogWrite(heat_pin, 20);
heating_on = 1;
}

else {

analogWrite(heat_pin, LOW);
heating_on = 0;

}

}

double calcDewPoint(double celsius, double humidity)
{
double RATIO = 373.15 / (273.15 + celsius);
double RHS = -7.90298 * (RATIO - 1);
RHS += 5.02808 * log10(RATIO);
RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO ))) - 1) ;
RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
RHS += log10(1013.246);

// factor -3 is to adjust units - Vapor Pressure SVP * humidity
double VP = pow(10, RHS - 3) * humidity;

// (2) DEWPOINT = F(Vapor Pressure)
double T = log(VP / 0.61078); // temp var
return (241.88 * T) / (17.558 - T);
}

// Fields are in order:
// temperature ch 1
// temperature ch 2
// temperature ambient
// relative humidity
// dew point
// output ch 1
// output ch 2
// output ch 3
// calibration ch 1
// calibration ch 2
// calibration ambient
// threshold ch 1
// threshold ch 2
// auto mode
// outputs ch 2 & 3 linked
// aggressivity

// "##" + String(temperatureScope) + "/11.11/" + String(temperatureAir) + "/" + String(humidity) + "/" + String(dewPoint) + "/0/0/0/0/0/0/2/2/0/0/4**"

void loop()
{

chk = DHT.read11(DHT11_PIN);

temperatureAir = DHT.temperature;
humidity = DHT.humidity;

temperatureScope = getTemperature();

dewPoint = calcDewPoint(temperatureAir, humidity) ;

myGLCD.setColor(0, 0, 0);
myGLCD.fillRect(90, 14, 159, 100);

myGLCD.setBackColor(0, 0, 0);
myGLCD.setColor(0, 0, 255);

myGLCD.print("Temperatur: ", 5, 15);
myGLCD.print(String(temperatureAir) + "$C", RIGHT, 15);

myGLCD.print("Feuchte: ", 5, 27);
myGLCD.print(String(humidity) + " %", RIGHT, 27);

myGLCD.print("Taupunkt: ", 5, 39);
myGLCD.print(String(dewPoint) + "$C", RIGHT, 39);

myGLCD.print("Teleskop: ", 5, 51);
myGLCD.print(String(temperatureScope) + "$C", RIGHT, 51);

myGLCD.print("Delta: ", 5, 63);

if ((temperatureScope - dewPoint) < 0 ) {
myGLCD.setBackColor(0, 0, 255);
myGLCD.setColor(255, 255, 255);
}
else {
myGLCD.setBackColor(0, 0, 0);
myGLCD.setColor(0, 0, 255);
}

myGLCD.print(String(temperatureScope - dewPoint) + "$C", RIGHT, 63);

myGLCD.setBackColor(0, 0, 0);
myGLCD.setColor(0, 0, 255);

myGLCD.print("Heizung: ", 5, 87);

check_heating(temperatureScope, dewPoint); //ändern in Dew point

if (heating_on == 0) myGLCD.print("off ", RIGHT, 87);
if (heating_on == 1) myGLCD.print(" on ", RIGHT, 87);

if (stringComplete) {
Serial.println("##" + String(temperatureScope) + "/11.11/" + String(temperatureAir) + "/" + String(humidity) + "/" + String(dewPoint) + "/0/0/0/0/0/0/2/2/0/0/4**");
// clear the string:
inputString = "";
stringComplete = false;
}

}

delay(1000);
}

void serialEvent()
{
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
if (inputString.length() == 6) {
stringComplete = true;
}
}
}

float getTemperature() {

byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;

if ( !ds.search(addr)) {
// Serial.println("No more addresses.");
// Serial.println();
ds.reset_search();
delay(250);
return;
}
/*
Serial.print("ROM =");
for( i = 0; i < 8; i++) {
Serial.write(' ');
Serial.print(addr*, HEX);*

  • }*
  • if (OneWire::crc8(addr, 7) != addr[7]) {*
  • Serial.println("CRC is not valid!");*
  • return;*
  • }*
  • Serial.println();*
    _ */_
  • // the first ROM byte indicates which chip*
  • switch (addr[0]) {*
  • case 0x10:*
  • // Serial.println(" Chip = DS18S20"); // or old DS1820*
  • type_s = 1;*
  • break;*
  • case 0x28:*
  • // Serial.println(" Chip = DS18B20");*
  • type_s = 0;*
  • break;*
  • case 0x22:*
  • // Serial.println(" Chip = DS1822");*
  • type_s = 0;*
  • break;*
  • default:*
  • // Serial.println("Device is not a DS18x20 family device.");*
  • return;*
  • }*
  • delay(300);*
  • ds.reset();*
  • ds.select(addr);*
  • ds.write(0x44, 1); // start conversion, with parasite power on at the end*
  • delay(1000); // maybe 750ms is enough, maybe not*
  • // we might do a ds.depower() here, but the reset will take care of it.*
  • present = ds.reset();*
  • ds.select(addr);*
  • ds.write(0xBE); // Read Scratchpad*
  • // Serial.print(" Data = ");*
  • // Serial.print(present, HEX);*
  • // Serial.print(" ");*
  • for ( i = 0; i < 9; i++) { // we need 9 bytes*
    _ data = ds.read();_
    _ // Serial.print(data*, HEX);
    // Serial.print(" ");
    }
    // Serial.print(" CRC=");
    // Serial.print(OneWire::crc8(data, 8), HEX);
    // Serial.println();
    // Convert the data to actual temperature*
    * // because the result is a 16 bit signed integer, it should*
    * // be stored to an "int16_t" type, which is always 16 bits*
    * // even when compiled on a 32 bit processor._
    int16_t raw = (data[1] << 8) | data[0];
    if (type_s) {
    _ raw = raw << 3; // 9 bit resolution default*
    * if (data[7] == 0x10) {
    // "count remain" gives full 12 bit resolution*
    * raw = (raw & 0xFFF0) + 12 - data[6];
    }
    } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them*
    * if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms*
    * else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms*
    * else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms*
    * //// default is 12 bit resolution, 750 ms conversion time*
    * }
    celsius = (float)raw / 16.0;
    // fahrenheit = celsius * 1.8 + 32.0;
    return celsius;
    }*_

Your code does not compile. There is one too many closing braces in your loop function.

....and way too many italics.

Sorry been working on it. Now is fine.

//
#include <UTFT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <dht.h>

#define DHT11_PIN 7     // DHT11 data pin

#define heat_pin 3

OneWire  ds(2);

dht DHT;

extern uint8_t SmallFont[]; // Declare which fonts we will be using

// Usage: myGLCD(<model code>, SDA, SCL, CS, RST[, RS]);

// connection of the TFT pins to ARDUINO pins
// GND
// BL +3.3
// VCC
// CLK 13
// DIN 11
// DC 9
// CS 10
// RST 8


UTFT myGLCD(ST7735, 11, 13, 10, 8, 9);

// used variables

String inputString = "";
bool stringComplete = false;

int delta = 2; // temperature delta mirrow vs. dew point in  °C

int scope = 0; // index for the DS18x20 (mirror/scope temperature

int chk = 0; // for the DHT11 requests

float temperatureAir, humidity, temperatureScope, dewPoint;

// heating on/off
int heating_on = 0;


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

  pinMode(heat_pin, OUTPUT);

  // Setup the LCD
  myGLCD.InitLCD();
  myGLCD.setFont(SmallFont); //SmallFont

  int buf[158];
  int x, x2;
  int y, y2;
  int r;

  //Clear the screen and draw
  myGLCD.clrScr();
  delay(100);
  myGLCD.setColor(30, 30, 30);
  myGLCD.fillRect(0, 0, 159, 13);
  myGLCD.setColor(30, 30, 30);
  myGLCD.fillRect(0, 114, 159, 127);
  myGLCD.setColor(0, 0, 255);
  myGLCD.setBackColor(30, 30, 30);
  myGLCD.print("Dew Controller v0.1", CENTER, 1);
  myGLCD.setBackColor(30, 30, 30);

  myGLCD.setColor(0, 0, 255);
}

void check_heating( float TS, float TA) {
  //  127 = 50%
  //  191 = 75%
  //  255 = 100&
  float diff = TS - (TA + delta);

  if (TS < (TA + delta)) {

    if (diff < -2.00) {
      analogWrite(heat_pin, 255);
    }

    else  if (diff < -1.25) {
      analogWrite(heat_pin, 200);
    }
    else if (diff < -0.75) {
      analogWrite(heat_pin, 170);
    }
    else if (diff < -0.45) {
      analogWrite(heat_pin, 65);

    }
    else {
      analogWrite(heat_pin, 35);
    }

    heating_on = 1;


  } else if (diff < 0.15) {
    analogWrite(heat_pin, 20);
    heating_on = 1;
  }

  else {

    analogWrite(heat_pin, LOW);
    heating_on = 0;

  }

}


double calcDewPoint(double celsius, double humidity)
{
  double RATIO = 373.15 / (273.15 + celsius);
  double RHS = -7.90298 * (RATIO - 1);
  RHS += 5.02808 * log10(RATIO);
  RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO ))) - 1) ;
  RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
  RHS += log10(1013.246);

  // factor -3 is to adjust units - Vapor Pressure SVP * humidity
  double VP = pow(10, RHS - 3) * humidity;

  // (2) DEWPOINT = F(Vapor Pressure)
  double T = log(VP / 0.61078); // temp var
  return (241.88 * T) / (17.558 - T);
}


// Fields are in order:
// temperature ch 1
// temperature ch 2
// temperature ambient
// relative humidity
// dew point
// output ch 1
// output ch 2
// output ch 3
// calibration ch 1
// calibration ch 2
// calibration ambient
// threshold ch 1
// threshold ch 2
// auto mode
// outputs ch 2 & 3 linked
// aggressivity

// "##" + String(temperatureScope) + "/11.11/" + String(temperatureAir) + "/" + String(humidity) + "/" + String(dewPoint) + "/0/0/0/0/0/0/2/2/0/0/4**"

void loop()
{

  chk = DHT.read11(DHT11_PIN);

  temperatureAir = DHT.temperature;
  humidity = DHT.humidity;

  temperatureScope = getTemperature();

  dewPoint = calcDewPoint(temperatureAir, humidity) ;

  myGLCD.setColor(0, 0, 0);
  myGLCD.fillRect(90, 14, 159, 100);

  myGLCD.setBackColor(0, 0, 0);
  myGLCD.setColor(0, 0, 255);

  myGLCD.print("Temperatur: ", 5, 15);
  myGLCD.print(String(temperatureAir) + "$C", RIGHT, 15);

  myGLCD.print("Feuchte: ", 5, 27);
  myGLCD.print(String(humidity) + " %", RIGHT, 27);

  myGLCD.print("Taupunkt: ", 5, 39);
  myGLCD.print(String(dewPoint) + "$C", RIGHT, 39);

  myGLCD.print("Teleskop: ", 5, 51);
  myGLCD.print(String(temperatureScope) + "$C", RIGHT, 51);

  myGLCD.print("Delta: ", 5, 63);

  if ((temperatureScope - dewPoint) < 0 ) {
    myGLCD.setBackColor(0, 0, 255);
    myGLCD.setColor(255, 255, 255);
  }
  else {
    myGLCD.setBackColor(0, 0, 0);
    myGLCD.setColor(0, 0, 255);
  }

  myGLCD.print(String(temperatureScope - dewPoint) + "$C", RIGHT, 63);

  myGLCD.setBackColor(0, 0, 0);
  myGLCD.setColor(0, 0, 255);

  myGLCD.print("Heizung: ", 5, 87);

  check_heating(temperatureScope, dewPoint); //ändern in Dew point

  if (heating_on == 0) myGLCD.print("off  ", RIGHT, 87);
  if (heating_on == 1) myGLCD.print(" on  ", RIGHT, 87);

  if (stringComplete) {
    Serial.println("##" + String(temperatureScope) + "/11.11/" + String(temperatureAir) + "/" + String(humidity) + "/" + String(dewPoint) + "/0/0/0/0/0/0/2/2/0/0/4**");
    // clear the string:
    inputString = "";
    stringComplete = false;
  }


delay(1000);
}


void serialEvent()
{
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    if (inputString.length() == 6) {
      stringComplete = true;
    }
  }
}


float getTemperature() {

  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;

  if ( !ds.search(addr)) {
    //    Serial.println("No more addresses.");
    //    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      //      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      //      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      //      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      //     Serial.println("Device is not a DS18x20 family device.");
      return;
  }

  delay(300);

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end

  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  present = ds.reset();
  ds.select(addr);
  ds.write(0xBE);         // Read Scratchpad

  //  Serial.print("  Data = ");
  //  Serial.print(present, HEX);
  //  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    //    Serial.print(data[i], HEX);
    //    Serial.print(" ");
  }
  //  Serial.print(" CRC=");
  //  Serial.print(OneWire::crc8(data, 8), HEX);
  // Serial.println();

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  // fahrenheit = celsius * 1.8 + 32.0;

  return celsius;
}

Dew_controller_02.ino (7.73 KB)

astroalex:
// All commands are exactly 6 bytes, no start/end markers
UDP_CMD_LEN 6

// Responses also include "\n\r"

You can use the \n\r as the end-marker. Try the second example in Serial Input Basics

...R

Thank you Robin, will go trough your tutorial.

But the in string sent from the software ("SWHOIS" and "SGETAL") are sent without \n\r
only the out responses from the arduino are with \n\r.

Tried to make it work with

if (inputString.length() == 6) stringComplete = true;

but this works only one time.

astroalex:
But the in string sent from the software ("SWHOIS" and "SGETAL") are sent without \n\r
only the out responses from the arduino are with \n\r.

Two thoughts ...

I presume nothing is sent to the Arduino unless it sends a request message first - if that's wrong ignore the rest of this and tell us in detail (in English rather than code) how the system works.

If the response comes quickly after a request then just send a request, wait a second and the reponse will have arrived.

Or

Immediately before you send a request empty the serial input buffer with

while (Serial.available() > 0) {
   byte dumpThisByte = Serial.read();
}

then send the request, following which check for when Serial.available() >= 6

...R