2024-06-17 12:26:39 +02:00
|
|
|
/*
|
|
|
|
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 <https://www.gnu.org/licenses/>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <LiquidCrystal_I2C.h>
|
|
|
|
|
|
|
|
// 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
|
2024-06-19 16:51:43 +02:00
|
|
|
float lastSpeed_m_min = -1; // Variable to store the last speed value
|
2024-06-17 12:26:39 +02:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
2024-06-19 16:51:43 +02:00
|
|
|
// 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");
|
|
|
|
|
2024-06-17 12:26:39 +02:00
|
|
|
// 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;
|
|
|
|
|
2024-06-19 16:51:43 +02:00
|
|
|
// 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;
|
|
|
|
}
|
2024-06-17 12:26:39 +02:00
|
|
|
|
|
|
|
// 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++;
|
|
|
|
}
|
2024-06-19 16:51:43 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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++;
|
|
|
|
}
|
|
|
|
}
|