BLYNK
HOME       📲 GETTING STARTED       📗 DOCS       ❓HELP CENTER       👉 SKETCH BUILDER

Rotary encoder along with Blynk Slider Widget!


#1

Hello !

Has anyone ever tried to get in sync with a rotary encoder along with the Blynk slider widget to control the brightness of a LED or something similar ?
Went through the community and found someone tried it with a potentiometer but not with rotary encoder.
What is the way out to achive this ? Can anyone show me a way ??

Thank you in advance.


#2

There are different types of rotary encoders and different ways of reading them… polling, interrupts, etc.

Start with finding a NON-Blynk sketch that works with your device and encoder type.

Get it working, study and learn HOW it works, so you can determine how to merge it’s timing needs with Blynk’s

Use the results to increment/decrement a value

Then add in the Blynk libraries, and assuming you have the timing worked out sufficiently, use that incrementing/decrementing value to sync the slider… which in turn controls the thing you want.


#3

Sure thing… i will try that out.


#4

Totally hashed together proof of concept using parts I have that probably won’t do you any good :stuck_out_tongue:

Using the simple three pin rotary encoder on my Diyode CodeShield that is mounted to my Arduino Mega testbench. It is using two analog pins as if they were normal GPIO becasue all the other pins on the shield are used.

This is NOT the complete sketch, but just what I added to an existing testbench to see how it worked… A bit imprecise in motion detection, but otherwise not to bad considering the low end encoder and how many other tasks are running at same time on my testbench.

You will get better results Googling for a proper library to read your encoder with.

/*
    Diyode Codeshield Rotary Encoder - Uses Port Manipulation
    ENCODER_A 54 (A0) for MEGA - Use 14 (A0) for Uno
    ENCODER_B 55 (A1) for MEGA - Use 15 (A1) for Uno
    ENCODER_PORT PINF - use PINC for Uno
*/

#define ENCODER_A 54
#define ENCODER_B 55
#define ENCODER_PORT PINF
static uint8_t rotCounter = 128;  // Start in the middle of the slider - This variable will be changed by encoder input
int lastRotValue;

In setup…

  /* Setup encoder pins as inputs */
  pinMode(ENCODER_A, INPUT);
  digitalWrite(ENCODER_A, HIGH);
  pinMode(ENCODER_B, INPUT);
  digitalWrite(ENCODER_B, HIGH);

  timer.setInterval(10L, RotEncoder);  // Scan rotary encoder pins

Main code…

void RotEncoder()
{
    int8_t tmpdata;
    tmpdata = read_encoder();
    if (tmpdata) {
        rotCounter += tmpdata;
        Blynk.virtualWrite(vPin, rotCounter);  // Sync to Slider Widget
        Blynk.syncVirtual(vPin);  // Process Slider state change
    }
}

/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
    static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
    static uint8_t old_AB = 0;
    old_AB <<= 2;                   //remember previous state
    old_AB |= ( ENCODER_PORT & 0x03 );  //add current state
    return ( enc_states[( old_AB & 0x0f )]);
}

BLYNK_WRITE(vPin) { //  Slider Widget set to 0-255
  rotCounter = param.asInt();  // Synced from Slider Widget
  // Control stuff with the slider here
}

#5

@Gunner thank you for sharing this code. I was just trying now with my rotary encoder and i was just dimming an led in 25 steps . But i was wondering how to add blynk slider to that part of code. Now i can try injecting your code and try to get in sync with it .
Later comes zero crossing and some serious stuff !! :stuck_out_tongue:


#6
int detectado = 0;
int valor=0;
int last_CH1_state = 0;

void setup() {
  /*
   * Port registers allow for lower-level and faster manipulation of the i/o pins of the microcontroller on an Arduino board. 
   * The chips used on the Arduino board (the ATmega8 and ATmega168) have three ports:
     -B (digital pin 8 to 13)
     -C (analog input pins)
     -D (digital pins 0 to 7)   
  //All Arduino (Atmega) digital pins are inputs when you begin...
  */  
   
  PCICR |= (1 << PCIE0);    //enable PCMSK0 scan                                                 
  PCMSK0 |= (1 << PCINT0);  //Set pin D8 trigger an interrupt on state change. Input from optocoupler
  pinMode(3,OUTPUT);        //Define D3 as output for the DIAC pulse

}

