กลับไปหน้ารวมไฟล์
rpm-meter-with-hall-effect-square-encoder-sensors-a3ef1b-en.md

This project consists of using Hall effect sensors to determine the turning direction and RPMs of a DC motor. In this case 2 motors at the same time.

With the use of external interruptions, the state of the sensors 1 of each pair is determined, and with this the state of the sensors 2 placed at four (90 degrees) is registered and by means of the code determine if the direction of rotation of each motor. In addition to internal interruptions (Timer1), the period time is calculated to determine the frequency (Turns per second) and the RPM of each motor.

On each motor shaft, I have improvised an encoder with neodymium magnets.

To control the direction of rotation of each motor, I use op amps (LM324N) with a joystick and a driver (L293N and L298N).

To digitize the analog signal from each sensor I use op amps as comparators.

Last but not least, I have used a Schmitt Trigger Inverter (SN74LS14N) to nullify the transient effect of each sensor, thus avoiding false readings and thus obtaining with sufficient precision the revolutions and direction of rotation of each motor.

I use the ATmega32u4 (Beatle BadUSB) microcontroller as Arduino Leonardo, however the code is usable on most types of arduino.

The display is a ST7735 of 128x128 pixels with SPI bus, easy to use.

Technical Deep-Dive

This project, "Mag-Tach," is a masterclass in Magnetic Sensing Forensics and Signal Integrity. While standard RPM meters use single-pulse IR sensors, this project utilizes a dual-channel Quadrature Hall Effect architecture. By mapping the magnetic flux of neodymium magnets through linear sensors and conditioning the signal with Schmitt triggers, Mag-Tach extracts both the scalar magnitude (RPM) and the vector direction (+/-) of two concurrent DC motors, providing high-fidelity telemetry for robotics and propulsion systems.

  • Quadrature Encoding Forensics:
    • The 90-Degree Phase Shift: Two Hall effect sensors (KY-035) are positioned at a 90-degree spatial interval relative to the magnetic poles, as shown in the first image. This creates two square waves (Channel A and B) that are phase-shifted.
    • Vector Direction Logic: By monitoring which channel triggers its FALLING edge first, the ATmega32U4 determines the rotational vector. If A leads B, the motor is CW (+); if B leads A, the motor is CCW (-).
  • Signal Conditioning & Noise Nullification:
    • The Schmitt Trigger (SN74LS14N): Hall effect sensors often produce transient "jitter" at the edge of magnetic attraction. This project utilizes a Schmitt trigger with Hysteresis to digitize the analog signal. This ensures that the interrupt pins only see "Clean" square waves, eliminating false triggers caused by magnetic noise.
    • Op-Amp Comparison: The LM324N, shown in the second image, serves as a high-speed comparator, transforming the linear analog voltage from the Hall sensors into logic-level transitions required by the Schmitt trigger.
  • Timer1 Frequency Extraction:
    • Period-Based Measurement: Instead of counting pulses per second (which is inaccurate at low RPM), Mag-Tach measures the time between pulses using the TimerOne library. By calculating the reciprocal of the period, the system achieves near-instantaneous RPM updates even during slow starts or rapid decelerations.

Engineering & Implementation

  • Interrupt-Driven Architecture:
    • High-speed tachometry requires non-blocking logic. The project utilizes attachInterrupt on pins 2 and 3 to handle the motor A/B pulses. This allows the primary CPU loop to focus on rendering the ST7735 TFT graphics while the hardware handles the millisecond-accurate timing in the background.
  • Visual Data Analytics (ST7735):
    • The 128x128 color display is utilized for Live Bar Graphs, as seen in the final image. The code maps the rpm value to a visual Y-axis, providing a real-time analog-style representation of motor performance alongside the digital RPM readout.
  • Atomic Data Protection:
    • To prevent "Race Conditions" where the main loop reads a multi-byte variable while an interrupt is updating it, the code utilizes the ATOMIC() block. This ensures data integrity by temporarily disabling interrupts during the RPM math calculation.

Conclusion

Mag-Tach represents a significant leap in Propulsion Telemetry. By mastering the synthesis of Quadrature Phase Logic, Hysteresis-based Debouncing, and Atomic Data Management, developers can build industrial-grade encoders for mission-critical robotic platforms.


