diff --git a/tachometer_v0.ino b/tachometer_v0.ino
new file mode 100644
index 0000000..a50f8fd
--- /dev/null
+++ b/tachometer_v0.ino
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2024, Pablo César Galdo Regueiro.
+ info.wokwi(at)pcgaldo.com
+
+ Project in editing process. Operation may be limited.
+
+ License
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+*/
+
+#include
+
+// LCD configuration
+#define I2C_ADDR 0x3F
+#define LCD_COLUMNS 20
+#define LCD_LINES 4
+
+LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
+
+// Encoder input pins
+#define ENCODER_CLK 2
+#define ENCODER_DT 3
+
+// Global variables
+volatile long counter = 0; // Counter for encoder pulses
+unsigned long lastTime = 0; // To store the last time when RPM was calculated
+unsigned long currentTime = 0; // To store the current time
+float rpm = 0; // Variable to store the RPM value
+float speed_m_min = 0; // Variable to store the speed in meters per minute
+
+// Constants for encoder and roller
+const int pulsesPerRevolution = 1000; // Pulses per revolution of the encoder
+const float rollerDiameter = 100.0; // Diameter of the roller in mm
+
+void setup() {
+ // Set up encoder pins as input with internal pull-up resistors
+ pinMode(ENCODER_CLK, INPUT_PULLUP);
+ pinMode(ENCODER_DT, INPUT_PULLUP);
+
+ // Initialize the LCD
+ lcd.init();
+ lcd.backlight();
+
+ // Set up interrupts for encoder signal changes
+ attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), ai0, CHANGE);
+ attachInterrupt(digitalPinToInterrupt(ENCODER_DT), ai1, CHANGE);
+
+ // Initialize the time reference
+ lastTime = millis();
+}
+
+void loop() {
+ // Calculate RPM and speed every second
+ currentTime = millis();
+ if (currentTime - lastTime >= 1000) {
+ // Calculate RPM: (counter * 60) / (pulses per revolution)
+ rpm = (counter * 60.0) / pulsesPerRevolution;
+
+ // Calculate speed in m/min: (RPM * π * diameter) / 1000
+ speed_m_min = (rpm * 3.14159 * rollerDiameter) / 1000.0;
+
+ // Reset counter for the next measurement
+ counter = 0;
+
+ // Display RPM and speed on the LCD
+ lcd.clear();
+ lcd.setCursor(4, 0);
+ lcd.print("EGURKO SPEED");
+ lcd.setCursor(5, 1);
+ lcd.print("CONTROLLER");
+ lcd.setCursor(5, 2);
+ lcd.print("VELOCIDADE");
+ lcd.setCursor(5, 3);
+ lcd.print(speed_m_min);
+ lcd.print(" m/min");
+
+ // Update the last time reference
+ lastTime = currentTime;
+ }
+}
+
+// Interrupt service routine for encoder channel A
+void ai0() {
+ // If both signals are the same, the encoder is rotating forward
+ if (digitalRead(ENCODER_CLK) == digitalRead(ENCODER_DT)) {
+ counter++;
+ }
+}
+
+// Interrupt service routine for encoder channel B
+void ai1() {
+ // If both signals are different, the encoder is rotating forward
+ if (digitalRead(ENCODER_CLK) != digitalRead(ENCODER_DT)) {
+ counter++;
+ }
+}