void loop() {
   //Read the value of the pot and map it from 10 to 10.000 us. AC frequency is 50Hz, so period is 20ms. We want to control the power
   //of each half period, so the maximum is 10ms or 10.000us. In my case I've maped it up to 7.200us since 10.000 was too much
   
   valor = map(analogRead(A0),0,1024,7200,10);
    if (detectado)
    {
      delayMicroseconds(valor); //This delay controls the power
      digitalWrite(3,HIGH);
      delayMicroseconds(100);
      digitalWrite(3,LOW);
      detectado=0;
    } 
}




//This is the interruption routine
//----------------------------------------------

ISR(PCINT0_vect){
  /////////////////////////////////////               //Input from optocoupler
  if(PINB & B00000001){                               //We make an AND with the pin state register, We verify if pin 8 is HIGH???
    if(last_CH1_state == 0){                          //If the last state was 0, then we have a state change...
      detectado=1;                                    //We haev detected a state change!
    }
  }
  else if(last_CH1_state == 1){                       //If pin 8 is LOW and the last state was HIGH then we have a state change      
    detectado=1;                                      //We haev detected a state change!
    last_CH1_state = 0;                               //Store the current state into the last state for the next loop
    }
}

@Gunner I found this code on the internet and it works really good in dimming the incandescent bulb with a potentiometer. But this works with uno… I am not able to find a suitable ex. code for nodemcu.
Interrupts are the main thing used to achieve the dimming frequency. But in nodemcu that doesnt work, i tried that, but i maybe wrong. Can the same code modified to work in nodemcu ??


#7

I have no idea… but what does this have to do with your topic, rotary encoders or even Blynk?


#8

Inspired by this.

Rotary encoder with nodemcu is never tried. So i thought using this potentiometer sketch and later try to add rotary encoder in place of potentiometer. But the main problem is this sketch is not compatible with nodemcu. So in this community there are some talented heads, so thought of taking suggestion.
Thought this is not a blynk related issues… i asked because without the base code blynk alone cannot be used right ?


#9

Here is how I solved it for a local server.
I control an LED stripe by the Blynk app including one button and a slider. Additionally I have a rotary encoder with a button (KY-040). The goal was to synchronize the app and the encoder. When reaching either the darker or the brighter end of the LED brightness by the encoder, the LEDs start to flicker. So I know that I don’t have to turn the knob anymore. Moreover the brightness can’t reach more than 1%/100% of the brightness. A whole cycle through the brightness means 1.2 turns by the encoder for the mentoned one.
V2 is the knob to turn the light on or off. V3 is the slider. Be aware that there might be something missing or uneccessary because I copied the code from a more complex one.
You can find the library here.

/*********Settings****************/

//ESP            
#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
BlynkTimer timer;
int ReCnctFlag;
char auth[]   = "xxxx";
char ssid[]   = "xxxx";
char pass[]   = "xxxx";
char server[] = "xxxx";
int port      = xxxx;

//LED
int LEDpin = 15;
int LEDbright = 100;
bool LEDstate = false;

//Encoder
#include <Encoder.h>
Encoder Enc(13, 5);
long oldPos = -999;
long newPos;

//Button
int ButtonPin = 4;
volatile bool ButtonState = false;
volatile bool bounced = false;

/*********Blynk*********************/

//LED Power
BLYNK_WRITE(V2)  {
  if (param.asInt() == 1) {
    analogWrite(LEDpin, LEDbright);
    LEDstate = true;
  } else {
    analogWrite(LEDpin, 0);
    LEDstate = false;
  }
}

BLYNK_WRITE(V3)  {
  LEDbright = param.asInt();
  Enc.write(LEDbright);
}

//Sync When Connected
BLYNK_CONNECTED() {
  Blynk.syncVirtual(V2);
  Blynk.syncVirtual(V3);
  Enc.write(LEDbright);
}

/*********Functions*********************/