Vector Precision: Mastering rotational forensics through magnetic quadrature.

In the following video you can see the operation and testing of the code:

/*
RPM Meter Direction
Use Square Encoder with Hall effect sensors
By DrakerDG (c)
https://www.youtube.com/user/DrakerDG
*/
#include <SPI.h>
#include <TFT_ST7735.h>
#include <SimplyAtomic.h>
#include <TimerOne.h>
#define	 GREEN 0x07E0
#define YELLOW 0x07FF
#define DC A0 //9
#define RS A1 //10
#define CS A2 //11
// Sensor pins
const byte PinX[4] = {2, 3, 10, 11};
// Limit of microseconds
const long uSeg = 100000;
// Left position RPM labels
const byte x1 = 75;
// Pulse timer counters
volatile unsigned long pwc[2];
// PWM periods
volatile unsigned long pwm[2];
// RPM values
unsigned long rpm[2];
// States of the second sensors
volatile bool Sen[2];
// Count variable printing millis
unsigned long prT = 0;
TFT_ST7735 tft = TFT_ST7735(CS, DC, RS);
void CountSA(void);
void CountSB(void);
void RPMc(void);
void Draw_Table(void);
void Print_Data(void);
void setup(){
 Serial.begin(9600);
 tft.begin();
 tft.setRotation(1);
 tft.clearScreen();
 tft.setTextWrap(true);
 tft.setTextColor(YELLOW, BLACK);
 tft.setCursor(0, 0);
 Draw_Table();
 for (byte i=0; i<4; i++){
   pinMode(PinX[i], INPUT);
   }
 for (byte i=0; i<2; i++){
   pwc[i] = uSeg;
   pwm[i] = uSeg;
   rpm[i] = 0;
 }
 // Interrupt to count period time
 Timer1.initialize(100);
 Timer1.attachInterrupt(RPMc);
 // Interrupt of Sensor 1 of Motor A
 attachInterrupt(digitalPinToInterrupt(PinX[0]), CountSA, FALLING);
 // Interrupt of Sensor 1 of Motor B
 attachInterrupt(digitalPinToInterrupt(PinX[1]), CountSB, FALLING);
}
void loop(){
 Print_Data();
}
void CountSA(){
 // 2nd sensor value
 Sen[0] = 1 & (PINB >> 7); 
 pwm[0] = pwc[0]; // Save the period
 pwc[0] = 0; // Reset the timer
}
void CountSB(){
 // 2nd sensor value
 Sen[1] = 1 & (PINB >> 6);
 pwm[1] = pwc[1]; // Save the period
 pwc[1] = 0; // Reset the timer
}
void RPMc(){
 for (byte i=0; i<2; i++){
   // Increase the time counter
   pwc[i]++;
   if (pwc[i] > (uSeg)){
     // Limit the timer & period
     pwc[i] = uSeg;
     pwm[i] = uSeg;
   }
 }  
}
void Draw_Table(){
 // Code to draw the table on screen
 tft.drawFastVLine(22, 0, 128, WHITE);
 for ( int i=0; i<11; i+=1 ){
   tft.drawFastHLine( 20, 5+i*12, 4, WHITE);
   if (!(i&1)){
     tft.setCursor( 0, i*12 + 2);
     tft.print((10.0-i)*0.5, 1);
     }
   }
 tft.drawFastHLine( 20, 125, 128, WHITE);
 tft.setTextSize(1);
 tft.setCursor(x1, 10);
 tft.print("Motor A");
 tft.setCursor(x1+30, 45);
 tft.print("RPM");
 tft.setCursor(x1, 70);
 tft.print("Motor B");
 tft.setCursor(x1+30, 105);
 tft.print("RPM");
 tft.setTextSize(2);
}
void Print_Data(){
 unsigned long nwT = millis();
 // Calculations and prints every 10ms
 if ((nwT - prT) > 10){
   prT = nwT;
   char sRPM[10];
   for (byte i=0; i<2; i++){
     //RPM
     tft.setCursor(x1, 25+60*i);
     // Protects math calculation
     ATOMIC()
     {
       // Detect Rotation Decrease
       if (pwc[i]>(pwm[i]*2)){
         pwm[i] *= 2;
         pwm[i] = constrain(pwm[i], 0, uSeg);
         pwc[i] = pwc[i]*2;
       }
       /* detects or not the
       rotation of the motors */
       if (pwm[i] < uSeg) rpm[i] = 6*uSeg/pwm[i]; // Detects rotation
       else if ((rpm[i] > 0)&&(pwm[i] == uSeg)) rpm[i] = int(rpm[i]/2); // No rotatiom
       // Limits the value of RPMs
       rpm[i] = constrain(rpm[i], 0, 9999);
     }
     dtostrf(rpm[i], 4, 0, sRPM);
     // Print the RPMs
     tft.print(sRPM);
     int valX = rpm[i]*120/500;
     // Prints the RPM bars
     tft.fillRect(30+15*i, 0, 10, 125 - valX, BLACK);
     tft.fillRect(30+15*i, 125 - valX, 10, valX, GREEN);
     tft.setCursor(x1-15, 25+60*i);
     /* Determines the direction
     of rotation of the motors.
     Prints + if it turns CW and
     - if it turns CCW */
     if ((rpm[i] == 0)&&(pwm[i] == uSeg)) tft.print(" ");
     else if (Sen[i]) tft.print("-");
     else tft.print("+");
     }
   }
}
Video of the tests
Two Hall effect sensors placed in quadrature
Quadruple operational amplifier (LM324N) to digitalize the analog signal of each sensor
Quadruple operational amplifier (LM324N) to control the movement of the motors
Driever to control the two motors (L293N)
Direction of rotation indicator (+/-) and RPM of the two DC motors

