Go Down

Topic: MAP Function Not Working Correctly (Read 457 times) previous topic - next topic

Phil666

Hi guys

i am sure its something daft that i am missing.

i have a MODBUS network with 6 slaves, each slave has 5 analog inputs from various sensors.

i am using the MAP function for each sensor, but only two of them are returning a valid figure on the MASTER i can use?

for example outVal2 is returning a valid value between -40C & +60C and outVal3 is returning a value between 0 & 100% - as mapped.

But outVal0 & outVal1 is returning a strange value like 65565? when mapped between -100 & +100
and like wise with outVal4.

any ideas?

Code: [Select]

       // Analog Input #1 - Vacuum (Stbd/Port)  -100kpa to 100 kpa (-1000mbar to 1000mbar)
        inVal0 = analogRead(0);
    outVal0 = map(inVal0, 0, 1023, -100, 100);
    holdingRegs[0] = outVal0;

       // Analog Input #2 - Vacuum (Stbd/Port) -100kpa to 100 kpa (-1000mbar to 1000mbar)
        inVal1 = analogRead(1);
    outVal1 = map(inVal1, 0, 1023, -100, 100);
    holdingRegs[1] = outVal1;

       // Analog Input #3 - Temp (Stbd) **Mapped relevant to sensor -40C - +60C
         inVal2 = analogRead(2);
    outVal2 = map(inVal2, 0, 1023, -40, 60);
    holdingRegs[2] = outVal2;


       // Analog Input #4 - Humidity (Stbd) **Mapoed relevant to sensor - 0-100%
         inVal3 = analogRead(3);
    outVal3 = map(inVal3, 0, 1023, 0, 100);
    holdingRegs[3] = outVal3;


       // Analog Input #5 - Pressure Diff (Stbd) **Mapped relevant to sensor. -150pa - +150pa
         inVal4 = analogRead(4);
    outVal4 = map(inVal4, 0, 1023, -150, 150);
    holdingRegs[4] = outVal4;


Here is my complete code.

Code: [Select]


#include <SimpleModbusSlave.h>

int inVal0;
int outVal0;
int inVal1;
int outVal1;
int inVal2;
int outVal2;
int inVal3;
int outVal3;
int inVal4;
int outVal4;
int inVal5;
int outVal5;

enum
{     
  // just add or remove registers and your good to go...
  // The first register starts at address 0
  ADC0,     
  ADC1,       
  ADC2,
  ADC3,
  ADC4,
  ADC5, 
  LED_STATE,
  BUTTON_STATE,
  TOTAL_ERRORS,
  // leave this one
  TOTAL_REGS_SIZE
  // total number of registers for function 3 and 16 share the same register array
};

unsigned int holdingRegs[TOTAL_REGS_SIZE]; // function 3 and 16 register array

void setup()
{
  modbus_configure(9600, 2, 6, TOTAL_REGS_SIZE, 0);
//  Serial.begin(9600);
}

