#include <PID_v2.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
int hallSensorPin = 3;
volatile int hallState = LOW;
volatile int lastHallState = LOW;
const int pwmPin = 11;
const int hallSensorPulsesPerRotation = 15;
double rpm;
double kp = 1, Ki = 0, Kd = 0;
double setpoint =120, input, output;
PID myPID(&input, &output, &setpoint, kp, Ki, Kd, DIRECT);
volatile unsigned long hallSensorCounter = 0;
unsigned long previousRisingEdgeTime = 0;
volatile unsigned long Interrupts = 0;
volatile unsigned long timeSinceLastRisingEdge;
unsigned long previousMillis = 0;
void hallSensorInterrupt() {
hallState = digitalRead(hallSensorPin);
if (hallState == HIGH) {
// A rising edge (north-to-south) has been detected for the first Hall sensor
Interrupts++;
}
}
void setup() {
Serial.begin(9600);
pinMode(hallSensorPin, INPUT_PULLUP);
pinMode(pwmPin, OUTPUT);
lcd.init(); // I2C
lcd.backlight();
lcd.clear();
attachInterrupt(digitalPinToInterrupt(hallSensorPin), hallSensorInterrupt, CHANGE);
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 255);
}
void loop() {
unsigned long currentMillis = millis();
if ((currentMillis - previousRisingEdgeTime) > 1000) {
timeSinceLastRisingEdge = currentMillis - previousRisingEdgeTime;
previousRisingEdgeTime = currentMillis;
double pulsesPerSecond = (1000.0*Interrupts) / timeSinceLastRisingEdge;
rpm = (pulsesPerSecond*60.0)/hallSensorPulsesPerRotation;
myPID.Compute();
analogWrite(pwmPin, output);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("RPM: ");
lcd.print(rpm);
lcd.setCursor(0, 1);
lcd.print("pwm:");
lcd.print(output);
Interrupts = 0;
previousRisingEdgeTime = currentMillis;
}
}