/********************************************************* A la Colour! *********************************************************/ #include "Adafruit_GFX.h" #include "Adafruit_ILI9341.h" #include #include #include #include #include #include #include #include "pins.h" #define DEBUG_MODE #ifdef DEBUG_MODE #define DEBUG_PRINT(x) Serial.print(x) #define DEBUG_PRINTLN(x) Serial.println(x) #define DEBUG_PRINTF(...) Serial.printf(__VA_ARGS__) #else #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) #define DEBUG_PRINTF(...) #endif const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASSWORD"; WebServer server(80); // Color rectangle const int Rect_start_x = 3; const int Rect_start_y = 90; const int Rect_end_x = 300; const int Rect_end_y = 130; // RGB int r_val; int g_val; int b_val; //int r = 255, g = 0, b = 0; float r = 0; float g = 0; float b = 0; int buttonState = 0; bool prevState[4] = {HIGH, HIGH, HIGH, HIGH}; // Previous State uint16_t colorInfo[4] = {0, 0, 0, 0}; //Colour information at each button no. XPT2046_Touchscreen ts(TOUCH_CS); // Define Touch screen Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI, TFT_DC, TFT_CS, TFT_RST); // Define ILI9341 void handleRGB() { StaticJsonDocument<200> doc; doc["r"] = (int)r; doc["g"] = (int)g; doc["b"] = (int)b; String response; serializeJson(doc, response); // server.send(200, "application/json", response); } // Main menu position #define set1_x 33 #define set1_y 113 #define set2_x 33 #define set2_y 155 #define set3_x 33 #define set3_y 197 #define set_width 240 #define set_length 42 #define MAIN_MENU 1 #define SET_MENU 2 #define EXEC_MENU 3 #define COL_PICK 4 #define LIVE_MENU 5 int current_disp = 0; int sb[4] = {SB1, SB2, SB3, SB4}; int rgbValue[4][3]; void setup() { //SPI0の場合 SPI.setTX(TFT_MOSI); SPI.setSCK(TFT_SCK); // Display Start tft.begin(); //Display Setting tft.fillScreen(ILI9341_BLACK); //背景の塗りつぶし tft.setRotation(3); //画面回転 tft.setTextSize(4); //サイズ // Touch screen begin ts.begin(); ts.setRotation(1); // debug mode(2) Serial.begin(9600); //Serial.begin(115200); /* // Big Button pinMode(BB1, INPUT_PULLUP); pinMode(BB2, INPUT_PULLUP); */ // Select Button(4) pinMode(SB1, INPUT_PULLUP); pinMode(SB2, INPUT_PULLUP); pinMode(SB3, INPUT_PULLUP); pinMode(SB4, INPUT_PULLUP); // Initial Display current_disp = MAIN_MENU; //setup1 // setup1(); } void loop() { // Read TouchScreen & Calibration int16_t pos_x; int16_t pos_y; static bool screenDrawn = false; switch(current_disp){ case MAIN_MENU: // Main Menu if (!screenDrawn) { Main_Menu(); screenDrawn = true; } // Calibration Calib_pos(pos_x, pos_y); if(pos_x != -1 && pos_y != -1){ if (isTouchInsideRect(pos_x, pos_y, start1_x, start1_y, end1_x, end1_y)) { current_disp = SET_MENU; screenDrawn = false; } else if (isTouchInsideRect(pos_x, pos_y, start2_x, start2_y, end2_x, end2_y)) { current_disp = EXEC_MENU; screenDrawn = false; } else if(isTouchInsideRect(pos_x, pos_y, start3_x, start3_y, end3_x, end3_y)){ current_disp = LIVE_MENU; } else { Err_msg("Please SELECT 1,2 or 3"); } while(ts.touched()) delay(10); } break; case SET_MENU: Set_Menu(); current_disp = MAIN_MENU; screenDrawn = false; break; case EXEC_MENU: Exec_Menu(); current_disp = MAIN_MENU; screenDrawn = false; break; case LIVE_MENU: Live_Menu(); current_disp = MAIN_MENU; screenDrawn = false; break; default: Err_msg("Please SELECT 1 or 2"); screenDrawn = false; } } void setup1(){ // Wifi WiFi.begin(ssid, password); Serial.print("Connecting"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected. IP: " + WiFi.localIP().toString()); server.on("/rgb", handleRGB); server.begin(); Serial.println("HTTP server started"); } void Send_data_to_led(){ DEBUG_PRINTLN("data send begin"); server.handleClient(); } void handleButton(int btn) { tft.setTextSize(2); tft.setCursor(30, 200); tft.setTextColor(ILI9341_YELLOW); //tft.printf("You selected #%d", btn); } /****************************************************** Error Message ******************************************************/ void Err_msg(const char *msg) { tft.setTextSize(4); tft.setCursor(err_x, err_y); tft.setTextColor(ILI9341_WHITE); tft.fillRect(err_x, err_y, 240, 40, ILI9341_BLACK); // 消去してから描画 tft.printf("%s", msg); // 明示的にフォーマット指定 } /******************************************************* isTouchInsideRect(): int tx, ty : touch position int xmin, ymin : minimum area int xmax, ymax : max area *******************************************************/ bool isTouchInsideRect(int tx, int ty, int xmin, int ymin, int xmax, int ymax) { return (tx >= xmin && tx <= xmax && ty >= ymin && ty <= ymax); } /************************************************************************** Main Menu Display First Main menu Select 1. Select Menu 2. Execute Menu **************************************************************************/ void Main_Menu(){ DEBUG_PRINTLN("main menu start"); //Display Text tft.setRotation(3); //Rotation of display tft.setTextSize(4); //Text size tft.fillScreen(ILI9341_BLACK); // Initialize the display(Black) tft.setCursor(20, 20); // Start position //tft.setFont(&FreeMonoBoldOblique12pt7b); tft.setTextColor(ILI9341_CYAN); // tft.printf("A! "); tft.setTextColor(ILI9341_GREEN); //赤 tft.printf("la "); tft.setTextColor(ILI9341_MAGENTA); //赤 tft.printf("COLOUR\n\n"); tft.setCursor(40, 75); //カーソル位置 tft.setTextColor(ILI9341_YELLOW); //赤 tft.setTextSize(3); //サイズ tft.printf("~ MAIN MENU ~\n\n"); tft.setTextSize(3); //サイズ tft.setTextColor(ILI9341_WHITE); tft.setCursor(60, 125); //カーソル位置 tft.printf("1. Setting\n"); tft.setCursor(60, 165); //カーソル位置 tft.printf("2. Execute\n"); tft.setCursor(60, 205); //カーソル位置 tft.printf("3. Live\n"); // debug write -> delete later(?) tft.drawRect(set1_x, set1_y, set_width, set_length, ILI9341_WHITE); tft.drawRect(set2_x, set2_y, set_width, set_length, ILI9341_WHITE); tft.drawRect(set3_x, set3_y, set_width, set_length, ILI9341_WHITE); } /****************************************************** Get Data from touch screen Calibration Code from chatGPT ******************************************************/ void Calib_pos(int16_t &x, int16_t &y){ boolean bTouch = ts.touched(); if(bTouch == true){ const int16_t Offset_x = 150; const int16_t Offset_y = 150; float RateX = (float)320 / (3700 - Offset_x); float RateY = (float)240 / (3700 - Offset_y); TS_Point tPoint = ts.getPoint(); x = (float)(tPoint.x - Offset_x) * RateX; y = (float)(tPoint.y - Offset_y) * RateY; }else{ x = -1; y = -1; } } /************************************************************************** Set Menu Display First Main menu Select 1. Push Button 2. Go to Col_pick() **************************************************************************/ void Set_Menu(){ buttonState = 0; int prev[4] = {HIGH, HIGH, HIGH, HIGH}; // 初期状態 // Select the button for color memory // Display which number you want to memorize the color? // Please push the button tft.fillScreen(ILI9341_BLACK); //Initialise the screen (paint black) tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.setCursor(10, 10); tft.printf("[Set Menu]"); tft.setTextSize(3); //サイズ tft.setCursor(20, 80); // Cursor position tft.setTextColor(ILI9341_YELLOW); // letter color tft.printf("PUSH the Button\n\n"); tft.printf(" [1 - 4]\n"); // Back to Main Menu tft.setTextSize(2); tft.setCursor(55, 190); tft.setTextColor(ILI9341_GREEN); // letter color tft.printf("when Touch the Screen\n"); tft.printf(" Back to Main\n"); //tft.drawRect(33, 120, set_width, set_length, ILI9341_WHITE); DEBUG_PRINTLN("set menu start"); // From here asked chatGPT about the procedure while(buttonState == 0) { int button = checkButtonPress(sb, prev, 4); if (button > 0) { Serial.printf("Pushed %d button\n", button); buttonState = button; } // if touch the screen, Back to Main page if (ts.touched()) { while(ts.touched()) delay(10); DEBUG_PRINTLN("display is touched. back to main"); return; } delay(10); } // Go to Next Process DEBUG_PRINT("button:"); DEBUG_PRINTLN(buttonState); if (buttonState > 0) { // Set Color Col_pick(buttonState); // Memory Col_memory(buttonState); // Fixed Fix_Col_Disp(buttonState); Col_Rect(); } // フィードバック表示(例) tft.setCursor(50, 90); tft.setTextColor(ILI9341_GREEN); tft.setTextSize(2); tft.print("Saved to Slot "); tft.print(buttonState); while (!ts.touched()) { delay(10); } // 指が離されるのも待つ while (ts.touched()) { delay(10); } buttonState = 0; // 処理後にリセット } /************************************************************************** Exec Menu Display First Main menu Select 1. Select Menu 2. Execute Menu **************************************************************************/ void Exec_Menu() { int16_t pos_x, pos_y; int buttonState = 0; int states[4] = {HIGH, HIGH, HIGH, HIGH}; int prev[4] = {HIGH, HIGH, HIGH, HIGH}; // 画面初期化 tft.fillScreen(ILI9341_BLACK); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.setCursor(10, 10); tft.printf("[Exec Menu]"); tft.setTextSize(3); tft.setCursor(20, 50); tft.setTextColor(ILI9341_YELLOW); tft.printf("PUSH the Button\n\n"); tft.setTextSize(2); tft.setCursor(55, 190); tft.setTextColor(ILI9341_GREEN); tft.printf("when Touch the Screen\n"); tft.printf(" Back to Main\n"); while (buttonState == 0) { int button = checkButtonPress(sb, prev, 4); if (button > 0) { Serial.printf("Pushed %d button\n", button); //put selected information to r,g,b r = rgbValue[button-1][0]; g = rgbValue[button-1][1]; b = rgbValue[button-1][2]; buttonState = button; } if (ts.touched()) return; // タッチされたらメインに戻る delay(10); } // 送信確認画面 DEBUG_PRINT("button:"); DEBUG_PRINTLN(buttonState); tft.fillScreen(ILI9341_BLACK); tft.setTextColor(ILI9341_WHITE); tft.setCursor(10, 20); tft.setTextSize(2); tft.printf("Is it ok to send data to the Light?\n\n"); tft.setTextColor(ILI9341_YELLOW); tft.setCursor(10, 70); tft.setTextSize(2); tft.printf("Picked color:"); Col_Rect(); // 色表示 // Yes / No ボタン描画 int yes_x = 50, yes_y = 120; int no_x = 170, no_y = 120; int wid = 70, leng = 40; tft.drawRect(yes_x, yes_y, wid, leng, ILI9341_WHITE); tft.drawRect(no_x, no_y, wid, leng, ILI9341_WHITE); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(3); tft.setCursor(60, 130); tft.printf("Yes"); tft.setCursor(190, 130); tft.printf("No"); // Yes / No 選択待ち while (true) { Calib_pos(pos_x, pos_y); if (pos_x == -1 || pos_y == -1) { delay(10); continue; } if (isTouchInsideRect(pos_x, pos_y, yes_x, yes_y, yes_x + wid, yes_y + leng)) { DEBUG_PRINTLN("push Yes"); Send_data_to_led(); // データ送信などの処理 tft.fillScreen(ILI9341_BLACK); tft.setCursor(20, 100); tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(3); tft.print("Data Sent!"); break; } else if (isTouchInsideRect(pos_x, pos_y, no_x, no_y, no_x + wid, no_y + leng)) { DEBUG_PRINTLN("push No"); tft.fillScreen(ILI9341_BLACK); tft.setCursor(40, 100); tft.setTextColor(ILI9341_RED); tft.setTextSize(3); tft.print("Canceled"); break; } delay(100); } // 色再表示 + 戻り案内 Col_Rect(); tft.setCursor(40, 70); tft.setTextColor(ILI9341_GREEN); tft.setTextSize(2); tft.print("Touch to return"); // 指を離すのを待つ while (!ts.touched()) delay(10); while (ts.touched()) delay(10); } /********************************************* checkButtonPress from GPT *********************************************/ int checkButtonPress(int* pins, int* prevS, int count) { for (int i = 0; i < count; i++) { int state = digitalRead(pins[i]); if (prevS[i] == HIGH && state == LOW) { prevS[i] = state; return i + 1; } prevS[i] = state; } return 0; } // 5/29 作業 /************************************************* Col_pick() : choose the color from the slide potentiometer *************************************************/ void Col_pick(int b_no){ /* byte r = 0; byte g = 0; byte b = 0; */ bool prevBtn = HIGH; bool btn = HIGH; bool disp_mode = false; // Display mode DEBUG_PRINT("Col_pick start:"); DEBUG_PRINTLN(b_no); // Display if (!disp_mode) { DEBUG_PRINTLN("disp"); Col_Disp(b_no); disp_mode = true; } DEBUG_PRINT("color_mode:"); DEBUG_PRINTLN(color_mode); // Draw Rectalngle with color // from chatGPT while (digitalRead(sb[b_no - 1]) == LOW) { delay(10); // 離されるまで待つ } prevBtn = HIGH; // 確実に離された状態からスタート // ======================================================= while(true){ btn = digitalRead(sb[b_no-1]); Col_palette(); if(prevBtn == HIGH && btn == LOW){ DEBUG_PRINTLN("btn is low"); break; } prevBtn = btn; delay(10); } } /***************************************** Display for Color select palette *****************************************/ void Col_palette(){ float h = 0; float s = 0; float v = 0; long RGB = 0; if(color_mode == COL_RGB){ // RGB r = Read_slide_data(SL1, slide_min_val, slide_max_val, rgb_min_val, rgb_max_val); g = Read_slide_data(SL2, slide_min_val, slide_max_val, rgb_min_val, rgb_max_val); b = Read_slide_data(SL3, slide_min_val, slide_max_val, rgb_min_val, rgb_max_val); }else if(color_mode == COL_HSV){ h = Read_slide_data(SL1, slide_min_val, slide_max_val, h_min_val, h_max_val); s = Read_slide_data(SL2, slide_min_val, slide_max_val, s_min_val, s_max_val); v = Read_slide_data(SL3, slide_min_val, slide_max_val, v_min_val, v_max_val); // Change data to RGB // hsv2Rgb(h, s, v, r, g, b); } // Check if value is more than 255 put 255 and if value is less than 0 put 0 r = constrain(r, 0, 255); g = constrain(g, 0, 255); b = constrain(b, 0, 255); // Color data change to HEX // RGB = rgb_hex(r, g, b); Col_Rect(); } /*************************************** Draw rectangle with selected color ***************************************/ void Col_Rect(){ long RGB = 0; RGB = color565(r, g, b); // Draw Colored Rectangle tft.fillRect(Rect_start_x, Rect_start_y, Rect_end_x, Rect_end_y, RGB); //tft.fillRect(5, 100, 150, 150, ILI9341_MAGENTA); // Disp Color info tft.setTextSize(2); tft.setCursor(10, 200); tft.setTextColor(ILI9341_WHITE); tft.printf("R:%d G:%d B:%d\n",(int)r, (int)g, (int)b); // tft.fillRect(Rect_start_x, Rect_start_y, Rect_end_x, Rect_end_y, ILI9341_MAGENTA); } /*************** rgb_val_check(float): if val is larger than 255 put 255 and if val is less than 0 put 0 ***************/ void rgb_val_check(float& val){ if (val > 255){ val = 255; }else if (val < 0){ val = 0; } } /************************************ Col_memory(int): ************************************/ void Col_memory(int no){ int num = 0; if (no <= 0){ return; }else{ num = no - 1; } rgbValue[num][0] = r; rgbValue[num][1] = g; rgbValue[num][2] = b; DEBUG_PRINT("num:"); DEBUG_PRINT(num); DEBUG_PRINT(" r:"); DEBUG_PRINT(r); DEBUG_PRINT(" g:"); DEBUG_PRINT(g); DEBUG_PRINT(" b:"); DEBUG_PRINTLN(b); } /***************** Live_Menu(): Lively Adjust colour using slide potentiometer *****************/ void Live_Menu() { DEBUG_PRINTLN("Live menu start\n"); // 初期化 tft.fillScreen(ILI9341_BLACK); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.setCursor(10, 10); tft.printf("[Live Menu]"); // 戻り案内 tft.setTextColor(ILI9341_GREEN); tft.setCursor(55, 100); tft.printf("when Touch the Screen\n"); tft.printf(" Back to Main\n"); // メインループ // 変化検出用の前回値 int prev_r = -1, prev_g = -1, prev_b = -1; while (!ts.touched()) { // 値を更新 Col_palette(); // 変化があるか確認 if (r != prev_r || g != prev_g || b != prev_b) { Send_data_to_led(); // 送信 prev_r = r; prev_g = g; prev_b = b; } } // タッチが離されるまで待つ(デバウンス) while (ts.touched()) { delay(10); } } /******************************* *******************************/ float Read_slide_data(int port, int from_min, int from_max, int to_min, int to_max){ float val; float retval; // Get the data val = analogRead(port); // for debug //tft.printf("val:%d ",val); // return map(val, from_min, from_max, to_min, to_max); retval = mapFloat(val, from_min, from_max, to_min, to_max); return retval; } void hsv2Rgb(float h, float s, float v, byte &r, byte &g, byte &b) { float c = v * s; // Chroma float x = c * (1 - abs(fmod(h / 60.0, 2) - 1)); float m = v - c; float r_, g_, b_; if (h < 60) { r_ = c; g_ = x; b_ = 0; } else if (h < 120) { r_ = x; g_ = c; b_ = 0; } else if (h < 180) { r_ = 0; g_ = c; b_ = x; } else if (h < 240) { r_ = 0; g_ = x; b_ = c; } else if (h < 300) { r_ = x; g_ = 0; b_ = c; } else { r_ = c; g_ = 0; b_ = x; } // 0-1 を 0-255 に変換 r = (r_ + m) * 255; g = (g_ + m) * 255; b = (b_ + m) * 255; } long rgb_hex(int r, int g, int b){ byte R, G, B; R = r; G = g; B = b; long RGB = (R << 16) | (G << 8) | B; Serial.println(RGB, HEX); return RGB; } /****************************** Col_Disp(): Color select display(top part) ******************************/ void Col_Disp(int no){ // Display tft.fillScreen(ILI9341_BLACK); //Initialise the screen (paint black) tft.setTextSize(3); //サイズ tft.setCursor(10, 10); // Cursor position tft.setTextColor(ILI9341_YELLOW); // letter color tft.printf("No: %d\n", no); tft.setTextSize(2); tft.setTextColor(ILI9341_WHITE); tft.printf("If color is OK,\npress button again\n"); } /******************** Fix_Col_Disp() ********************/ void Fix_Col_Disp(int no){ tft.fillScreen(ILI9341_BLACK); //Initialise the screen (paint black) tft.setTextSize(3); //サイズ tft.setCursor(10, 10); // Cursor position tft.setTextColor(ILI9341_YELLOW); // letter color tft.printf("No: %d ", no); tft.setTextSize(2); tft.setTextColor(ILI9341_WHITE); tft.setCursor(110, 20); tft.printf("Color is fixed!\n\n"); tft.printf(" TOUCH Screen\n Back to Main Menu"); } /*** mapFloat(from chatGPT) ***/ float mapFloat(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } /*** color565 (from chatGPT) ***/ uint16_t color565(byte r, byte g, byte b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); }