Calculation gives incorrect results...

Hello!

I got one of those cheap china mcufriend touch screens, and actually got it to work thanks to searching this forum.

The display itself was pretty easy, just adding touch took me some time. I found that the values tp.x and tp.y give me a value of where the screen is pressed. tp.x registers values from 130 up on the screen to 905 down. I tried scaling those values to match my pixels, but for some reason I can't figure out, I get incorrect or negative results, it's probably something very basic I overlooked, but if anybody could take a look at this, it would be highly appreciated!

This is the formula itself : x = (240*(tp.x-130))/(905-130);

And here is the code itself:

#define TOUCH_ORIENTATION  LANDSCAPE
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;  
#include <Adafruit_GFX.h>
#include <UTFTGLUE.h>
UTFTGLUE myGLCD(0x9327,A2,A1,A3,A4,A0);

extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];
#include <TouchScreen.h>        


#define YP A2   
#define YM 6    
#define XM A1
#define XP 7 
uint8_t SwapXY = 1;//8  

uint16_t TS_LEFT = 1135;
uint16_t TS_RT  = 135;
uint16_t TS_TOP = 975;
uint16_t TS_BOT = 450;


uint16_t identifier, oldcolor, currentcolor;
uint8_t Orientation = 0;
uint8_t Orientation_01 = 3;//PORTRAIT

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
TSPoint tp;   
int x = 0;
int y = 0;
char currentPage, selectedUnit;
#define MINPRESSURE 20
#define MAXPRESSURE 1000

#define SWAP(a, b) {uint16_t tmp = a; a = b; b = tmp;}
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

void setup()
{
  uint16_t tmp;
  Serial.begin(9600);
    
    digitalWrite(A0, HIGH);
    pinMode(A0, OUTPUT);
    myGLCD.InitLCD(TOUCH_ORIENTATION);
    myGLCD.clrScr();
    myGLCD.setFont(SmallFont);
    
    drawHomeScreen(); 
  currentPage = '0'; 
  selectedUnit = '0'; 
  switch (Orientation_01) {     
        case 0:   break;       
        case 1:   tmp = TS_LEFT, TS_LEFT = TS_BOT, TS_BOT = TS_RT, TS_RT = TS_TOP, TS_TOP = tmp;  break;
        case 2:   SWAP(TS_LEFT, TS_RT);  SWAP(TS_TOP, TS_BOT); break;
        case 3:   tmp = TS_LEFT, TS_LEFT = TS_TOP, TS_TOP = TS_RT, TS_RT = TS_BOT, TS_BOT = tmp;  break;
    }
    
    ts = TouchScreen(XP, YP, XM, YM, 300);     
    
}

void drawHomeScreen() {
 
  myGLCD.setBackColor(0,0,0);
  myGLCD.setColor(255, 255, 255); 
  myGLCD.setFont(BigFont);
  myGLCD.print("Arduino TFT Test", CENTER, 10);  
  myGLCD.setColor(255, 0, 0); 
  myGLCD.drawLine(0,32,319,32); 
}

void loop()
{
  
  tp = ts.getPoint();
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);

  if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) {
       
  if (currentPage == '0') {
    if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) {
      tp = ts.getPoint();   
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      myGLCD.setBackColor(0,0,0);
      myGLCD.setColor(255, 255, 255);
      myGLCD.setFont(BigFont);
      myGLCD.setCursor(0,0);
 
      x = (240*(tp.x-130))/(905-130);
      y = (400 * (tp.y - 965))/(-865); 
      
      myGLCD.println("x:");
      myGLCD.println(x);
      myGLCD.println(tp.x);
      myGLCD.println("y:");
      myGLCD.println(y);
      myGLCD.println(tp.y);
      
      if ((x>=35) && (x<=285) && (y>=90) && (y<=130)) {
      myGLCD.setColor(0,255,0);
      myGLCD.drawRect(35, 90, 285, 130);
      }
}
}
}
}

If you are using an Arduino Uno or Leonardo, then x and y are integers of 16 bits. Are tp.x and tp.y also integers ?
As soon as you multiply or divide those, it might be too large or zero.
Try the 'map()', I think it calculates with long to avoid that something is lost during the calculation.
https://www.arduino.cc/en/Reference/Map

If that doesn't work, try using float (that would be bad programming, but it will work).

If it is only that calculation, you could have made a small test sketch that prints the result on the serial monitor.

It's on a mega, sorry, forgot to mention

Just 'map()' starts good, but once I started touching different points it did it's own thing again.

Then I added 'int x1 = tp.x' and and 'int y1 = tp.y', used those in the formula instead of tp.x and tp.y but no difference.

After I tried with float, and it works fine, thanks a lot!

So the reason this happens is because at a certain point in the calculation, there's too much numbers for an integer?

x = (240*(tp.x-130))/(905-130);

for tp.x = 905

x = (240*775)/775;

x = 186000/775; // ups overflow

34R7:
So the reason this happens is because at a certain point in the calculation, there's too much numbers for an integer?

Far from that, you don't need floats. Just a larger integer type, like "long".

Please, if you post code again, use code tags!

long does not do the trick, it only works as a float.

and found the code tags, will do next time!

34R7:
long does not do the trick, it only works as a float.

The math you showed will work in long arithmetic. So you did something not quite right. Often it is about the order of operations. Sometimes the numerical constants have to be explicitly expressed as a long, e.g. 995L.

One way to make it work:

void setup() {
  Serial.begin(115200);
  Serial.print(F("(240L*(905-130))/(905-130) = "));
  Serial.println((240L * (905 - 130)) / (905 - 130));
}
void loop() {}
(240L*(905-130))/(905-130) = 240

aarg:
The math you showed will work in long arithmetic. So you did something not quite right. Often it is about the order of operations. Sometimes the numerical constants have to be explicitly expressed as a long, e.g. 995L.

also with the function 'map()' for scaling?

x = map(tp.x, 130, 905, 0, 240);
  y = map(tp.y, 975, 100, 0, 400);

I'll try with the formula tomorrow and let you know, now it's time for bed... Thanks for the support!

34R7:
also with the function 'map()' for scaling?

No. map() promotes all its parameters to long type automatically.