ข้อมูล Frontmatter ดั้งเดิม

apps:
  - "Arduino IDE"
  - "TimerOne Library"
author: "drakerdg"
category: "Robots"
components:
  - "1x ATmega32U4 (Arduino Leonardo / Beetle Host)"
  - "4x KY-035 Linear Hall Effect Sensors (Quadrature Node)"
  - "4x Neodymium Magnets (Magnetic Encoding Media)"
  - "1x SN74LS14N Schmitt Trigger Inverter (Noise Nullification)"
  - "2x LM324N Quad Op-Amps (Signal Comparison & Control)"
  - "1x ST7735 1.8\" Color TFT (Visual Data Analytics)"
  - "1x L293D Dual H-Bridge Driver (Actuation Node)"
  - "1x DSO138 Oscilloscope (Diagnostic Tool)"
description: "A dual-motor tachometry system that utilizes quadrature Hall effect mapping, Schmitt trigger debouncing, and Timer1 frequency forensics to measure real-time RPM and rotational direction with industrial precision."
difficulty: "Intermediate"
documentationLinks: []
downloadableFiles:
  - "https://github.com/DrakerDG/RPM_Meter_Direction_V3"
  - "https://github.com/DrakerDG/RPM_Meter_Direction_V3"
encryptedPayload: "U2FsdGVkX1/iR3hJ/9dWDESayDLQcsSHVPjtaUyqXkYUHNhz1kcIakwe533cgMCghkv2MdF3F4QCaXsW2rHcra14/FD/c14/rjWpuQ4WaLw="
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/rpm-meter-with-hall-effect-square-encoder-sensors-a3ef1b_cover.gif"
lang: "en"
likes: 3
passwordHash: "e2427876bc9462f5ffed5723cfbaedc7e83504d799a8a8c857be232216ecfcb9"
price: 699
seoDescription: "Measure RPM and rotation direction using KY-035 Hall Effect Square Encoder Sensors for your Arduino projects."
tags:
  - "hall-effect-sensors"
  - "quadrature-encoding"
  - "tachometry"
  - "signal-conditioning"
  - "schmitt-trigger"
  - "rpm-monitoring"
title: "RPM Meter with Hall Effect Square Encoder Sensors"
tools:
  - "Digital Oscilloscope"
  - "Breadboard & Protoshield"
videoLinks:
  - "https://www.youtube.com/embed/lOM5GylRBGY"
views: 5783