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 …

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 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.

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
	}
}

Previous
Previous

AS5600 magnetic position encoder

Next
Next

Testing a capacitive proximity sensor