KlausMu / esp32-fan-controller

ESP32 fan controller with temperature sensor and MQTT
272 stars 48 forks source link

Strange behaviour with 2.8 inch touch display #19

Closed andreasm123 closed 6 months ago

andreasm123 commented 7 months ago

i've installed the software on an AZ-Touch. So far everything works as expected except the touch diplay component. When compiling the code (via PlatformIO) using the option '#define climate_controlledByBME_targetByMQTTandTouch' in config.h the following happens:

Any idea how to fix this?

KlausMu commented 7 months ago

Hm, sounds like a power issue. How do you power your device?

andreasm123 commented 7 months ago

The device is powered by a 12V 6A power supply. The fan is directly powered by the power supply and the az-touch internally via its 5V regulator - of course with a common ground. Btw. this behaviour also exists with the fan disconnected. Also same happens when powering the Esp via USB without the fan connected. Guess powering issues can be excluded. Mqtt Control with Fan (and without Touch) works flawlessly. Can it be a driver/irq/touch-display version issue?

KlausMu commented 7 months ago

Did you change anything in file "config.h" in the section "// 2. "AZ-Touch" 2.8 inch, since November 2020"`?

You could also try a completely different example just to see if the device works.

Here is some code which I used long time ago, with the first version of the ArduiTouch. I adjusted the pins for you so that it should work with the newer one. But it is untested. Most likely you have to finetune.

#include <SPI.h>
#include "Adafruit_GFX.h" //Grafik Bibliothek
#include "Adafruit_ILI9341.h" // Display Treiber
#include <XPT2046_Touchscreen.h> // Touchscreen Treiber
#include <Fonts/FreeSans9pt7b.h> //Verwendete Schrift

#define _debug 1 //Anzeige von Meldunge am Seriellen Monitor

//Verwendete Pins am Display
#define TFT_CS    5
#define TFT_DC    4
#define TFT_MOSI  23
#define TFT_CLK   18
#define TFT_RST   22
#define TFT_MISO  19
#define TFT_LED   15

#define HAVE_TOUCHPAD
#define TOUCH_CS 14
#define TOUCH_IRQ 27

// Parameter für Touchscreen
#define ILI9341_ULTRA_DARKGREY  0x632C
#define MINPRESSURE 10
#define MAXPRESSURE 2000
//Messbereich muss eventuell kalibriert werden
#define TS_MINX 230 // 230
#define TS_MINY 350 // 350
#define TS_MAXX 3700 // 3700
#define TS_MAXY 3900 // 3900

//Treiber Instanzen
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen touch(TOUCH_CS, TOUCH_IRQ);

//aktuelle Positionen
int tsx, tsy, tsxraw, tsyraw;
//aktueller Touch Zustand
bool tsdown = false;
//aktuelle Bildschirmausrichtung
uint8_t rotation = 0;

//Vorbereitung
void setup() {
  #ifdef _debug
  Serial.begin(115200);
  #endif
  pinMode(TFT_LED, OUTPUT);
  digitalWrite(TFT_LED, HIGH); // Display-Beleuchtung einschalten
  //Treiber starten
  tft.begin();
  touch.begin();
  #ifdef _debug
  //Auflösung des Displays
  Serial.print("tftx ="); Serial.print(tft.width()); Serial.print(" tfty ="); Serial.println(tft.height());
  #endif
  //aktuelle Werte zurücksetzen
  tsx = 0;
  tsy = 0;
  tsxraw = 0;
  tsyraw = 0;
  tsdown = false;
  rotation = 0;
  //Anzeigen
  draw_screen(rotation);

}

void loop() {
  //auf Berührung reagieren
  handleTouch();
  delay(100);
}

//aktuelle Position und Berührungszustand
//vom Touchscreen ermitteln
void handleTouch() {
  TS_Point p;
  p = touch.getPoint(); //aktuelle Daten lesen
  tsxraw = p.x; //x und y als Rohwerte merken
  tsyraw = p.y;
  delay(1);
  //Bildschirm Ausrichtung ermitteln
  uint8_t rot = tft.getRotation();
  //je nach Ausrichtung relative Bildschirmpositionen
  //ermitteln
  switch (rot) {
    case 0: tsx = map(tsyraw, TS_MINY, TS_MAXY, 240, 0);
            tsy = map(tsxraw, TS_MINX, TS_MAXX, 0, 320);
            break;
    case 1: tsx = map(tsxraw, TS_MINX, TS_MAXX, 0, 320);
            tsy = map(tsyraw, TS_MINY, TS_MAXX, 0, 240);
            break;
    case 2: tsx = map(tsyraw, TS_MINY, TS_MAXY, 0, 240);
            tsy = map(tsxraw, TS_MINX, TS_MAXX, 320, 0);
            break;
    case 3: tsx = map(tsxraw, TS_MINX, TS_MAXX,320, 0);
            tsy = map(tsyraw, TS_MINY, TS_MAXY, 240, 0);
            break;
  }
  //Berührungszustand ermitteln
  if ((p.z > MINPRESSURE) != (tsdown)) {
    tsdown = (p.z > MINPRESSURE);
    //Überprüfen ob das grüne Rechteck in der Mitte berührt wurde
    if (tsdown && (tsx > (tft.width() / 2 - 20)) && (tsx < (tft.width() / 2 + 20)) 
      && (tsy > (tft.height() / 2 - 20)) && (tsy < (tft.height() / 2 + 20))) {
      //wenn ja dann Bildschirmausrichtung ändern
      rotation ++;
      if (rotation > 3) rotation = 0;
    }
    //Bildschirm neu zeichnen
    draw_screen(rotation);
  }

}

//Hauptbildschirm anzeigen
void draw_screen(uint8_t rot) {
  uint16_t w,h;
  //Ausrichtung Farben und Schrift auswählen
  tft.setRotation(rot); 
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.setFont(&FreeSans9pt7b);
  w = tft.width();
  h = tft.height();
  //je nach Ausrichtung Messwerte und
  //grünes Rechteck in der Mitte zeichnen
  if ((rot==1) || (rot == 3)) {
    drawPosition1(tsxraw,tsyraw,tsx,tsy,tsdown); 
    tft.fillRect(w/2 - 10, h/2 - 20,20,40, ILI9341_GREEN);
  } else { 
    drawPosition2(tsxraw,tsyraw,tsx,tsy,tsdown);
    tft.fillRect(w/2 - 20, h/2 - 10,40,20, ILI9341_GREEN);
  }
  //Rotations index im grünen Rechteck anzeigen
  tft.setCursor(w/2-5,h/2+6);
  tft.setTextColor(ILI9341_BLACK, ILI9341_GREEN);
  tft.print(rot);
  //Pfeile zu den Eckpunkten anzeigen
  tft.drawLine(0,0,20,0,ILI9341_WHITE);
  tft.drawLine(0,0,0,20,ILI9341_WHITE);
  tft.drawLine(0,0,40,40,ILI9341_WHITE);
  tft.drawLine(w-1,0,w-20,0,ILI9341_WHITE);
  tft.drawLine(w-1,0,w-1,20,ILI9341_WHITE);
  tft.drawLine(w-1,0,w-40,40,ILI9341_WHITE);
  tft.drawLine(w-1,h-1,w-40,h,ILI9341_WHITE);
  tft.drawLine(w-1,h-1,w,h-40,ILI9341_WHITE);
  tft.drawLine(w-1,h-1,w-40,h-40,ILI9341_WHITE);
  tft.drawLine(0,h-1,20,h-1,ILI9341_WHITE);
  tft.drawLine(0,h-1,0,h-20,ILI9341_WHITE);
  tft.drawLine(0,h-1,40,h-40,ILI9341_WHITE);
}

//Messwerte für Querformat anzeigen
void drawPosition1(uint16_t xraw, uint16_t yraw, uint16_t x, uint16_t y, bool down) {
  tft.setCursor(20,60);
  tft.print("X = ");
  display_right(110,60,String(x));
  tft.setCursor(180,60);
  tft.print("Y = ");
  display_right(270,60,String(y));

  tft.setCursor(20,180);
  tft.print("Xraw = ");
  display_right(120,180,String(xraw));
  tft.setCursor(180,180);
  tft.print("Yraw = ");
  display_right(280,180,String(yraw));
  if (down) tft.fillCircle(160,160,10,ILI9341_RED); else tft.fillCircle(160,160,10,ILI9341_YELLOW);
}  

//Messwerte für Hochformat anzeigen
void drawPosition2(uint16_t xraw, uint16_t yraw, uint16_t x, uint16_t y, bool down) {
  tft.setCursor(20,60);
  tft.print("X = ");
  display_right(110,60,String(x));
  tft.setCursor(20,100);
  tft.print("Y = ");
  display_right(110,100,String(y));

  tft.setCursor(20,240);
  tft.print("Xraw = ");
  display_right(120,240,String(xraw));
  tft.setCursor(20,280);
  tft.print("Yraw = ");
  display_right(120,280,String(yraw));
  if (down) tft.fillCircle(120,200,10,ILI9341_RED); else tft.fillCircle(120,200,10,ILI9341_YELLOW);
}  

//Eine Zahl rechtsbündig ausgeben 
void display_right(int x, int y, String val) {
  int16_t x1, y1;
  uint16_t w, h;
  int str_len =  val.length() + 1;
  char char_array[str_len];
  val.toCharArray(char_array, str_len);
  tft.getTextBounds(char_array, x, y, &x1, &y1, &w, &h);  
  tft.setCursor(x - w, y);
  tft.print(char_array);
}
andreasm123 commented 7 months ago

You asked: Did you change anything in file "config.h" in the section "// 2. "AZ-Touch" 2.8 inch, since November 2020"`? Did not change anything there. Regarding the test code i will give it a try in some days. Thanks for helping.

