/* 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 float lastSpeed_m_min = -1; // Variable to store the last speed value // 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(); // Display fixed text on the LCD lcd.setCursor(2, 0); lcd.print("CONVEYOR SPEED"); lcd.setCursor(5, 1); lcd.print("CONTROLLER"); lcd.setCursor(5, 2); lcd.print("VELOCIDADE"); // 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 speed on the LCD only if it has changed if (speed_m_min != lastSpeed_m_min) { lcd.setCursor(5, 3); lcd.print(" "); // Clear previous value lcd.setCursor(5, 3); lcd.print(speed_m_min); lcd.print(" m/min"); // Update the last speed value lastSpeed_m_min = speed_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++; } }