Velocímetro com Sensor Óptico no ESP32 e Display SPI

Saudações a todos os forenses.

Gostaria muito de fazer um Velocímetro e/ou Tacômetro, usando um Sensor Óptico de Impressora com Display SPI e ESP32. Já tentei mesclar o código de exemplo da biblioteca do Bodmer, "Animated_dial" com um código para Tacômetro com Sensor e Display LCD 16x2 mas, por imperícia minha, não tive sucesso. Portanto, peço aqui a ajuda dos que querem e podem me ajudar. Afirmo aqui que, não é preguiça minha mas, sim, falta de conhecimento no assunto.

Percebo que o segundo código (Display LCD) não é difícil; o difícil pra mim, é adaptar o código do Bodmer (Animated_dial) pois, são linhas que não compreendo, portanto, me impossibilita de fazê-lo.

Código que tentei adaptá-lo do "Animated_dial", abaixo:

/* ILI9488 ESP32 Dial Tachometer

   Conexões dos Pinos

   TFT_MISO 19  //MISO
   TFT_MOSI 23  //MOSI
   TFT_SCK  18  //SCK
   TFT_CS   15  // Chip select control pin
   TFT_DC   16  // Data Command control pin
   TFT_RST   4  // Reset pin (could connect to RST pin)
*/

#define NEEDLE_LENGTH 35  // Visible length
#define NEEDLE_WIDTH   5  // Width of needle - make it an odd number
#define NEEDLE_RADIUS 90  // Radius at tip
#define NEEDLE_COLOR1 TFT_MAROON  // Needle periphery colour
#define NEEDLE_COLOR2 TFT_RED     // Needle centre colour
#define DIAL_CENTRE_X 120
#define DIAL_CENTRE_Y 120

// Font attached to this sketch
#include "NotoSansBold36.h"
#define AA_FONT_LARGE NotoSansBold36

#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite needle = TFT_eSprite(&tft); // Sprite object for needle
TFT_eSprite spr    = TFT_eSprite(&tft); // Sprite for meter reading

// Jpeg image array attached to this sketch
#include "dial.h"

// Include the jpeg decoder library
#include <TJpg_Decoder.h>

uint16_t* tft_buffer;
bool      buffer_loaded = false;
uint16_t  spr_width = 0;
uint16_t  bg_color = 0;
// =======================================================================================
// This function will be called during decoding of the jpeg file
// =======================================================================================
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
  // Stop further decoding as image is running off bottom of screen
  if ( y >= tft.height() ) return 0;

  // This function will clip the image block rendering automatically at the TFT boundaries
  tft.pushImage(x, y, w, h, bitmap);

  // Return 1 to decode next block
  return 1;
}

unsigned long lastflash;
int RPM;
void ICACHE_RAM_ATTR sens() {
  RPM++;
}

// =======================================================================================
// Setup
// =======================================================================================
void setup()   {
  Serial.begin(115200); // Debug only

  // The byte order can be swapped (set true for TFT_eSPI)
  TJpgDec.setSwapBytes(true);

  // The jpeg decoder must be given the exact name of the rendering function above
  TJpgDec.setCallback(tft_output);

  tft.begin();
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);

  // IR Infrared sensor
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), sens, RISING);
  //SENSOR: GPIO0 (NodeMCU - D3)

  // Draw the dial
  TJpgDec.drawJpg(0, 0, dial, sizeof(dial));
  tft.drawCircle(DIAL_CENTRE_X, DIAL_CENTRE_Y, NEEDLE_RADIUS - NEEDLE_LENGTH, TFT_DARKGREY);

  // Load the font and create the Sprite for reporting the value
  spr.loadFont(AA_FONT_LARGE);
  spr_width = spr.textWidth("777"); // 7 is widest numeral in this font
  spr.createSprite(spr_width, spr.fontHeight());
  bg_color = tft.readPixel(120, 120); // Get colour from dial centre
  spr.fillSprite(bg_color);
  spr.setTextColor(TFT_WHITE, bg_color, true);
  spr.setTextDatum(MC_DATUM);
  spr.setTextPadding(spr_width);
  spr.drawNumber(0, spr_width / 2, spr.fontHeight() / 2);
  spr.pushSprite(DIAL_CENTRE_X - spr_width / 2, DIAL_CENTRE_Y - spr.fontHeight() / 2);

  // Plot the label text
  tft.setTextColor(TFT_WHITE, bg_color);
  tft.setTextDatum(MC_DATUM);
  tft.drawString("(degrees)", DIAL_CENTRE_X, DIAL_CENTRE_Y + 48, 2);

  // Define where the needle pivot point is on the TFT before
  // creating the needle so boundary calculation is correct
  tft.setPivot(DIAL_CENTRE_X, DIAL_CENTRE_Y);

  // Create the needle Sprite
  createNeedle();

  // Reset needle position to 0
  plotNeedle(0, 0);

  delay(2000);
}

// =======================================================================================
// Loop
// =======================================================================================
void loop() {
  noInterrupts();
  int wings = 3; //no of wings of rotating object, for disc object use 1 with white tape on one side
  int RPMnew = RPM / wings; //here we used fan which has 3 wings
  Serial.print(RPMnew);
  Serial.print(" Rot/sec :");  //Revolutions per second
  Serial.print((RPMnew * 60));
  Serial.println("Rot/min. ");   //Revolutions per minute
  RPM = 0;
  interrupts();
  delay(1000);  //1 second
}