//Encoder
void Enco() {
  if (LEDstate) {
    newPos = Enc.read();
    if ((newPos - oldPos) > 3 || (newPos - oldPos) < -3 ) {
      if (newPos > 100) {
        Enc.write(100);
        newPos = 100;
        LEDstate = false;
        timer.setTimeout(10L, []() {
          analogWrite(LEDpin, 0);
          timer.setTimeout(5L, []() {
            analogWrite(LEDpin, LEDbright);
            LEDstate = true;
          });
        });
      } else if (newPos < 1) {
        Enc.write(1);
        newPos = 1;
        LEDstate = false;
        timer.setTimeout(10L, []() {
          analogWrite(LEDpin, 0);
          timer.setTimeout(5L, []() {
            analogWrite(LEDpin, LEDbright);
            LEDstate = true;
          });
        });
      }
      oldPos = newPos;
      LEDbright = newPos;
      analogWrite(LEDpin, LEDbright);
      Blynk.virtualWrite(V3, newPos);
    }
  } else {
    Enc.write(LEDbright);
  }
}

//Button
void ButtonInterrupt() {
  if (!bounced) {
    bounced = true;
    ButtonState = true;
    timer.setTimeout(688L, []() {
      bounced = false;
    });
  }
}

void Buttonaction() {
  if (ButtonState) {
    if (LEDstate) {
      Blynk.virtualWrite(V2, 0);
    } else {
      Blynk.virtualWrite(V2, 1);
    }
    ButtonState = false;
    Blynk.syncVirtual(V2);
  }
}

/*********Void Setup*********************/

void setup() {
  //Debug console
  //Serial.begin(9600);

  //Button
  pinMode(ButtonPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(ButtonPin), ButtonInterrupt, FALLING);

  //LED
  pinMode(LEDpin, OUTPUT);
  digitalWrite(LEDpin, LOW);
  analogWriteRange(100);  

  //Network
  WiFi.begin(ssid, pass);                   // Non-blocking if no WiFi available
  Blynk.config(auth, server, port);
  Blynk.connect();
}


/*####################################################################################################################*/

/*********Void Loop*********************/

void loop() {
  //Timer
  timer.run();

  //Button
  Buttonaction();

  //Encoder
  Enco();

  //Blynk
  if (Blynk.connected()) {            // If connected run as normal
    Blynk.run();
  } else if (ReCnctFlag == 0) {       // If NOT connected and not already trying to reconnect, set timer to try to reconnect in 30 seconds
    ReCnctFlag = 1;                   // Set reconnection Flag    
    timer.setTimeout(30000L, []() {   // Lambda Reconnection Timer Function
      ReCnctFlag = 0;                 // Reset reconnection Flag
      Blynk.connect();                // Try to reconnect to the server
    });                               // END Timer Function
  }
}

#10

Thank you for the Sample code … But Using an nodemcu to Dim a light or control a fan speed is not possible i guess. Because the frequency at which interrupts are called it messes up with the wifi connectivity and stability. I did quite a bit of research on the internet but was not able to find sample code for the nodemcu and also a suitable circuit too. But i successfully dim the light on arduino uno using a (potTriac, optocoupler, diac). But thats no use … The problem i am facing is Timer1 library. That esp8266 cant handle.

This is not a blynk related issue at all… But felt like sharing the instance.
If anyone has faced a similar issue and found a solution … Please share…


#11

Sorry, I don’t understand your problem. Do you mean with Nodemcu the ESP8266? That is no problem as long as you don’t turn the knob with a drilling machine. I’m running the above code along with some other stuff on an ESP8285. Never had any stability issues. The circuit is pretty simple: some resistors, a mosfet.


#12

:joy::joy::joy:
well said.

you are dimming a led with pwm by pulsing the gate of the mosfet. But when it comes to triac we need to pulse the gate of the triac at every positive and negetive half of the cycle after zero crossing. So there has to be an interrupt for zero crossing. This is giving problem…
Dimming DC load is kind of easy. But dealing With AC is difficult.

cant stop laughing:joy::joy::joy::joy::joy::joy::joy::joy::joy: