DS18B20 Output as signed hex

Folks,

Any idea how I can get the output temperature of this device as a Signed Hex number? I can do serial.print(Temp, Hex) but I don't know how to print Signed hex...

Thanks in advance,
Craig

Usually hex is used to get a more-readable version of the binary bits. Something like 0xFF can be interpreted as a negative number (-128) but you'd never write a minus sign in front of the hex. "-FF" makes no sense.

What is this for?

If you know the hex number is a signed (2's complement) number then if the most significant digit is 8 or greater (8,9,A,B,C.D,E,F), it's a negative number.

I didn't know that, but I bet it doesn't explain what this is for.

It's an electric stepper focuser for a telescope but there is also an option to add a temperature sensor to allow automatic refocusing when the temperature drops by a set amount. I am using the protocol on this page (About halfway down) http://www.indilib.org/media/kunena/attachments/1/HighResSteppermotor107.pdf
It mentions this is a signed hex number and I have output the temp using serial.print(Temperature, HEX) but the reading is around double what the actual temperature is and I assume this is due to it being unsigned but I have no idea how to convert a number to singed HEX and print it to the serial line - I really am a beginner with Arduino and programming!

MorganS:
Usually hex is used to get a more-readable version of the binary bits. Something like 0xFF can be interpreted as a negative number (-128) but you'd never write a minus sign in front of the hex. "-FF" makes no sense.

What is this for?

Makes perfect sense, its a negative value in base 16.

  if (val < 0)
  {
    Serial.print ('-') ;
    val = abs(val) ;
  }
  Serial.println (val, HEX) ;

Sorry, I still dont understand, are you saying I dont need to anything as the temperature is already stored as a signed hex value?

Serial.println (val, HEX) ;

The application I am using this in seems to expect the temperature to be in 0.5 degree increments, I suppose if I divide by 2 prior to outputting the value this may work?

I think they are asking for a 2's complement value in raw hex.

ie FFF6 = -10, 0030 = 48

Just use Serial.print (temp, HEX)

The application I am using this in seems to expect the temperature to be in 0.5 degree increments, I suppose if I divide by 2 prior to outputting the value this may work?

The device is made in the US, they don't know about modern units like centigrade.

@MarkT
I like you used "modern" with centigrade. :slight_smile:
BTW: Since 1744 by Carl Linné.

Why do you need to send the temperature at all? The device reads the temperature and sends it as a so-called "signed hexadecimal" number. I would have thought you would be trying to read these four digits and convert them to decimal.
BTW. Using Serial.print(temp,HEX) won't help anyway because the datasheet indicates that the temperature is always 4 hex digits. You can't tell Serial.print to print exactly four digits with leading zeros if necessary. You'd have to write your own function or use something like:

 char buffer[6];
  sprintf(buffer,"%04X",temp);
  Serial.print(buffer);

The device appears to use the DS18B20 with 12-bit precision (because "the conversion
process takes a maximum of 750 milliseconds"). It seems that all they are doing is reading the signed 16-bit temperature from the DS18B20 and sending it as 4 hex digits.

Pete

Ok, Following from my previous posts I now find that when I connect up the DS18B20 to an Arduino on its own I get a correct reading, when I connect it via the same digital pin (Pin 2) on to my L293D Board, and I have checked and Pin 2 is unused on these boards, it gives an incorrect reading. I have confirmed this a few times by swapping the same DS18B20 between the Motor board and just the Arduino and I have checked how I have connected it up but cant see anything wrong either. I have Data to Digital Pin2, the +5v and GND Lines Connected together to GND and a Pull up resistor between 5v and Digital Pin2.
I am pulling my hair out now as I cannot for the life of me figure this out!

Ok, I have a L293D board on the back of my Arduino, I have a stepper motor and that all works fine, this project is to control a telescope focuser. I want to add a temperature reading since it is already build into the sketch but is hardcoded as a dummy value. I connect my DS1820B to Digital Pin 2 as I know it is unsed, I use a pull up resistor and connect the data line to also +5v. I connect the other lines to +5v and GND.
If I upload the basic DS1820B test sketch I get a proper reading of temperature:

/********************************************************************/
// First we include the libraries
#include <OneWire.h> 
#include <DallasTemperature.h>
/********************************************************************/
// Data wire is plugged into pin 2 on the Arduino 
#define ONE_WIRE_BUS 2 
/********************************************************************/
// Setup a oneWire instance to communicate with any OneWire devices  
// (not just Maxim/Dallas temperature ICs) 
OneWire oneWire(ONE_WIRE_BUS); 
/********************************************************************/
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
/********************************************************************/ 
void setup(void) 
{ 
 // start serial port 
 Serial.begin(9600); 
 Serial.println("Dallas Temperature IC Control Library Demo"); 
 // Start up the library 
 sensors.begin(); 
} 
void loop(void) 
{ 
 // call sensors.requestTemperatures() to issue a global temperature 
 // request to all devices on the bus 
/********************************************************************/
 Serial.print(" Requesting temperatures..."); 
 sensors.requestTemperatures(); // Send the command to get temperature readings 
 Serial.println("DONE"); 
/********************************************************************/
 Serial.print("Temperature is: "); 
 Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"?  
   // You can have more than one DS18B20 on the same bus.  
   // 0 refers to the first IC on the wire 
   delay(1000); 
  
}

Output on the Serial Monitor line is:
Requesting temperatures...DONE
Temperature is: 18.69

If I now upload the focuser sketch

// Moonlite-compatible stepper controller
//
// Uses AccelStepper (http://www.airspayce.com/mikem/arduino/AccelStepper/)
// Uses AFMotor and the Adafruit v1.2 Motor Shield https://learn.adafruit.com/adafruit-motor-shield
//
// Requires a 10uf - 100uf capacitor between RESET and GND on the motor shield; this prevents the
// Arduino from resetting on connect (via DTR going low).  Without the capacitor, this sketch works
// with the stand-alone Moonlite control program (non-ASCOM) but the ASCOM driver does not detect it.
// Adding the capacitor allows the Arduino to respond quickly enough to the ASCOM driver probe
//
// orly.andico@gmail.com, 13 April 2014


#include <AccelStepper.h>
#include <AFMotor.h>
#include <OneWire.h> 
#include <DallasTemperature.h>
#include <Math.h>

#define ONE_WIRE_BUS 2 
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensors(&oneWire);


// maximum speed is 160pps which should be OK for most
// tin can steppers
#define MAXSPEED 100
#define SPEEDMULT 3

AF_Stepper motor1(300, 1);

void forwardstep() {  
  motor1.onestep(BACKWARD, DOUBLE);
}

void backwardstep() {  
  motor1.onestep(FORWARD, DOUBLE);
}

AccelStepper stepper(forwardstep, backwardstep);

#define MAXCOMMAND 8

char inChar;
char cmd[MAXCOMMAND];
char param[MAXCOMMAND];
char line[MAXCOMMAND];
long pos;
int isRunning = 0;
int speed = 32;
int eoc = 0;
int idx = 0;
long millisLastMove = 0;

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

  // we ignore the Moonlite speed setting because Accelstepper implements
  // ramping, making variable speeds un-necessary
  stepper.setSpeed(MAXSPEED);
  stepper.setMaxSpeed(MAXSPEED);
  stepper.setAcceleration(10);
  stepper.enableOutputs();
  memset(line, 0, MAXCOMMAND);
  millisLastMove = millis();
  
  sensors.begin(); 
}



void loop(){
  // run the stepper if there's no pending command and if there are pending movements
  if (!Serial.available())
  {
    if (isRunning) {
      stepper.run();
      millisLastMove = millis();
    } 
    else {
      // reported on INDI forum that some steppers "stutter" if disableOutputs is done repeatedly
      // over a short interval; hence we only disable the outputs and release the motor some seconds
      // after movement has stopped
      if ((millis() - millisLastMove) > 15000) {
        stepper.disableOutputs();
        motor1.release();
      }
    }

    if (stepper.distanceToGo() == 0) {
      stepper.run();
      isRunning = 0;
    }
  } 
  else {

    // read the command until the terminating # character
    while (Serial.available() && !eoc) {
      inChar = Serial.read();
      if (inChar != '#' && inChar != ':') {
        line[idx++] = inChar;
        if (idx >= MAXCOMMAND) {
          idx = MAXCOMMAND - 1;
        }
      } 
      else {
        if (inChar == '#') {
          eoc = 1;
        }
      }
    }
  } // end if (!Serial.available())

  // process the command we got
  if (eoc) {
    memset(cmd, 0, MAXCOMMAND);
    memset(param, 0, MAXCOMMAND);

    int len = strlen(line);
    if (len >= 2) {
      strncpy(cmd, line, 2);
    }

    if (len > 2) {
      strncpy(param, line + 2, len - 2);
    }

    memset(line, 0, MAXCOMMAND);
    eoc = 0;
    idx = 0;

    // the stand-alone program sends :C# :GB# on startup
    // :C# is a temperature conversion, doesn't require any response

    // LED backlight value, always return "00"
    if (!strcasecmp(cmd, "GB")) {
      Serial.print("00#");
    }

    // home the motor, hard-coded, ignore parameters since we only have one motor
    if (!strcasecmp(cmd, "PH")) { 
      stepper.setCurrentPosition(8000);
      stepper.moveTo(0);
      isRunning = 1;
    }

    // firmware value, always return "10"
    if (!strcasecmp(cmd, "GV")) {
      Serial.print("10#");
    }

    // get the current motor position
    if (!strcasecmp(cmd, "GP")) {
      pos = stepper.currentPosition();
      char tempString[6];
      sprintf(tempString, "%04X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }

    // get the new motor position (target)
    if (!strcasecmp(cmd, "GN")) {
      pos = stepper.targetPosition();
      char tempString[6];
      sprintf(tempString, "%04X", pos);
      Serial.print(tempString);
      Serial.print("#");
    }

    // get the current temperature, hard-coded
    if (!strcasecmp(cmd, "GT")) {
      //Serial.print("20#");      
    Serial.print(sensors.getTempCByIndex(0)); 
   
      
    }

    // get the temperature coefficient, hard-coded
    if (!strcasecmp(cmd, "GC")) {
      Serial.print("02#");
    }

    // get the current motor speed, only values of 02, 04, 08, 10, 20
    if (!strcasecmp(cmd, "GD")) {
      char tempString[6];
      sprintf(tempString, "%02X", speed);
      Serial.print(tempString);
      Serial.print("#");
    }

    // set speed, only acceptable values are 02, 04, 08, 10, 20
    if (!strcasecmp(cmd, "SD")) {
      speed = hexstr2long(param);

      // we ignore the Moonlite speed setting because Accelstepper implements
      // ramping, making variable speeds un-necessary

      // stepper.setSpeed(speed * SPEEDMULT);
      // stepper.setMaxSpeed(speed * SPEEDMULT);
      stepper.setSpeed(MAXSPEED);
      stepper.setMaxSpeed(MAXSPEED);
    }

    // whether half-step is enabled or not, always return "00"
    if (!strcasecmp(cmd, "GH")) {
      Serial.print("00#");
    }

    // motor is moving - 01 if moving, 00 otherwise
    if (!strcasecmp(cmd, "GI")) {
      if (abs(stepper.distanceToGo()) > 0) {
        Serial.print("01#");
      } 
      else {
        Serial.print("00#");
      }
    }

    // set current motor position
    if (!strcasecmp(cmd, "SP")) {
      pos = hexstr2long(param);
      stepper.setCurrentPosition(pos);
    }

    // set new motor position
    if (!strcasecmp(cmd, "SN")) {
      pos = hexstr2long(param);
      stepper.moveTo(pos);
    }


    // initiate a move
    if (!strcasecmp(cmd, "FG")) {
      isRunning = 1;
      stepper.enableOutputs();
    }

    // stop a move
    if (!strcasecmp(cmd, "FQ")) {
      isRunning = 0;
      stepper.moveTo(stepper.currentPosition());
      stepper.run();
    }
  }
} // end loop

long hexstr2long(char *line) {
  long ret = 0;

  ret = strtol(line, NULL, 16);
  return (ret);
}

And enter the GT# command I get the following output:
85.00

Why is this different?

Can this be removed as I have posted a better explanation of the issue in the programming section

Bad idea to make a second thread for the same problem.
Now you have to inform us (code) all over again.

https://forum.arduino.cc/index.php?topic=499229.0

Did you try a different pin for the DS18B20.
Remember that the analogue pins can also be used (as digital pins).
#define ONE_WIRE_BUS 2
could be
#define ONE_WIRE_BUS A0
or
#define ONE_WIRE_BUS 14
Leo..

This is the GT Command:

 // get the current temperature, hard-coded
    if (!strcasecmp(cmd, "GT")) {
      //Serial.print("20#");      
    Serial.print(sensors.getTempCByIndex(0));  
      
    }

blinky123:
Can this be removed as I have posted a better explanation of the issue in the programming section

As far as I can tell the three threads are all essentially the same topic so...

@blink123, please do not cross-post. Threads merged.