🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    M5Stack Gauges for Boats

    Scheduled Pinned Locked Moved PROJECTS
    3 Posts 3 Posters 7.0k Views 1 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Hans-J.
      last edited by

      Hello,

      this is my first post in this forum. I am pretty new to this product and not very experienced in Arduino programing. So I need your help in order to finalize my project. I do need several gauges for my boat. So I decided to try the M5Stack which allows me to display 3 different gauges on one display by simply pressing one of the three buttons. As a start I used the example "TFT_Meter_linear". So far the functionality is given. However, I would like to rotate the scale and the pointer. The command "tft.setRotation()" doesn't do it. I would appreciate if someone could give me a hint on which values I have to manipulate in order to get the desired result. I have attached a picture of the current and the required display as well as the code

      Best regards
      0_1618302186104_Rudder.JPG image url)

       
       
       An example analogue meter using a ILI9341 TFT LCD screen
      
       Needs Font 2 (also Font 4 if using large scale label)
      
       Make sure all the display driver and pin comnenctions are correct by
       editting the User_Setup.h file in the TFT_eSPI library folder.
      
       #########################################################################
       ###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
       #########################################################################
       
      Updated by Bodmer for variable meter size
       */
      
      // Define meter size as 1 for M5.Lcd.rotation(0) or 1.3333 for M5.Lcd.rotation(1)
      #define M_SIZE 1.3333
      
      #include <M5Stack.h>
      
      #define ADC_Calibration_Value1 250.0 // For resistor measure 5 Volt and 180 Ohm equals 100% plus 1K resistor.
      #define ADCpin1 35  // Potentiometer is connected to GPIO 35 (Analog ADC1_CH7) 
      // add a 1k Resistor from pin 35 to +5V and a Diode from GND to pin 35 (Cathode)
      // a 10µf cap from GND to pin 35 may reduce a noisy needle
      
      #define TFT_GREY 0x5AEB
      
      float ltx = 0;    // Saved x coord of bottom of needle
      uint16_t osx = M_SIZE*120, osy = M_SIZE*120; // Saved x & y coords
      uint32_t updateTime = 0;       // time for next update
      
      int old_analog =  -999; // Value last displayed
      
      int value[6] = {0, 0, 0, 0, 0, 0};
      int old_value[6] = { -1, -1, -1, -1, -1, -1};
      int d = 0;
      
      // variable for storing the potentiometer value
      int potValue = 0;
      
      void setup(void) {
        M5.begin();
        M5.Power.begin();
        // M5.Lcd.setRotation(1);
        // Serial.begin(57600); // For debug
        M5.Lcd.fillScreen(TFT_BLACK);
      
        analogMeter(); // Draw analogue meter
      
        updateTime = millis(); // Next update time
      
      }
      
      //*****************************************************************************
      // ReadADC is used to improve the linearity of the ESP32 ADC see: https://github.com/G6EJD/ESP32-ADC-Accuracy-Improvement-function
      double ReadADC(byte pin) {
        double reading = analogRead(pin); // Reference voltage is 3v3 so maximum reading is 3v3 = 4095 in range 0 to 4095
        if (reading < 1 || reading > 4095) return 0;
        // return -0.000000000009824 * pow(reading,3) + 0.000000016557283 * pow(reading,2) + 0.000854596860691 * reading + 0.065440348345433;
        return (-0.000000000000016 * pow(reading, 4) + 0.000000000118171 * pow(reading, 3) - 0.000000301211691 * pow(reading, 2) + 0.001109019271794 * reading + 0.034143524634089) * 1000;
      } 
      // Added an improved polynomial, use either, comment out as required
      
      void loop() {
      
        potValue = ReadADC(ADCpin1) * ADC_Calibration_Value1 / 4096;
      
       Serial.print(ReadADC(ADCpin1));                   // print raw value
       Serial.print(" ");                                // tab
       Serial.println(potValue);                         // print final value 
       
       delay(200); // to smoothen the pointer
      
        
        plotNeedle(potValue, 0);
      
      }
      
      // #########################################################################
      //  Draw the analogue meter on the screen
      // #########################################################################
      void analogMeter()
      {
      
        // Meter outline
        M5.Lcd.fillRect(0, 0, M_SIZE*239, M_SIZE*126, TFT_GREY);
        M5.Lcd.fillRect(5, 3, M_SIZE*230, M_SIZE*119, TFT_WHITE);
      
        M5.Lcd.setTextColor(TFT_BLACK);  // Text colour
      
        // Draw ticks every 5 degrees from -50 to +50 degrees (100 deg. FSD swing)
        for (int i = -50; i < 51; i += 5) {
          // Long scale tick length
          int tl = 15;
      
          // Coodinates of tick to draw
          float sx = cos((i - 90) * 0.0174532925);
          float sy = sin((i - 90) * 0.0174532925);
          uint16_t x0 = sx * (M_SIZE*100 + tl) + M_SIZE*120;
          uint16_t y0 = sy * (M_SIZE*100 + tl) + M_SIZE*140;
          uint16_t x1 = sx * M_SIZE*100 + M_SIZE*120;
          uint16_t y1 = sy * M_SIZE*100 + M_SIZE*140;
      
          // Coordinates of next tick for zone fill
          float sx2 = cos((i + 5 - 90) * 0.0174532925);
          float sy2 = sin((i + 5 - 90) * 0.0174532925);
          int x2 = sx2 * (M_SIZE*100 + tl) + M_SIZE*120;
          int y2 = sy2 * (M_SIZE*100 + tl) + M_SIZE*140;
          int x3 = sx2 * M_SIZE*100 + M_SIZE*120;
          int y3 = sy2 * M_SIZE*100 + M_SIZE*140;
      
          // Green zone limits
          if (i >= -50 && i < 0) {
            M5.Lcd.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_GREEN);
            M5.Lcd.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_GREEN);
          }
      
          // Red zone limits
          if (i >= 0 && i <50) {
            M5.Lcd.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_RED);
            M5.Lcd.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_RED);
          }
      
          // Short scale tick length
          if (i % 25 != 0) tl = 8;
      
          // Recalculate coords incase tick lenght changed
          x0 = sx * (M_SIZE*100 + tl) + M_SIZE*120;
          y0 = sy * (M_SIZE*100 + tl) + M_SIZE*140;
          x1 = sx * M_SIZE*100 + M_SIZE*120;
          y1 = sy * M_SIZE*100 + M_SIZE*140;
      
          // Draw tick
          M5.Lcd.drawLine(x0, y0, x1, y1, TFT_BLACK);
      
          // Check if labels should be drawn, with position tweaks
          if (i % 25 == 0) {
            // Calculate label positions
            x0 = sx * (M_SIZE*100 + tl + 10) + M_SIZE*120;
            y0 = sy * (M_SIZE*100 + tl + 10) + M_SIZE*140;
            switch (i / 25) {
              case -2: M5.Lcd.drawCentreString("40", x0, y0 - 12, 2); break;
              case -1: M5.Lcd.drawCentreString("20", x0, y0 - 9, 2); break;
              case 0: M5.Lcd.drawCentreString("CTR", x0, y0 - 7, 2); break;
              case 1: M5.Lcd.drawCentreString("20", x0, y0 - 9, 2); break;
              case 2: M5.Lcd.drawCentreString("40", x0, y0 - 12, 2); break;
            }
          }
      
          // Now draw the arc of the scale
          sx = cos((i + 5 - 90) * 0.0174532925);
          sy = sin((i + 5 - 90) * 0.0174532925);
          x0 = sx * M_SIZE*100 + M_SIZE*120;
          y0 = sy * M_SIZE*100 + M_SIZE*140;
          // Draw scale arc, don't draw the last part
          if (i < 50) M5.Lcd.drawLine(x0, y0, x1, y1, TFT_BLACK);
        }
      
        M5.Lcd.drawString("Port", M_SIZE*(5 + 230 - 40), M_SIZE*(119 - 20), 2); // Label at bottom right
        M5.Lcd.drawString("STBD", M_SIZE*(5 + 60 - 40), M_SIZE*(119 - 20), 2); // Label at bottom left
        M5.Lcd.drawCentreString("Rudder", M_SIZE*120, M_SIZE*70, 4); // Comment out to avoid font 4
        M5.Lcd.drawRect(5, 3, M_SIZE*230, M_SIZE*119, TFT_BLACK); // Draw bezel line
      
        plotNeedle(0, 0); // Put meter needle at 0
      }
      
      // #########################################################################
      // Update needle position
      // This function is blocking while needle moves, time depends on ms_delay
      // 10ms minimises needle flicker if text is drawn within needle sweep area
      // Smaller values OK if text not in sweep area, zero for instant movement but
      // does not look realistic... (note: 100 increments for full scale deflection)
      // #########################################################################
      void plotNeedle(int value, byte ms_delay)
      {
      
        if (value < -10) value = -10; // Limit value to emulate needle end stops
        if (value > 110) value = 110;
      
        // Move the needle until new value reached
        while (!(value == old_analog)) {
          if (old_analog < value) old_analog++;
          else old_analog--;
      
          if (ms_delay == 0) old_analog = value; // Update immediately if delay is 0
      
          float sdeg = map(old_analog, -10, 110, -150, -30); // Map value to angle
          // Calcualte tip of needle coords
          float sx = cos(sdeg * 0.0174532925);
          float sy = sin(sdeg * 0.0174532925);
      
          // Calculate x delta of needle start (does not start at pivot point)
          float tx = tan((sdeg + 90) * 0.0174532925);
      
          // Erase old needle image
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx - 1), M_SIZE*(140 - 20), osx - 1, osy, TFT_WHITE);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_WHITE);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_WHITE);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_WHITE);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_WHITE);
      
          // Re-plot text under needle
          M5.Lcd.setTextColor(TFT_BLACK);
          M5.Lcd.drawCentreString("Rudder", M_SIZE*120, M_SIZE*70, 4); // // Comment out to avoid font 4
      
          // Store new needle end coords for next erase
          ltx = tx;
          osx = M_SIZE*(sx * 98 + 120);
          osy = M_SIZE*(sy * 98 + 140);
      
          // Draw the needle in the new postion, magenta makes needle a bit bolder
          // draws 5 lines to thicken needle
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx - 1), M_SIZE*(140 - 20), osx - 1, osy, TFT_RED);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_MAGENTA);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_RED);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_MAGENTA);
          M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_RED);
      
          // Slow needle down slightly as it approaches new postion
          if (abs(old_analog - value) < 10) ms_delay += ms_delay / 5;
      
          // Wait before next update
          delay(ms_delay);
        }
      }
      ``
      1 Reply Last reply Reply Quote 0
      • A Offline
        AndyT
        last edited by

        Sorry can't help your question. But would like to thank you for your code. Which i have adapted to display temperatures.

        1 Reply Last reply Reply Quote 0
        • M Offline
          macsbug
          last edited by

          Add the following to void loop ().

          void loop() {
          M5.update();
          if(M5.BtnA.wasPressed()){M5.Lcd.setRotation(3);M5.Lcd.fillScreen(TFT_BLACK);analogMeter();}
          if(M5.BtnC.wasPressed()){M5.Lcd.setRotation(1);M5.Lcd.fillScreen(TFT_BLACK);analogMeter();}

          1 Reply Last reply Reply Quote 0

          Hello! It looks like you're interested in this conversation, but you don't have an account yet.

          Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

          With your input, this post could be even better 💗

          Register Login
          • First post
            Last post