// =======================================================================================
// Create the needle Sprite
// =======================================================================================
void createNeedle(void)
{
  needle.setColorDepth(16);
  needle.createSprite(NEEDLE_WIDTH, NEEDLE_LENGTH);  // create the needle Sprite

  needle.fillSprite(TFT_BLACK); // Fill with black

  // Define needle pivot point relative to top left corner of Sprite
  uint16_t piv_x = NEEDLE_WIDTH / 2; // pivot x in Sprite (middle)
  uint16_t piv_y = NEEDLE_RADIUS;    // pivot y in Sprite
  needle.setPivot(piv_x, piv_y);     // Set pivot point in this Sprite

  // Draw the red needle in the Sprite
  needle.fillRect(0, 0, NEEDLE_WIDTH, NEEDLE_LENGTH, TFT_MAROON);
  needle.fillRect(1, 1, NEEDLE_WIDTH - 2, NEEDLE_LENGTH - 2, TFT_RED);

  // Bounding box parameters to be populated
  int16_t min_x;
  int16_t min_y;
  int16_t max_x;
  int16_t max_y;

  // Work out the worst case area that must be grabbed from the TFT,
  // this is at a 45 degree rotation
  needle.getRotatedBounds(45, &min_x, &min_y, &max_x, &max_y);

  // Calculate the size and allocate the buffer for the grabbed TFT area
  tft_buffer =  (uint16_t*) malloc( ((max_x - min_x) + 2) * ((max_y - min_y) + 2) * 2 );
}

// =======================================================================================
// Move the needle to a new position
// =======================================================================================
void plotNeedle(int16_t angle, uint16_t ms_delay)
{
  static int16_t old_angle = -120; // Starts at -120 degrees

  // Bounding box parameters
  static int16_t min_x;
  static int16_t min_y;
  static int16_t max_x;
  static int16_t max_y;

  if (angle < 0) angle = 0; // Limit angle to emulate needle end stops
  if (angle > 240) angle = 240;

  angle -= 120; // Starts at -120 degrees

  // Move the needle until new angle reached
  while (angle != old_angle || !buffer_loaded) {

    if (old_angle < angle) old_angle++;
    else old_angle--;

    // Only plot needle at even values to improve plotting performance
    if ( (old_angle & 1) == 0)
    {
      if (buffer_loaded) {
        // Paste back the original needle free image area
        tft.pushRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer);
      }

      if ( needle.getRotatedBounds(old_angle, &min_x, &min_y, &max_x, &max_y) )
      {
        // Grab a copy of the area before needle is drawn
        tft.readRect(min_x, min_y, 1 + max_x - min_x, 1 + max_y - min_y, tft_buffer);
        buffer_loaded = true;
      }

      // Draw the needle in the new position, black in needle image is transparent
      needle.pushRotated(old_angle, TFT_BLACK);

      // Wait before next update
      delay(ms_delay);
    }

    // Update the number at the centre of the dial
    spr.setTextColor(TFT_WHITE, bg_color, true);
    spr.drawNumber(old_angle + 120, spr_width / 2, spr.fontHeight() / 2);
    spr.pushSprite(120 - spr_width / 2, 120 - spr.fontHeight() / 2);

    // Slow needle down slightly as it approaches the new position
    if (abs(old_angle - angle) < 10) ms_delay += ms_delay / 5;
  }
}

Código do Display LCD 16x2, abaixo:

//DIY Tachometer to Measure Accurate RPM using ESP32
//This code is published by https://www.circuitschools.com
//Attribution required to republish.

#include <LiquidCrystal_I2C.h>

// Create the lcd object address 0x3F and 16 columns x 2 rows
LiquidCrystal_I2C lcd (0x27, 16, 2); //

unsigned long lastflash;
int RPM;
void ICACHE_RAM_ATTR sens() {
  RPM++;
}

void setup() {
  Serial.begin(9600);
  lcd. init ();

  // Turn on the backlight on LCD.
  lcd. backlight ();

  // IR Infrared sensor
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), sens, RISING);
  //SENSOR: GPIO0 (NodeMCU - D3)
}

void loop() {
  noInterrupts();
  int wings = 3; // no of wings of rotating object, for disc object use 1 with white tape on one side
  int RPMnew = RPM / wings; //here we used fan which has 3 wings
  Serial.print(RPMnew);
  Serial.print(" Rot/sec :");  //Revolutions per second
  lcd.clear();
  lcd.print(RPMnew);
  lcd.print("Rot/sec");
  Serial.print((RPMnew * 60));
  Serial.println("Rot/min. ");   //Revolutions per minute
  lcd. setCursor (0, 1);
  lcd.print(RPMnew * 60);
  lcd.print("Rot/min");
  RPM = 0;
  interrupts();
  delay(1000);  //1 second.
}

Observe que eu quero usar o código do Display LCD mas, não usar o Display LCD mas, sim, o Display TFT para mostrar o Velocímetro (Dial).

Me desculpem e me corrijam, se errei e/ou faltei com alguma coisa.

Meus antecipados agradecimentos.

Daniel Fernandes

Alguém que esteja disponível a me ajudar? Ou, até mesmo, transferir esse tópico para o fórum em inglês, no qual, a comunidade é maior?!

Pergunte a @PerryBebbington, moderador do fórum internacional, (eu acho).

Eu não sou o moderador de português, se você deseja chamar a atenção de um moderador para algo, por favor use a bandeira no final de cada resposta. Obrigado

Obrigado Perry e gonpezzi; já o fiz.

Ao gonpezzi e ao Perry, quando eu disse: já o fiz, eu quis dizer que enviei uma mensagem, clicando na bandeira, no final do post (como me instruiu o Perry), pedindo que a minha postagem fosse transferida para o tópico em Inglês mas, até agora, ninguém me respondeu. Será que é tão difícil assim? Aqui mesmo, nesse tópico, em Português, será que não tem alguém que me possa sugerir e/ou me ajudar sobre o assunto? Fico no aguardo. Obrigado

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.