void loop()
{
  holdingRegs[TOTAL_ERRORS] = modbus_update(holdingRegs);
  {
       // Analog Input #1 - Vacuum (Stbd/Port)  -100kpa to 100 kpa (-1000mbar to 1000mbar)
        inVal0 = analogRead(0);
    outVal0 = map(inVal0, 0, 1023, -100, 100);
    holdingRegs[0] = outVal0;

       // Analog Input #2 - Vacuum (Stbd/Port) -100kpa to 100 kpa (-1000mbar to 1000mbar)
        inVal1 = analogRead(1);
    outVal1 = map(inVal1, 0, 1023, -100, 100);
    holdingRegs[1] = outVal1;

       // Analog Input #3 - Temp (Stbd) **Mapped relevant to sensor -40C - +60C
         inVal2 = analogRead(2);
    outVal2 = map(inVal2, 0, 1023, -40, 60);
    holdingRegs[2] = outVal2;


       // Analog Input #4 - Humidity (Stbd) **Mapoed relevant to sensor - 0-100%
         inVal3 = analogRead(3);
    outVal3 = map(inVal3, 0, 1023, 0, 100);
    holdingRegs[3] = outVal3;


       // Analog Input #5 - Pressure Diff (Stbd) **Mapped relevant to sensor. -150pa - +150pa
         inVal4 = analogRead(4);
    outVal4 = map(inVal4, 0, 1023, -150, 150);
    holdingRegs[4] = outVal4;


       // Analog Input #6 - Not Used
         inVal5 = analogRead(5);
    outVal5 = map(inVal5, 0, 1023, 1000, 2700);
    holdingRegs[5] = outVal5;
   
    delayMicroseconds(50);
   
//         Serial.print(outVal0);
//         Serial.println( "Input #1");
//         Serial.print(outVal1);
//         Serial.println( "Input #2");
//         Serial.print(outVal2);
//         Serial.println( "Input #3");
//         Serial.print(outVal3);
//         Serial.println( "Input #4");
//         Serial.print(outVal4);
//         Serial.println( "Input #5");
//         Serial.print(outVal5);
//         Serial.println( "Input #6");
//         delay(1000);
  }
}

Paul_KD7HB

I am not going to study your code, but I wonder if you have actually looked at the original values being returned. I see this quote in the MAP documentation:
"Does not constrain values to within the range, because out-of-range values are sometimes intended and useful.". So your return may be from this possibility.

Paul

jremington

#2
Dec 05, 2019, 06:07 pm Last Edit: Dec 05, 2019, 06:18 pm by jremington
The map() function expects and returns long integer values.

Debug by strategically placing Serial.print() statements to verify input and output values.

ardly

Before you blame MAP what are the values of inVal0...5 ?
"Facts do not cease to exist because they are ignored" - Aldous Huxley

Phil666

Yes guys if you look at the code I have the serial.print all commented out as I was testing earlier

If it serial.print the analogRead(0) it returns fine somewhere between 0-1023 on all Of them?

I mapped them to the sensor values and I just assumed it would work and to be fair 2/5 are working?

I'm not near the test bench at the mo but I'll take another look tomorrow at all the values coming in and being mapped

ardly

Yes guys if you look at the code I have the serial.print all commented out as I was testing earlier

If it serial.print the analogRead(0) it returns fine somewhere between 0-1023 on all Of them?

I mapped them to the sensor values and I just assumed it would work and to be fair 2/5 are working?

I'm not near the test bench at the mo but I'll take another look tomorrow at all the values coming in and being mapped
The commented code shows the 'out' values being printed, not the 'in' values.
Also what is the value of TOTAL_REGS_SIZE


"Facts do not cease to exist because they are ignored" - Aldous Huxley

blh64

your holdingRegs array is 'unsigned int' but you are mapping some of your values to negative numbers.  When you assign a negative number to an unsigned int, you get things like -1 -> 65535

ardly

your holdingRegs array is 'unsigned int' but you are mapping some of your values to negative numbers.  When you assign a negative number to an unsigned int, you get things like -1 -> 65535
That sounds like you may have hit it.
"Facts do not cease to exist because they are ignored" - Aldous Huxley

Phil666

Thanks blh64

Perhaps that's it, I'll give it a try tomorrow, am I better to just use an "int" can't use the "const int" ?

@ardly - I had tested the "in" and "out" values that's just what I tested last and had saved the code.

Phil666

blh64 ...... The more I think about it I do think you've hit the nail on the head....

As I said the outVal3 is working even though it's mapped from -40 to 60C but the value current given is about 20C (positive value)

While outVal0 and outVal1 are vacuum readings and I'm expecting a value of about -40kpa (negative value) so as you said this could be what is throwing it all out.

What can I used instead of an unsigned int?

Phil666

RTFM.....

unsigned int

Description
On the Uno and other ATMEGA based boards, unsigned ints (unsigned integers) are the same as ints in that they store a 2 byte value. Instead of storing negative numbers however they only store positive values, yielding a useful range of *** 0 to 65,535 ***((2^16) - 1).

