Notifications
Clear all

KY-o40 - What nobody bothers to mention!

8 Posts
2 Users
1 Reactions
3,376 Views
(@pugwash)
Sorcerers' Apprentice
Joined: 7 years ago
Posts: 923
Topic starter  

The KY-040 has been covered by lots of people on YouTube, even by Bill.

What all of them have forgotten to mention is the middle pin labelled "SW" and how it works. This is a momentary switch that does not work as I expected it too! I expected the pin to go HIGH if the switch was pressed, silly me!

I connected this pin directly to a pin on the Arduino and changed the sketch to monitor the pin's state and got some strange results. So I attached my oscilloscope to the "SW" and when not pressed I was getting a ripple at 0V and when the switch was pressed the 0V ripple disappears. Conclusion: when the switch is not pressed then the pin is floating and when pressed the "SW" pin is providing a route to GND.

I have confirmed this by attaching an LED with a resistor to the 5V pin then to "SW" pin. Now when pressed the LED lights up. My guess is that an Arduino pin needs a pullup resistor and will be pulled LOW when the switch is pressed.



   
Quote
Topic Tags
(@zeferby)
Member
Joined: 6 years ago
Posts: 355
 

Hi @pugwash, I was playing with the same toys...

Here is a modified DBW example i edited from Bill's, with encoder switch detection (implementing a "Return to Zero") and "high speed" encoder rotation detection, with 5 leds and the encoder switch pulled high : check the #defines at the beginning of the sketch for the pin numbers !!

I use a high speed for Serial, otherwise at 9600 it cannot cope with real quick shaft turning.
And yes, the switch is temporary and active LOW, so i reverse the digitalRead to digitalWrite to the blue LED.

/*
Rotary Encoder Demo
rot-encode-demo-5leds.ino
Demonstrates operation of Rotary Encoder
Displays results on Serial Monitor
DroneBot Workshop 2019
https: / / dronebotworkshop.com

Edited by ZeFerby for "high speed" encoding detection + Return-To-Zero on encoder switch click
2x red LEDs for "high speed" encoder pulses, 2x yellow LEDs for "low speed" encoder pulses, 1x blue LED for SW/RTZ
*/

// Rotary Encoder Inputs
#define inputCLK 4
#define inputDT 5
#define inputSW 6

// LED Outputs
#define ledCW2 8 //"high speed" red
#define ledCW1 9 //"low speed" yellow
#define ledZero 10 //Switch click->RTZ, blue
#define ledCCW1 11 //"low speed" yellow
#define ledCCW2 12 //"high speed" red

unsigned long intervalHighSpeed = 25;

int counter = 0;
int currentStateSW;
int currentStateCLK;
int previousStateCLK;

unsigned long previousMillisSW = 0;
unsigned long previousMillisCW = 0;
unsigned long previousMillisCCW = 0;
unsigned long currentMillis;
unsigned long encDelay;
bool bFast = false;

String encDir ="";

void setup() {

// Set encoder pins as inputs
pinMode (inputCLK,INPUT);
pinMode (inputDT,INPUT);
pinMode (inputSW,INPUT_PULLUP);

// Set LED pins as outputs
pinMode (ledCW2,OUTPUT);
pinMode (ledCW1,OUTPUT);
pinMode (ledZero,OUTPUT);
pinMode (ledCCW1,OUTPUT);
pinMode (ledCCW2,OUTPUT);

// Setup Serial Monitor
Serial.begin (57600);

// Read the initial state of inputCLK
// Assign to previousStateCLK variable
previousStateCLK = digitalRead(inputCLK);

}

void loop() {

currentMillis = millis();

// Read the current state of inputSW
currentStateSW = digitalRead(inputSW);
digitalWrite(ledZero, !currentStateSW); //blue
if ( (currentStateSW == LOW) && ( (previousMillisCW > previousMillisSW) || (previousMillisCCW > previousMillisSW) ) )
{
counter = 0;
digitalWrite(ledCW2, LOW); //red
digitalWrite(ledCW1, LOW); //yellow
digitalWrite(ledCCW1, LOW); //yellow
digitalWrite(ledCCW2, LOW); //red
Serial.println("SW => RTZ !");
previousMillisSW = currentMillis;
}

// Read the current state of inputCLK
currentStateCLK = digitalRead(inputCLK);

// If the previous and the current state of the inputCLK are different then a pulse has occured
if ((currentStateCLK == HIGH) && (currentStateCLK != previousStateCLK))
{
// Serial.print("currentStateCLK: ");
// Serial.println(currentStateCLK);

// If the inputDT state is different than the inputCLK state then
// the encoder is rotating counterclockwise
if (digitalRead(inputDT) != currentStateCLK) {
counter --;
encDir ="CCW";
digitalWrite(ledCW2, LOW); //red
digitalWrite(ledCW1, LOW); //yellow
encDelay = currentMillis - previousMillisCCW;
bFast = (encDelay < intervalHighSpeed);
digitalWrite(ledCCW1, (bFast ? LOW : HIGH)); //yellow
digitalWrite(ledCCW2, (bFast ? HIGH: LOW)); //red
previousMillisCCW = currentMillis;

}
else
{
// Encoder is rotating clockwise
counter ++;
encDir ="CW";
encDelay = currentMillis - previousMillisCW;
bFast = (encDelay < intervalHighSpeed);
digitalWrite(ledCW2, (bFast ? HIGH: LOW)); //red
digitalWrite(ledCW1, (bFast ? LOW : HIGH)); //yellow
digitalWrite(ledCCW1, LOW); //yellow
digitalWrite(ledCCW2, LOW); //red
previousMillisCW = currentMillis;

}
Serial.print("Direction: ");
Serial.print(encDir);
Serial.print(" -- Delay: ");
Serial.print(encDelay);
Serial.print(bFast ? " -- QUICK " : " -- Slow ");
Serial.print(" -- Value: ");
Serial.println(counter);
}
// Update previousStateCLK with the current state
previousStateCLK = currentStateCLK;
}

