declaring signed integer variable

Dear all,

Here is example code for modbus slave from modbus library. Here variable are declared as signed int . My sensor value read negative value. SO i wanted to declared the variable as signed int . How can i store variable as signed integer of 16 bit

How can declare below has signed int

// data array for modbus network sharing
uint16_t au16data[9];

#include <ModbusRtu.h>
#define ID   1

Modbus slave(ID, 0, 0); // this is slave ID and RS-232 or USB-FTDI
boolean led;
int8_t state = 0;
unsigned long tempus;

// data array for modbus network sharing
uint16_t au16data[9];


void setup() {
  io_setup(); // I/O settings

  // start communication
  slave.begin( 19200 );
  tempus = millis() + 100;
  digitalWrite(13, HIGH );
}

void loop() {
  // poll messages
  // blink led pin on each valid message
  state = slave.poll( au16data, 9 );

  if (state > 4) {
    tempus = millis() + 50;
    digitalWrite(13, HIGH);
  }
  if (millis() > tempus) digitalWrite(13, LOW );

  // link the Arduino pins to the Modbus array
  io_poll();
} 

void io_setup() {
  // define i/o
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(13, OUTPUT);

  digitalWrite(6, LOW );
  digitalWrite(7, LOW );
  digitalWrite(8, LOW );
  digitalWrite(9, LOW );
  digitalWrite(13, HIGH ); // this is for the UNO led pin
  analogWrite(10, 0 );
  analogWrite(11, 0 );
}

/**
 *  Link between the Arduino pins and the Modbus array
 */
void io_poll() {
  // get digital inputs -> au16data[0]
  bitWrite( au16data[0], 0, digitalRead( 2 ));
  bitWrite( au16data[0], 1, digitalRead( 3 ));
  bitWrite( au16data[0], 2, digitalRead( 4 ));
  bitWrite( au16data[0], 3, digitalRead( 5 ));

  // set digital outputs -> au16data[1]
  digitalWrite( 6, bitRead( au16data[1], 0 ));
  digitalWrite( 7, bitRead( au16data[1], 1 ));
  digitalWrite( 8, bitRead( au16data[1], 2 ));
  digitalWrite( 9, bitRead( au16data[1], 3 ));

  // set analog outputs
  analogWrite( 10, au16data[2] );
  analogWrite( 11, au16data[3] );

  // read analog inputs
  au16data[4] = analogRead( 0 );
  au16data[5] = analogRead( 1 );

  // diagnose communication
  au16data[6] = slave.getInCnt();
  au16data[7] = slave.getOutCnt();
  au16data[8] = slave.getErrCnt();
}
int someVariableName = someValue;
//Yes it's really this simple

It seems we are going around in circles with your code for Modbus in various threads Ajit.

Recall Modbus holding registers are type agnostic, and are generally just encoded as 16bit data.
You store your data in these holding registers and you get data out the other end, remembering to bring it back into the same data type as you had it before storing.

So, if you have sensor data that needs to be a signed integer, then simply place this data into the Modbus mapping register array, which is an array of uint16_t. Then when you get the data back at another Modbus device, you simply re-cast the data from the uint16_t array back into the type you need.

It is the same with floating point data on Modbus, where I mentioned to you previously to map 2 of the Modbus mapping registers to make 32 bits which can then be re-cast back as 32 bit floating point.

Keep the Modbus mapping registers as 16 bit unsigned.
I hope you can understand this better now.


Paul

Dear sir,
Here simple example i am putting.

Variable declare as Unsigned Integer ; the value i am getting are Converted value

#include <ModbusRtu.h>

// data array for modbus network sharing
uint16_t au16data[16] = {
  3, 1415, 9265, 4, 2, 7182, 28182, 8, -2, -5, -6, 0, 0, 0, 1, -1 };

Modbus slave(1,0,0); // this is slave @1 and RS-232 or USB-FTDI

void setup() {
  slave.begin( 9600 ); 
}

void loop() {
  slave.poll( au16data, 16 );
}

if change the line to uint16_t to int . below error will display. Is there way to read it.

Int au16data[16] = {
  3, 1415, 9265, 4, 2, 7182, 28182, 8, -2, -5, -6, 0, 0, 0, 1, -1 };

That means i need to change libary to make read signed value. The value is proper when i converted to HEX & match with -ve value type in DEC.

Ok, I'll say it again,

