// Constrain angle within limits
int constrainAngle(int angle, int minVal, int maxVal) {
if (angle < minVal) return minVal;
if (angle > maxVal) return maxVal;
return angle;
}
// Update text area with angle value
void updateAngleDisplay(lv_obj_t* textarea, int angle) {
char buf[16];
snprintf(buf, sizeof(buf), "%d", angle);
lv_textarea_set_text(textarea, buf);
}
Comments
hi any solution guys same issue here
include <PCA9557.h>
include <lvgl.h>
include <Crowbits_DHT20.h>
include <Preferences.h>
define LGFX_USE_V1
include <LovyanGFX.hpp>
include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp>
include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp>
// ============= ANGLE LIMITS - EDIT THESE VALUES =============
define PAN_MIN_ANGLE 0 // Minimum pan angle
define PAN_MAX_ANGLE 360 // Maximum pan angle
define TILT_MIN_ANGLE 0 // Minimum tilt angle
define TILT_MAX_ANGLE 180 // Maximum tilt angle
define SERIAL_BAUD 9600 // Serial baud rate
define SPLASH_DURATION 3000 // Splash screen duration in milliseconds
// ============================================================
define TFT_BL 2
// Global variables for angles
int panAngle = 0;
int tiltAngle = 0;
// Preferences object for saving angles
Preferences preferences;
// LGFX Display Class
class LGFX : public lgfx::LGFX_Device
{
public:
lgfx::Bus_RGB _bus_instance;
lgfx::Panel_RGB _panel_instance;
LGFX(void)
{
{
auto cfg = _bus_instance.config();
cfg.panel = &_panel_instance;
}
};
LGFX lcd;
// UI
include "ui.h"
Crowbits_DHT20 dht20;
// Touch
include "touch.h"
// Display buffers
static uint32_t screenWidth;
static uint32_t screenHeight;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t disp_draw_buf[800 * 480 / 15];
static lv_disp_drv_t disp_drv;
// ============= HELPER FUNCTIONS =============
// Constrain angle within limits
int constrainAngle(int angle, int minVal, int maxVal) {
if (angle < minVal) return minVal;
if (angle > maxVal) return maxVal;
return angle;
}
// Update text area with angle value
void updateAngleDisplay(lv_obj_t* textarea, int angle) {
char buf[16];
snprintf(buf, sizeof(buf), "%d", angle);
lv_textarea_set_text(textarea, buf);
}
// Send serial command
void sendSerial(const char* command) {
Serial.println(command);
}
// Save angles to preferences
void saveAngles() {
preferences.begin("motor", false);
preferences.putInt("panAngle", panAngle);
preferences.putInt("tiltAngle", tiltAngle);
preferences.end();
}
// Load angles from preferences
void loadAngles() {
preferences.begin("motor", true);
panAngle = preferences.getInt("panAngle", 0);
tiltAngle = preferences.getInt("tiltAngle", 0);
preferences.end();
// Constrain loaded values
panAngle = constrainAngle(panAngle, PAN_MIN_ANGLE, PAN_MAX_ANGLE);
tiltAngle = constrainAngle(tiltAngle, TILT_MIN_ANGLE, TILT_MAX_ANGLE);
Serial.print("Loaded Pan: ");
Serial.print(panAngle);
Serial.print(" Tilt: ");
Serial.println(tiltAngle);
}
// ============= EVENT HANDLERS =============
// Pan Plus Button
void panPlusClicked(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
panAngle++;
panAngle = constrainAngle(panAngle, PAN_MIN_ANGLE, PAN_MAX_ANGLE);
updateAngleDisplay(ui_PANANGLE, panAngle);
sendSerial("PAN_PLUS");
char buf[32];
snprintf(buf, sizeof(buf), "PAN_ANGLE:%d", panAngle);
sendSerial(buf);
saveAngles();
}
}
// Pan Minus Button
void panMinusClicked(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
panAngle--;
panAngle = constrainAngle(panAngle, PAN_MIN_ANGLE, PAN_MAX_ANGLE);
updateAngleDisplay(ui_PANANGLE, panAngle);
sendSerial("PAN_MINUS");
char buf[32];
snprintf(buf, sizeof(buf), "PAN_ANGLE:%d", panAngle);
sendSerial(buf);
saveAngles();
}
}
// Tilt Plus Button
void tiltPlusClicked(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
tiltAngle++;
tiltAngle = constrainAngle(tiltAngle, TILT_MIN_ANGLE, TILT_MAX_ANGLE);
updateAngleDisplay(ui_PANANGLE1, tiltAngle);
sendSerial("TILT_PLUS");
char buf[32];
snprintf(buf, sizeof(buf), "TILT_ANGLE:%d", tiltAngle);
sendSerial(buf);
saveAngles();
}
}
// Tilt Minus Button
void tiltMinusClicked(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
tiltAngle--;
tiltAngle = constrainAngle(tiltAngle, TILT_MIN_ANGLE, TILT_MAX_ANGLE);
updateAngleDisplay(ui_PANANGLE1, tiltAngle);
sendSerial("TILT_MINUS");
char buf[32];
snprintf(buf, sizeof(buf), "TILT_ANGLE:%d", tiltAngle);
sendSerial(buf);
saveAngles();
}
}
// Pan Angle keyboard READY event (when user presses Enter/OK)
void panAngleReady(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_READY) {
const char* txt = lv_textarea_get_text(ui_PANANGLE);
int newAngle = atoi(txt);
panAngle = constrainAngle(newAngle, PAN_MIN_ANGLE, PAN_MAX_ANGLE);
updateAngleDisplay(ui_PANANGLE, panAngle);
char buf[32];
snprintf(buf, sizeof(buf), "PAN_ANGLE:%d", panAngle);
sendSerial(buf);
saveAngles();
}
}
// Tilt Angle keyboard READY event (when user presses Enter/OK)
void tiltAngleReady(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_READY) {
const char* txt = lv_textarea_get_text(ui_PANANGLE1);
int newAngle = atoi(txt);
tiltAngle = constrainAngle(newAngle, TILT_MIN_ANGLE, TILT_MAX_ANGLE);
updateAngleDisplay(ui_PANANGLE1, tiltAngle);
char buf[32];
snprintf(buf, sizeof(buf), "TILT_ANGLE:%d", tiltAngle);
sendSerial(buf);
saveAngles();
}
}
// Extend Button
void extendClicked(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
sendSerial("EXTEND");
}
}
// Retract Button
void retractClicked(lv_event_t * e) {
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
sendSerial("RETRACT");
}
}
// ============= DISPLAY FUNCTIONS =============
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
if (LV_COLOR_16_SWAP != 0)
lcd.pushImageDMA(area->x1, area->y1, w, h,(lgfx::rgb565_t*)&color_p->full);
else
lcd.pushImageDMA(area->x1, area->y1, w, h,(lgfx::rgb565_t*)&color_p->full);
endif
lv_disp_flush_ready(disp);
}
void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
if (touch_has_signal())
{
if (touch_touched())
{
data->state = LV_INDEV_STATE_PR;
data->point.x = touch_last_x;
data->point.y = touch_last_y;
}
else
{
data->state = LV_INDEV_STATE_REL;
}
delay(15);
}
// Timer callback to switch from splash to main screen
void splashTimerCallback(lv_timer_t * timer) {
lv_scr_load_anim(ui_MainScreen, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, false);
lv_timer_del(timer);
// Add event callbacks AFTER main screen is loaded
Serial.println("Main screen loaded, registering button events...");
lv_obj_add_event_cb(ui_PLUSPAN, panPlusClicked, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_MINUSPAN, panMinusClicked, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_tilt_plus, tiltPlusClicked, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_MINUSTILT, tiltMinusClicked, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_OPEN_STAND, extendClicked, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_OPEN_STAND1, retractClicked, LV_EVENT_ALL, NULL);
lv_obj_add_event_cb(ui_PANANGLE, panAngleReady, LV_EVENT_READY, NULL);
lv_obj_add_event_cb(ui_PANANGLE1, tiltAngleReady, LV_EVENT_READY, NULL);
// Set initial angle display values
updateAngleDisplay(ui_PANANGLE, panAngle);
updateAngleDisplay(ui_PANANGLE1, tiltAngle);
Serial.println("All event handlers registered!");
}
// ============= SETUP =============
PCA9557 Out;
void setup()
{
Serial.begin(SERIAL_BAUD);
Serial.println("Motor Control System Starting...");
// IO pin setup
pinMode(38, OUTPUT);
digitalWrite(38, LOW);
pinMode(17, OUTPUT);
digitalWrite(17, LOW);
pinMode(18, OUTPUT);
digitalWrite(18, LOW);
pinMode(42, OUTPUT);
digitalWrite(42, LOW);
delay(200);
// CRITICAL: Touch screen power sequence via PCA9557 for V3.0
Wire.begin(19, 20);
delay(50);
dht20.begin();
// Initialize PCA9557 IO expander
Out.reset();
Out.setMode(IO_OUTPUT);
// GT911 Touch Reset Sequence (CRITICAL for V3.0)
Out.setState(IO0, IO_LOW); // Touch power low
Out.setState(IO1, IO_LOW); // Touch reset low
delay(20);
Out.setState(IO0, IO_HIGH); // Touch power high
delay(100);
Out.setMode(IO1, IO_INPUT); // Release reset
delay(50);
Serial.println("Touch controller reset complete");
// Init Display
lcd.begin();
lcd.fillScreen(TFT_BLACK);
lcd.setTextSize(2);
delay(200);
// Init LVGL
lv_init();
// Init touch device AFTER PCA9557 initialization
touch_init();
Serial.println("Touch initialized");
screenWidth = lcd.width();
screenHeight = lcd.height();
lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, screenWidth * screenHeight / 15);
// Initialize the display
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = screenWidth;
disp_drv.ver_res = screenHeight;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
// Initialize the input device driver
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);
ifdef TFT_BL
ledcSetup(1, 300, 8);
ledcAttachPin(TFT_BL, 1);
ledcWrite(1, 255);
endif
// Initialize UI (shows splash screen by default)
ui_init();
// Start fade-in animation on splash screen logo
fadein_Animation(ui_LOGO, 0);
// Load saved angles from memory
loadAngles();
// Create timer to switch to main screen after splash duration
lv_timer_create(splashTimerCallback, SPLASH_DURATION, NULL);
Serial.println("System Ready! Touch should work now.");
Serial.print("Pan Limits: ");
Serial.print(PAN_MIN_ANGLE);
Serial.print(" to ");
Serial.println(PAN_MAX_ANGLE);
Serial.print("Tilt Limits: ");
Serial.print(TILT_MIN_ANGLE);
Serial.print(" to ");
Serial.println(TILT_MAX_ANGLE);
Serial.println("Touch the screen to test...");
}
// ============= MAIN LOOP =============
void loop()
{
lv_timer_handler();
delay(5);
}
my code