Eric


   
ReplyQuote
(@zeferby)
Member
Joined: 6 years ago
Posts: 355
 

And here is the version playing with a small SG90 micro-servo (trying to attach the source file, i'll edit if it doesn't work)

 


Eric


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 7 years ago
Posts: 923
Topic starter  

@zeferby

Here is a modified DBW example i edited from Bill's, with encoder switch detection (implementing a "Return to Zero") and "high speed" encoder rotation detection, with 5 leds and the encoder switch pulled high : check the #defines at the beginning of the sketch for the pin numbers !!

Thanks for sharing!

Tried it out and works well, I am sure I will glean some info from the code regarding coding the switch.

What I am trying to achieve is the following:

I wish to be able to toggle the Arduino between "learning" and "operation" modes.

The learning mode would involve moving a servo or stepper motor to a particular position with the rotary decoder, and then storing the position in the EEPROM using the momentary switch.

The operation mode involves automatically moving the servo/stepper to the stored positions, ad infinitum or until I change the stored values. 



   
ReplyQuote
(@zeferby)
Member
Joined: 6 years ago
Posts: 355
 

@pugwash I see, something like an adjustable "homing" position.

I suppose you're aware of Flash/EEPROM wear ? I have been reading on PROGMEM after looking at some library source files, which led me to look at the EEPROM capacities...what i read did not encourage me to use the Arduino's own EEPROM but rather to add an external chip (that can be replaced when wear level gets too high) for EEPROM storage.  Of course that depends on the expected frequency of write/erase operations...

While browsing i found this repo, and especially the Atmel doc linked there, that you may be interested in :

https://github.com/drjoju/Arduino-wear-leveling


Eric


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 7 years ago
Posts: 923
Topic starter  

@zeferby

Thanks for drawing my attention to this issue, but I have also read about EEPROM wear and that 10000 write/erase cycles will wear out the EEPROM registers.

I am not particularly worried about this as the number of changes to be made to the registers will be nowhere near this limit, and considering the limited number of years I have left on this planet. ? 

And of course, if you wear out a number registers, you can change the starting address, if the number of registers needed does not exceed 512.



   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 7 years ago
Posts: 923
Topic starter  

Many thanks to @zeferby

The following is the bare minimum code to poll the rotary encoder switch.

#define inputSW 6 //attach  UNO pin D6 to SW pin on rotary encoder
// const byte interruptPin = 2; // alternative to pin 6

#define ledZero 10 //attach to an LED on UNO pin D10

void setup() {
pinMode (inputSW,INPUT_PULLUP);
// pinMode (interruptPin,INPUT_PULLUP);
// attachInterrupt(digitalPinToInterrupt(interruptPin), doSomething, FALLING);
}

void loop() {
int currentStateSW = digitalRead(inputSW);

if(currentStateSW == LOW){
digitalWrite(ledZero, HIGH); // the do something part
}
else{
digitalWrite(ledZero, LOW);
}
void doSomething(){
// another do something section
}
}

In a large program, it would probably be advisable to attach the switch SW to an interrupt pin (2 or 3), looking for a falling signal as the alternative commented out code above shows.

 



   
ZeFerby reacted
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 7 years ago
Posts: 923
Topic starter  

Corrected an obvious mistake! ? 

#define inputSW 6 //attach UNO pin D6 to SW pin on rotary encoder
// const byte interruptPin = 2; // alternative to pin 6

#define ledZero 10 //attach to an LED on UNO pin D10

void setup() {
pinMode (inputSW,INPUT_PULLUP);
// pinMode (interruptPin,INPUT_PULLUP);
// attachInterrupt(digitalPinToInterrupt(interruptPin), doSomething, FALLING);
}

void loop() {
int currentStateSW = digitalRead(inputSW);

if(currentStateSW == LOW){
digitalWrite(ledZero, HIGH); // the do something part
}else{
digitalWrite(ledZero, LOW);
}
}

void doSomething(){
// another do something section
}


   
ReplyQuote