Is it possible to mimic a rotary encoder with an arduino?

Is it possible to mimic a rotary encoder with an arduino?

I have device I wish to hack, I want to write a program that will have the same effect as turning the dial 1 click at a time.

Looking originally for tutorial on this subject and found nothing. I found tons of "hack a button" tutorials which seem close, but nowhere anywhere close to a rotary encoder

Indubitably.

1 Like

Some really handy stuff there and I take it what I should be searching for is Quadrature Encoder Simulation?

I had a look at some of the scrips written and they are far far to difficult and fully featured for a beginner like me understand or learn from

Anybody every seen and ULTRA basic Quadrature Encoder Simulation scripts that I can use this for testing purposes?

All I really need to test is 1 increment move on either side

Rather than give you some complicated code I'd suggest you start very simply. You need to generate two pulse trains that are in "pase quadrature" - which looks like this
image
Use the "blink without delay" example

to generate the A signal to an "A" LED

now adapt it to generate the SAME signal to an "B" LED eg

// constants won't change. Used here to set a pin number:
const int chA_Pin = 3;  // put a led & reisitor on D3
const int chB_Pin = 4;  // put a led & reisitor on D4

you now have two leds flashing together. (AB) 00 - 11 - 00 -etc

now add a counted loop to make the lights do this: (AB) 00 -01-11-10 - 00 - 01

2 Likes

Thats great, that will give me something simple to work on first, exactly what I am looking for. Lets say I achieve this, how will I wire the arduino to the 4 pins where the encoder used to go?

That all depends on HOW the original encoder was wired, don't you think?

2 Likes

Yeah I understand what you mean. I have now figured out what the wires are (I think) after testing the encoder. I had planned to put vcc - vcc, gnd - gnd, output A - output A etc. I thought that the wiring would be different from encoder testing setup to trying to mimic the encoder.

I still have the arduino connected and wired to test the encoder, not sure if this can be used or just disassemble and proceed with the advice on post #4

Ok so I have followed your guidelines and I have managed to get an A led and B led both to flash on and off at the same time. I have hit a brick wall and just cannot figure out how to add the counted loop.

Anyway this was the code I am at right now:

/*
  Blink without Delay

  Turns on and off a light emitting diode (LED) connected to a digital pin,
  without using the delay() function. This means that other code can run at the
  same time without being interrupted by the LED code.

  The circuit:
  - Use the onboard LED.
  - Note: Most Arduinos have an on-board LED you can control. On the UNO, MEGA
    and ZERO it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN
    is set to the correct LED pin independent of which board is used.
    If you want to know what pin the on-board LED is connected to on your
    Arduino model, check the Technical Specs of your board at:
    https://www.arduino.cc/en/Main/Products

  created 2005
  by David A. Mellis
  modified 8 Feb 2010
  by Paul Stoffregen
  modified 11 Nov 2013
  by Scott Fitzgerald
  modified 9 Jan 2017
  by Arturo Guadalupi

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
*/

// constants won't change. Used here to set a pin number:
const int ledPinA = 13;  // the number of the LED pin
const int ledPinB = 12;

// Variables will change:
int ledState = LOW;  // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;  // will store last time LED was updated

// constants won't change:
const long interval = 1000;  // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPinA, OUTPUT);
  pinMode(ledPinB, OUTPUT);
}

void loop() {
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPinA, ledState);
    digitalWrite(ledPinB, ledState);
    
  }
}


Something here might help.

1 Like

Yeah thats an interesting link. Dont know if I'll ever get my head around it but the two boolean arrays seem like the way to go. Tried uploading the code (changing to pin 12 and 13) and it makes the leds flash although not the way I expected. This code has 1 led constant and the other flashes on and off quickly.

Somehow need to merge bits of these two codes

Another approach:

1 Like
/*
   This simple sketch is an example showing how the switch - case structure can be used to implement a state machine
   LEDs are connected to pins 2,3 on the nano, with 470 ohm resistors to ground
   J. Errington 12 Jan 2023
*/
// assign pin numbers for the leds
const byte led_R = 4;  //channel A
const byte led_Y = 3;  //channel B
const byte dirSwitch = 9;  //direction switch on pin 9
int qState = 0;
int dir;


const int phaseTime = 500;             //duration of each phase in miliseconds
unsigned long timeStart, timeElapsed;  //will hold the time the state started and the time elapsed in the current state

void setup() {
  Serial.begin(57600);
  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB
  }
  pinMode(led_R, OUTPUT);
  pinMode(led_Y, OUTPUT);
  pinMode(dirSwitch, INPUT_PULLUP);
  qState = 0;  //start with the amber on
  timeStart = millis();
}

void loop() {
  switch (qState) {
    case 0:  //00
      {
        digitalWrite(led_R, LOW);
        digitalWrite(led_Y, LOW);
      }
      break;

    case 1:  //01
      {
        digitalWrite(led_R, LOW);
        digitalWrite(led_Y, HIGH);
      }
      break;

    case 2:  //11
      {
        digitalWrite(led_R, HIGH);
        digitalWrite(led_Y, HIGH);
      }
      break;

    case 3:  //10
      {
        digitalWrite(led_R, HIGH);
        digitalWrite(led_Y, LOW);
      }
      break;
  }
  //is it time for the next state?
  timeElapsed = millis() - timeStart;
  if (timeElapsed > phaseTime) {
    //restart the timer and change the state
    timeStart = millis();
    if(digitalRead(dirSwitch)) {dir = 1;} else {dir = -1;}
    qState += dir;
    if ((qState >= 4) && (dir == 1)) qState = 0; //restart from state zero if counting up;
    if ((qState < 0 ) && (dir == -1)) qState = 3; //restart from state 3 if counting down
    Serial.println(qState);
  }
}  //loop

edite to add direction control

1 Like

Verrrry interesting

so, I know this is led's but if this was on the hot plate should this move 4 degrees?

what hot plate?

1 Like

apologies... I had forgotten to mention on this thread that the whole idea for this would be to control a hot plate via its rotary encoder. Ignore that post... oops

perhaps a picture would help? why would a hot plate rotate?

1 Like

Sorry I realised I hadn't answered your question. The hot plate is a Vevo Hotplate stirrer, s-1600 is the model name I think.

To control the temperature you turn the dial which I believe is a rotary encoder. I am trying to control this hotplate automatically.

I just tried this code and it works perfectly, very cool :slight_smile: Tested this with LED's. many thanks for this code.

I'm going to need to study this code somewhat. I understand some of this but the last has got me at the moment. I think this code is very handy, is it possible to stop this from looping over. I'd be looking to have this do 1 step, then stop for 10 seconds, 1 step then stop for 15 seconds, 1 step then 22 seconds etc.