andreasm123 commented 7 months ago

Gave it a try - unfortunately your test code does not compile - see errors below. Am i missing something else?

src/test.cpp: In function 'void setup()': src/test.cpp:66:3: error: 'draw_screen' was not declared in this scope draw_screen(rotation); ^~~~~~~~~~~ src/test.cpp: In function 'void loop()': src/test.cpp:72:3: error: 'handleTouch' was not declared in this scope handleTouch(); ^~~~~~~~~~~ Compiling .pio\build\esp32dev\libaf1\PubSubClient\PubSubClient.cpp.o src/test.cpp: In function 'void handleTouch()': src/test.cpp:113:5: error: 'draw_screen' was not declared in this scope draw_screen(rotation); ^~~~~~~~~~~ src/test.cpp: In function 'void draw_screen(uint8_t)': src/test.cpp:132:5: error: 'drawPosition1' was not declared in this scope drawPosition1(tsxraw,tsyraw,tsx,tsy,tsdown); ^~~~~~~~~~~~~ src/test.cpp:135:5: error: 'drawPosition2' was not declared in this scope drawPosition2(tsxraw,tsyraw,tsx,tsy,tsdown); ^~~~~~~~~~~~~ src/test.cpp: In function 'void drawPosition1(uint16_t, uint16_t, uint16_t, uint16_t, bool)': src/test.cpp:161:3: error: 'display_right' was not declared in this scope display_right(110,60,String(x)); ^~~~~~~~~~~~~ src/test.cpp: In function 'void drawPosition2(uint16_t, uint16_t, uint16_t, uint16_t, bool)': src/test.cpp:179:3: error: 'display_right' was not declared in this scope display_right(110,60,String(x)); ^~~~~~~~~~~~~ *** [.pio\build\esp32dev\src\test.cpp.o] Error 1

