CNC encoder wheel with stepper motors
In this video I show you another type of encoder wheel. In some of my previous videos, I showed how to work with a typical rotary encoder or with an absolute encoder and stepper motors. This time, I show you how to utilize the CNC encoder wheels and use them in your stepper motor projects to control the stepper motors.
Schematics
The core of the system is an STM32 blue pill, but you can use any Arduino-based microcontroller, even a Teensy! All connections are shown on the image. If you use an Arduino, make sure that you use either Pin 2 or Pin 3 as the interrupt pin for the “A” output of the encoder wheel. Also make sure that you assign the pins properly. The OLED display is a regular i2C device, so it uses the i2C pins of the microcontroller.
Encoder output signals
Channel 1 (yellow): pin A, Channel 2 (pink): pin B. The rising edge of Pin A occurs when pin B is LOW. This is the clockwise direction.
Channel 1 (yellow): pin A, Channel 2 (pink): pin B. The rising edge of Pin A occurs when pin B is HIGH. This is the counter-clockwise direction.
Arduino/STM32duino source code
#include <Wire.h> #include "SSD1306Ascii.h" #include "SSD1306AsciiWire.h" // 0X3C+SA0 - 0x3C or 0x3D #define I2C_ADDRESS 0x3C #define RST_PIN -1 SSD1306AsciiWire oled; //I2C pins: //STM32: SDA: PB7 SCL: PB6 //Arduino: SDA: A4 SCL: A5 int pinA = PB10; // Pin A of the encoder int pinB = PB11; // Pin B of the encoder //CNC Decoder behavior //CW rotation: output of B is half square wave delayed from output of A //CCW rotation: output of A is half square wave delayed from output of B //The pulse generator's output can be DIRECTLY wired to the step and dir pins. //This means that the microcontroller can be omitted!!! - of course there won't be any feedback then int numberofclicks = 0; //Stores the number of click done by the encoder. 1 turn = 100 clicks int previous_numberofclicks = 0; //Stores the "previous" number of clicks. Helps us to see if the encoder was moved float OLEDTimer = 0; //Timer for the screen refresh //--Stepper motor related---------------------------------------------------------- #include <AccelStepper.h> AccelStepper stepper(1, PA9, PA8);// pulses/steps 9; Direction 8 const int stepperEnablePin = PB12; //enable/disable pin for the stepper motor driver //remember that for Arduino, you don't need the "PA" and "PB" prefixes. Just use 1,2,3...etc. void setup() { pinMode(pinA, INPUT_PULLUP); pinMode(pinB, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(pinA), pinAInterrupt, RISING); //pin A is an interrupt Serial.begin(115200); Serial.println("CNC encoder test."); //OLED part Wire.begin(); Wire.setClock(800000L); #if RST_PIN >= 0 oled.begin(&Adafruit128x32, I2C_ADDRESS, RST_PIN); #else // RST_PIN >= 0 oled.begin(&Adafruit128x32, I2C_ADDRESS); #endif // RST_PIN >= 0 oled.setFont(Adafruit5x7); oled.clear(); // first row oled.set2X(); //double-line font size - better to read it OLEDTimer = millis(); //start the timer //Stepper setup--------------------------------------------------------- stepper.setSpeed(1000); //SPEED = Steps / second stepper.setMaxSpeed(1000); //SPEED = Steps / second stepper.setAcceleration(5000); //ACCELERATION = Steps /(second)^2 pinMode(stepperEnablePin, OUTPUT); //enable/disable pin is defined as an output digitalWrite(stepperEnablePin, LOW); //enable motor current //disabling the current can prevent the driver and the motor running hot //on the other hand, it can lead to inaccuracies because the motor is not held at place when it is not under power } void loop() { showLCD(); //if all conditions are fulfilled, the OLED is updated stepper.moveTo(numberofclicks); //Updates the "go to" position of the stepper motor - absolute value while (stepper.distanceToGo() != 0) //This blocks the rest of the code! { stepper.runSpeedToPosition(); //Runs to the target position defined by the moveTo() function //does not use accelerations } } void pinAInterrupt() { //When pin A's wave is detected... if (digitalRead(pinB) == 0) //if B is LOW, it means that pin A's wave occured first -> CW rotation occured { numberofclicks++; //increase value //Serial.println(numberofclicks); //do not use delays or prints in the final code, use it only for debugging/developing } else //if B is HIGH, it means that pin B's wave occured first. So, when pin A has a rising edge, pin B is alreadi high -> CCW rotation { numberofclicks--; //decrease value //Serial.println(numberofclicks); } } void showLCD() { if (millis() - OLEDTimer > 200) //update every 200 ms { if (previous_numberofclicks != numberofclicks) //if the encoder was moved... { oled.clear(); //delete the content of the display oled.println(numberofclicks); //print the new position OLEDTimer = millis(); //reset timer previous_numberofclicks = numberofclicks; //update current position } } else { //skip } }