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
Encoder output signals
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 } }