int

Description
Integers are your primary data-type for number storage.

On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value. This yields a range of *** -32,768 to 32,767 *** (minimum value of -2^15 and a maximum value of (2^15) - 1). On the Arduino Due and SAMD based boards (like MKR1000 and Zero), an int stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648 to 2,147,483,647


Thanks guys! This must be my problem! Shout out to blh64 for pointing out my mistake!

blh64

And your debugging statements would have printed the correct values since they are of type 'int'

The problem is really with your master code that reads in these values over the modbus.  I'm guessing that is where they are also declared as 'unsigned int' as well and the root of the problem.

ardly

On a single machine whether or not something is signed or unsigned is really down to how you declare or interpret it. In the code below the pointers are both pointing to the same variable but one pointer thinks it is pointing at a signed value and the other thinks it is pointing at an unsigned value. The actual bit pattern in the variable being pointed at is the same.
Hence it is can be looked at as either a small negative value or large positive value.

Once you transmit data between different machines of the same type then they will store data in the same way and there should not be a problem. If you transmit data between different machines of different types then you might have problems because they might store variables in different ways (look up big endian vs little endian ).

I have no connection with but like the online compiler at that I used to try the code out on;
https://www.tutorialspoint.com/compile_cpp_online.php

Code: [Select]
#include <iostream>

using namespace std;

int main()
{
    int signedInt, *pointerSignedInt;
    unsigned int unsignedInt, *pointerUnsignedInt;
    
    signedInt=-1;
    unsignedInt=signedInt;
    
    // BOTH pointers are being pointed at the same thing
    pointerSignedInt=(int *) &unsignedInt;
    pointerUnsignedInt= &unsignedInt;
    
    
    cout << signedInt << endl;
    cout << unsignedInt << endl;
    
    cout << *pointerSignedInt << endl;
    cout << *pointerUnsignedInt << endl;
  
   return 0;
}



Output;
-1
4294967295
-1
4294967295



"Facts do not cease to exist because they are ignored" - Aldous Huxley

krupski

#13
Dec 06, 2019, 10:21 pm Last Edit: Dec 06, 2019, 11:23 pm by krupski
Hi guys

i am sure its something daft that i am missing.

i have a MODBUS network with 6 slaves, each slave has 5 analog inputs from various sensors.

i am using the MAP function for each sensor, but only two of them are returning a valid figure on the MASTER i can use
I've replaced the Arduino map() function with this:

Code: [Select]
#ifndef map
#define map(X,X1,X2,Y1,Y2)(((X-X1)*(Y2-Y1)/(X2-X1))+Y1)
#endif



Note that the original map function must be commented out in the Arduino IDE in two places for this to work:


(1) Line 253 of arduino-1.8.10/hardware/arduino/avr/cores/arduino/Arduino.h
(2) Line 52 through 55 of arduino-1.8.10/hardware/arduino/avr/cores/arduino/WMath.cpp


Then, at line 254 of arduino-1.8.10/hardware/arduino/avr/cores/arduino/Arduino.h (directly after the original map() was commented out), insert the code above.

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

blh64

I've replaced the Arduino map() function with this:

Code: [Select]
#ifndef map
#define map(X,X1,X2,Y1,Y2)(((X-X1)*(Y2-Y1)/(X2-X1))+Y1)
#endif



Note that the original map function must be commented out in the Arduino IDE in two places for this to work:


(1) Line 253 of arduino-1.8.10/hardware/arduino/avr/cores/arduino/Arduino.h
(2) Line 52 through 55 of arduino-1.8.10/hardware/arduino/avr/cores/arduino/WMath.cpp


Then, at line 254 of arduino-1.8.10/hardware/arduino/avr/cores/arduino/Arduino.h (directly after the original map() was commented out), insert the code above.
And make every sketch you write that depends on this functionality break for everyone else in the world?  No thanks.

Go Up