The Modbus data protocol does not specify a data type for holding registers, it is simply stored as 16 bit unsigned data.

This will mean programs like QModbus or what ever you are using will also only be able to show you this data as unsigned 16 bit data.

You can see that 65534 is actually -2 and that 65531 is actually -5.
Why is this so, I hear you ask?
Well, if you don't know, you need to learn up on basic signed integer maths.

In 16 bits of data, you can go from 0 to 66535, or (2^16) - 1, correct?
So, if you have a value that is a data type of signed integer with a value of -2, then when you place this into a 16 bit holding register, which, again, I'll tell you is unsigned, will appear as 65534.

65535 already is -1, so the next one down is 65534, which is -2, and so on and so on.

Again, Qmodbus has no idea what the original data type might have been.
It may be signed int or unsigned int or it may be packed bits or it may be two bytes swapped around.

It will be up to your program at the other end, the Qmodbus end to re-intepret the data how initially intended it.

So, if it were just a packed word of bits, then your program at the destination will need to unpack that 16 bit word back into its meaningful bits.


Paul

Of coarse you will get errors like what you are getting, you are trying to place signed constants into an unsigned integer. You will get a compile error.

What you need to do is cast your sensor data that is not already unsigned integer to unsigned integer.
Par example;

au16data[4] = (uint16_t)analogRead(0);

Even though analogRead can only ever return a positive int anyhow, but just to show you how you can re-cast in this maner.


Paul

AMPS_N wrote:

That means i need to change libary to make read signed value

No, please do not touch the library, it is simply that you do not understand how to deal with the data you have in the way you need to.

The modbus library is well thought out and written by someone who understands the Modbus protocol and also who understands data types. Leave the library un-modified.


Paul

Hi,

Here i have attached sensor specification. I would like to read the negative value here. The sensor reference is 2.5v.I am facing problem reading the -ve value.

As you said if you type cast your not already unsigned integer to unsigned integer. The people user end may not understand the value.
for example

-2 equivalent in HEX is FFFE where last bits indicate -ve value
-2 =65534 in unsigned format when you type cast in mod bus
Which cant be in format of readable to user.
I need to unpack the into readble format ? right

What you need to do is cast your sensor data that is not already unsigned integer to unsigned integer.

2_1_HA025T01-UR_Rev-01.pdf (348 KB)

It's the first bit which shows that it is a negative value.

First, I looked at your sensor specifications last week and let you know in your other thread on Modbus that this sensor will only give you the equivelent of 255bits of resolution for the full scale range of the sensor into the 5.0 Volt analog input of your Arduino.

I hope you will understand this and I asked you if that was going to be an issue for you, but you did not respond or make any comment about this issue with this sensor you have selected.

Next,

I would like to read the negative value here

So, I understand you wish to be able to read current flow in the sensor in both directions, can you confirm this exactly please?
Will or can the current flow you are wanting to measure flow in both directions?

If your ansew is ‘no’, then you do not need to do anything with readings from the sensor in this part of its range.
As I said in my personal reply message to you, you need to effectively clamp this part out using the example I gave you.

I will write a little story, maybe it will help you undertsand Modbus better as it appears to me you are very much caught up in mind how it works.

Imagine Modbus to be a postman, who flys a nice big aeroplane 8)
I am here in France and I want to send some data to South America.

The data will be the temperature, which is -2˚C at my home in southern France.
Now, when I look at how the number -2 looks inside a signed integer inside my computer, it looks like all of these;

Decimal -2 = int16_t 65534
Decimal -2 = Hexidecimal FFFE
Decimal -2 = Binary 1111111111111110

The format the postman takes is only numbers between 0 and 65535.
Well, luckily for me, my number of 65534 is within the accepted range and the postman can take my number, simply by casting my signed int to unsigned int.

The actual data does not change, only we need to do the type cast to fullfil the requirements of the postman.

I give it to him as a uint16_t, which is what he accepts, again, the actual data bit stay the same.

So, the postman takes my data as uint16_t, and jumps into his big plane and flys all the way to South America. Landing there, he take this data to the end person there.

The person there, sees the data and says, ‘oh, this makes no sense as is, but I know how to intepret this data’. He thanks the postman and the postman leaves.

He then takes the data and as he already knows beforehand that he must intepret this data not as uint16_t, but as int16_t.

So, plugging this number back into his computer, the (uint16_t)(65534) he re-casts this to (int16_t)(65534).

