#include <LiquidCrystal.
h>
// LCD pins
const int LCD_RS = 8;
const int LCD_EN = 9;
const int LCD_D4 = 4;
const int LCD_D5 = 5;
const int LCD_D6 = 6;
const int LCD_D7 = 7;
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
// Motor Driver Pins (L298)
const int IN1 = 13;
const int IN2 = 12;
const int ENA = 11; // PWM pin
// Control Buttons (active LOW)
const int Clockwise_Pin = A1;
const int AClockwise_Pin = A2;
// Potentiometer
const int POT_PIN = A0;
// Encoder
const int encoderOUT = 2;
volatile long pulseCount = 0;
// Encoder specs
const int PPR = 12;
unsigned long lastTime = 0;
float RPM = 0;
float filteredRPM = 0;
// Biến trở mượt
int smoothPot = 0;
// Thời gian đếm xung gần nhất
unsigned long lastPulseTime = 0;
void setup() {
pinMode(Clockwise_Pin, INPUT_PULLUP);
pinMode(AClockwise_Pin, INPUT_PULLUP);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(encoderOUT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(encoderOUT), countPulse, RISING);
[Link](16, 2);
[Link]("Motor+Encoder");
delay(800);
[Link]();
smoothPot = analogRead(POT_PIN);
lastTime = millis();
lastPulseTime = millis();
void loop() {
int Clockwise = digitalRead(Clockwise_Pin);
int AClockwise = digitalRead(AClockwise_Pin);
// --- Đọc và làm mượt biến trở ---
int rawPot = analogRead(POT_PIN);
smoothPot = (smoothPot * 7 + rawPot) / 8; // lọc nhiễu
int pwmVal = map(smoothPot, 0, 1023, 0, 255);
pwmVal = constrain(pwmVal, 0, 255);
if (pwmVal < 12) pwmVal = 0; // bỏ vùng chết
String direction;
if (Clockwise == LOW) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, pwmVal);
direction = "Clockwise";
} else if (AClockwise == LOW) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, pwmVal);
direction = "Anti-Clock";
} else {
// --- PHANH NHANH (BRAKE) ---
digitalWrite(IN1, HIGH);
digitalWrite(IN2, HIGH);
analogWrite(ENA, 255); // Giữ ENA HIGH để phanh nhanh
direction = "Braking";
// --- Tính RPM mỗi 200 ms ---
if (millis() - lastTime >= 200) {
noInterrupts();
long count = pulseCount;
pulseCount = 0;
interrupts();
float newRPM = 0;
if (count > 0) {
newRPM = (count * 60.0 * 1000.0) / (PPR * (millis() - lastTime));
lastPulseTime = millis();
} else {
if (millis() - lastPulseTime > 300) newRPM = 0;
filteredRPM = filteredRPM * 0.7 + newRPM * 0.3;
RPM = filteredRPM;
lastTime = millis();
// --- Hiển thị LCD ---
[Link](0, 0);
[Link]("Dir: ");
[Link](direction);
for (int i = [Link]() + 5; i < 16; i++) [Link](' ');
[Link](0, 1);
[Link]("Speed:");
[Link]((int)RPM);
[Link]("RPM ");
// Hiển thị % PWM ở góc phải
[Link](12, 1);
int percent = map(pwmVal, 0, 255, 0, 100);
if (percent < 100) [Link](' ');
[Link](percent);
[Link]("% ");
void countPulse() {
pulseCount++;
lastPulseTime = millis();