KlausMu commented 7 months ago

That's because PlatformIO needs forward declarations if a function is not yet known where it is used. Simply place these lines somewhere at the top, before setup()

void handleTouch();
void draw_screen(uint8_t rot);
void drawPosition1(uint16_t xraw, uint16_t yraw, uint16_t x, uint16_t y, bool down);
void drawPosition2(uint16_t xraw, uint16_t yraw, uint16_t x, uint16_t y, bool down);
void display_right(int x, int y, String val);
andreasm123 commented 7 months ago

unfortunately does not work either - i can compile the code now but the screen stays blank. Not sure if i'm still missing something else. But: is there a chance to get in touch with you via email? i could then send a short video on how the display behaves - maybe that's more helpful to trace down the bug (or whatever the root cause is)

KlausMu commented 7 months ago

Don't get me wrong, but I think here is the place where it should be discussed. If anyone else is facing similar problems, he or she is for sure interested in a solution.

If you want to, you can upload a video to Google Drive or OneDrive or something similar. But I don't know if this is helpful.

Please keep in mind that I don't have the new AZ Touch, so I can only help you by guessing, not by trying it by myself.

If the screen stays black, the try to play around with TFT_LED. Most likely this is the place to go.

You could also try other examples from the AZ Delivery blog.

First you have to get the device to work. Maybe you also need support from AZ Delivery.

But I'm sure if you try other examples from AZ Delivery, you will a) learn a lot and b) solve the problem

andreasm123 commented 7 months ago

No Problem. In the meanwhile i tested another ESP32 and Display with your fan controller code - same result. Really seems to be code related. As said the device itself is working 100% fine (except the display portion). A short demo video showing the behaviour can be accessed here: https://www.dropbox.com/scl/fi/69jcq75ifbymrhwbz7k43/DisplayError.mp4?rlkey=0dsa0lz6vukvywhhwovddrdex&dl=0 A fan was not connected during the tests. Also same result when powering the ESP via USB or the AZ-Touch device.

KlausMu commented 7 months ago

Seems like when you hit the lower left corner, you turn off the screen. But the off button is at the upper right corner. Sounds like you should try the setting

#define TFT_ROTATION

Possible values are 1 and 3.

andreasm123 commented 7 months ago

Had this idea as well before. Unfortunately same result. That also does not explain why the display turns off when hitting a different area besides upper right / lower left.

KlausMu commented 7 months ago

Ok, what does the log say? Every touch event is logged with x and y coordinate. And also if the code thinks that on that coordinate a button is hit. If the screen is off, a touch event does nothing but only to turn on the screen, no matter of the coordinates. See onClick in tftTouch.cpp