And guess what happens, yes, he then will see a -2 pop up on the screen.

Le Fin. :slight_smile:

So, like I have mentioned a few times already, you need to have both ends understand the source data type, with the destination also intepreting the data the very same way.


Paul

I have kept my code as it . I never done conversion here.

Yes i dont wanted to read negetive value of current. But i would like to Know How can read those value in sensor side. I.e voltage 1.875~2.5v equal to -25Ato 0A.

I have downloaded the Modbus Poll software. Here i just chosen the right address & right holding register , iD. select ok.

I found that Qmodbus reading value in format of Uint16_t of negative being displayed as actual negative values.

But i found lot of time it gives CRC Error. Error Count keep increment. Once i disconnect & connect back start working properly.

It's the first bit which shows that it is a negative value.

Really? Are you calling the first bit bit0 or are you referring the the first bit reading from left to right (i.e., bit7)?

Yes i dont wanted to read negetive value of current. But i would like to Know How can read those value in sensor side. I.e voltage 1.875~2.5v equal to -25Ato 0A.

Ajit, either you do allow for measuring bi-directional current flow in the hall effect current sensor and use it, or you don’t. You need to make up your mind, what are your requirements exactly?

You found QModbus reads value in format of uint16_t, no you didn’t, I told you already a few times that QModbus will only display as 16 bits unsigned integer.

Ok, I’ve modified the porgram to read the current sensors as bi-directional with the data being stored in the Modbus holding registers as scaled -250 Amps to + 250 Amps. You need to devide by 10 at your display point so you can get one decimal point of precision, par example, Modbus data is 225, then you display this as 255÷10 which is 22.5, which will be 22.5Amps.

/*---------------------------------------------------------------------------------
 * AMPS-N.cpp
 *
 * Program to read various sensors and make this available to a Modbus RTU master:
 *
 * Uses Modbus library
 * https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino
 *
 * Known issues with modbus library:
 * It is not compatible with ARDUINO LEONARDO and not tested under ARDUINO DUE and newer boards:
 *
 * Note:
 * Modbus library header file line 137 has maximum size for the communication buffer in bytes MAX_BUFFER = 64
 *
 * From AMPS-N first post on Arduino forum thread;
 * http://forum.arduino.cc/index.php?topic=295580.0
 *
 * he states he has the following sensor arrangement:
 * 'i have totally 25 current parameter ; 1 voltage ; 1 temprature sensor'
 *
 * Sensors are:
 *     8 'current' sensors on Arduino analog pin A0 via MUX chip A:
 *     8 'current' sensors on Arduino analog pin A1 via MUX chip B:
 *     8 'current' sensors on Arduino analog pin A2 via MUX chip C:
 *     1 'current' sensor on Arduino analog pin A3:
 *     1 'voltage' sensor on Arduino analog pin A4:
 *     1 temperature sensor on Arduino analog pin A5:
 *
 * Modbus address 1 and at speed 9600
 */

//#include "AMPS_N.h"
#include "Arduino.h"
#include <ModbusRtu.h>

#define modbus_ID 1                    // modbus slave ID:
#define TXEN 0                         // assign the Arduino pin that must be connected to RE-DE RS485 transceiver, 0 for disable:
#define ZERO_OFFSET 512                // sensor zero offset which will be Vcc/2 which is 2.5Volts or 512 ADc counts:

#define PORTD_MASK B00111000           // define our MUX bits, pins 3,4 and 5 which are on PORTD:
#define sensor_25_pin A3               // pin for 'current' sensor number 25:
#define sensor_volts_pin A4            // pin for one and only volatge sensor, scale is ....:
#define temp_sensor_pin A5             // pin for temperature sensor, scale is ....:

int8_t mb_retVal = 0;                  // must be the state of the Modbus poll result:
uint16_t mb_reg[30];                   // array of uint16 to hold values to be sent out by Modbus:

uint32_t  last_loop = 0;               // current value of loop timer:
const uint32_t period_loop = 1000;     // loop timer preset value, every 1 second:

//Modbus slave(modbus_ID, 0, TXEN);      // Modbus ID (master = 0, slave = 1..247), serial port number, mode = 0 for RS-232 or USB-FTDI mode > 0 RS-485 Tx enable pin:

/*---------------------------------------------------------------------------------
 * void read_sensors()
 * sensor setup is as follows:
 *     8 current based sensors connected to analog A0 via MUX chip A:
 *     8 current based sensors connected to analog A1 via MUX chip B:
 *     8 current based sensors connected to analog A2 via MUX chip C:
 *     1 current based sensor connected to analog A3:
 *     1 voltage based sensor connected to analog A4:
 *     1 temperature based sensor connected to analog A5:
 *
 * all sensors connected to MUX chips are read by looping through MUX channels
 *
 * each 'current' sensor has a range of -25A to +25A over a voltage range of 1.875v to 3.125v
 * at 0A the sensor centres around 2.5v which will be between 511 and 513 ADC counts, dependent on device noise and offset:
 *
 * we are interested in reading the bi-directional flow of current, so, -25Amps to +25Amps
 * we scale up the value of current by a factor of 10 to give us at least one decimal place in the uint16_t:
 * thus a value of 250, will in fact be 25.0Amps, a value of 127 will represent 12.7Amps at the end display point:
 */
void read_sensors() {
  int16_t analog_chan_0;
  int16_t analog_chan_1;
  int16_t analog_chan_2;

  for(uint8_t chan_count = 0; chan_count < 8; chan_count++)
  {
    PORTD = PORTD | ((chan_count << 3) & PORTD_MASK);                      // set MUX channel bits by direct port manipulation with safety mask:
    delay(2);                                                              // a short delay to let the MUX settle before reading analog channel:

    analog_chan_0 = (int16_t)((analogRead(A0) - ZERO_OFFSET) / 0.512);     // sample analog A0 and scale to -250Amps to 250 Amps:
    analog_chan_1 = (int16_t)((analogRead(A1) - ZERO_OFFSET) / 0.512);     // sample analog A1 and scale to -250Amps to 250 Amps:
    analog_chan_2 = (int16_t)((analogRead(A2) - ZERO_OFFSET) / 0.512);     // sample analog A2 and scale to -250Amps to 250 Amps:

    mb_reg[chan_count] = (uint16_t)analog_chan_0;                          // re-cast and store in Modbus register holding array:
    mb_reg[chan_count + 8] = (uint16_t)analog_chan_1;                      // re-cast and store in Modbus register holding array:
    mb_reg[chan_count + 16] = (uint16_t)analog_chan_2;                     // re-cast and store in Modbus register holding array:
  }

  mb_reg[24] = (uint16_t)((analogRead(sensor_25_pin) - ZERO_OFFSET) / 0.512);// sample and remove offset and scale to -250Amps to 250 Amps:
  mb_reg[25] = analogRead(sensor_volts_pin);                               // sample as voltage sensor, need scaling data:
  mb_reg[26] = analogRead(temp_sensor_pin);                                // sample as temperature sesnor, needs scaling:
}


/*---------------------------------------------------------------------------------
 * void setup()
 * ah, at last, this is where we initailise a few of our favorite things:
 *
 * If working on an Arduino with only one hardware serial port,
 * then only select to use one port, either for serial printing or for Modbus.
 *
 */
void setup() {
  DDRD = DDRD | PORTD_MASK;                                                // set pins 3,4 and 5 as outputs for MUX channel select:
  slave.begin(9600);                                                       // set Modbus slave port speed:
//  Serial.begin(9600);                                                      // this will be the default async serial port:

  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(sensor_25_pin, INPUT);
  pinMode(sensor_volts_pin, INPUT);
  pinMode(temp_sensor_pin, INPUT);
}

/*---------------------------------------------------------------------------------
 * void loop()
 * this is mission control:
 *
 * we call sensor reading and optional serial print routines on a time base, every 1000mSec:
 *
 * we call the Modbus slave poll function here to check for any queries from a Modbus master:
 * mb_retVal is 0 if no query
 * mb_retVal is 1..4 if communication error
 * mb_retVal is > 4 if correct query processed
 */
void loop() {
  if (millis() - last_loop >= period_loop)                                 // ye good old delay without delay:
  {
      read_sensors();
      last_loop = millis();                                                // reset our loop timer value:
  }

//  mb_reg[27] = slave.getInCnt();                                           // input messages counter value:
//  mb_reg[28] = slave.getOutCnt();                                          // transmitted messages counter value:
//  mb_reg[29] = slave.getErrCnt();                                          // errors counter value:

  mb_retVal = slave.poll(mb_reg, 30);                                      // cyclic slave poll the modbus channel if there is any incoming query:
}

Paul