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