I want to declare the KY40 sketch as a function so I can call it multiple times within a 'master' sketch. I placed the KY40 function outside my void loop.
To try this, I wrote a simple sketch directing my void loop to call the KY40 function and then print the KY40 output. This amounts to a 2-3 line Void loop. The sketch compiles and uploads OK, but doesn't work.
Inside the KY40 function I placed a debug print statement to make sure the KY40 function is actually being called. It is but the KY40 output is not.
I'm at a loss as to what is wrong and hope someone can help. My sketch is attached, Please remember, the Ky40 sketch works fine as a stand alone sketch.
#define CLK 2
#define DT 3
#define SW 4
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;
//end of Ky40 'top' stuff
void setup(){
//moved the setup stuff from the Ky40 sketch here
//Set encoder pins as inputs
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
Serial.begin(9600);
// Read the initial state of CLK
lastStateCLK = digitalRead(CLK);
}
//end of KY40 setup
void loop(){
//Really short loop: read the KY40 count and print it, that's all !!!
counter = KY40Function();//call the KY40 function
Serial.println(counter);//print the KY40's counter
}
//The KY40 FUNCTION itself starts below.
int KY40Function(){//begin KY40 function
delay(1000);
Serial.print("Debug to see if KY40Function is executing");
delay(1000);
// Read the current state of CLK
currentStateCLK = digitalRead(CLK);
// If last and current state of CLK are different, then pulse occurred
// React to only 1 state change to avoid double count
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so decrement
if (digitalRead(DT) != currentStateCLK) {
counter --;
currentDir ="CCW";
} else {
// Encoder is rotating CW so increment
counter ++;
currentDir ="CW";
}
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
}
// Remember last CLK state
lastStateCLK = currentStateCLK;
// Read the button state
int btnState = digitalRead(SW);
//If we detect LOW signal, button is pressed
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
Serial.println("Button pressed!");
}
// Remember last button press event
lastButtonPress = millis();
}
// Put in a slight delay to help debounce the reading
delay(1);
int result;
result=counter;
return result;
//end of KY40 function
}
You made a mess of 'counter'. Its a global variable which you use in the function, then return by passing through 'result" and re-assigning 'counter' to itself. There is a lot of room for error there, even if it happened to work (but you're saying it doesn't...).
Make 'counter' local to the function by declaring it with the 'static' keyword and return it, or else make it global and modify it in the function and don't return anything.
Also this is redundant
int result;
result=counter;
return result;
//end of KY40 function
}
your function has two delay(1000) this makes the microcontroller wait for a full second.
Tha'ts why counting/up-down does not work any more.
Of course serial.print every time your LY40-function is called doesn't make sense.
So you have to re-code it using timing based on millis()
#define CLK 2
#define DT 3
#define SW 4
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir = "";
unsigned long lastButtonPress = 0;
//end of Ky40 'top' stuff
void setup() {
//moved the setup stuff from the Ky40 sketch here
//Set encoder pins as inputs
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SW, INPUT_PULLUP);
Serial.begin(115200);
// Read the initial state of CLK
lastStateCLK = digitalRead(CLK);
}
//end of KY40 setup
boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - expireTime >= TimePeriod )
{
expireTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
unsigned long MyTestTimer = 0; // variables MUST be of type unsigned
unsigned long MyKY40Timer = 0; // variables MUST be of type unsigned
void loop() {
//Really short loop: read the KY40 count and print it, that's all !!!
KY40Function();//call the KY40 function
if (TimePeriodIsOver (MyTestTimer, 1000) ) {
Serial.println(counter);//print the KY40's counter
}
}
//The KY40 FUNCTION itself starts below.
void KY40Function() { //begin KY40 function
if (TimePeriodIsOver (MyKY40Timer, 500) ) {
Serial.print("Debug to see if KY40Function is executing");
}
// Read the current state of CLK
currentStateCLK = digitalRead(CLK);
// If last and current state of CLK are different, then pulse occurred
// React to only 1 state change to avoid double count
if (currentStateCLK != lastStateCLK && currentStateCLK == 1) {
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so decrement
if (digitalRead(DT) != currentStateCLK) {
counter --;
currentDir = "CCW";
} else {
// Encoder is rotating CW so increment
counter ++;
currentDir = "CW";
}
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
}
// Remember last CLK state
lastStateCLK = currentStateCLK;
// Read the button state
int btnState = digitalRead(SW);
//If we detect LOW signal, button is pressed
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
Serial.println("Button pressed!");
}
// Remember last button press event
lastButtonPress = millis();
}
// Put in a slight delay to help debounce the reading
delay(1);
//end of KY40 function
}
aarg:
You made a mess of 'counter'. Its a global variable which you use in the function, then return by passing through 'result" and re-assigning 'counter' to itself. There is a lot of room for error there, even if it happened to work (but you're saying it doesn't...).
Make 'counter' local to the function by declaring it with the 'static' keyword and return it, or else make it global and modify it in the function and don't return anything.
Also this is redundant
int result;
result=counter;
return result;
//end of KY40 function
}
It is no different than:
return counter;
//end of KY40 function
}
Thanks AARG, that helps a lot, but I still need to work out some bugs!
If your "bugs" are non-constant counting - in most cases this is caused by bouncing of the mechanical contacts of the KY40. This can be eliminated by a method called table-decoding.
user Argmue posted code that does use this method some time ago.
right today another thread was started about rotary-encoders where I have posted a polling-version and a interrupt-driven version of this code
you can find it here:
I'm able to call my KY40 function from void loop, and The KY40 function itself executes OK.
With the KY40 function running OK, I want to use the WHILE statement to exit the KY40 function and call another function called AA. The WHILE 'trigger' is when the KY40 button is pressed. This is part of a menu sketch which will eventually call several other functions.
My problem is the WHILE statement doesn't execute when the KY40 is pressed
and the KY40 call to the AA function never happens. I confirmed the KY40 button IS working correctly.
Help please? My code follows;
#define CLK 2
#define DT 3
#define SW 4
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;
//end of Ky40 'declare' stuff
void setup(){
//Set encoder pins as inputs
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
Serial.begin(9600);
// Read the initial state of KY40 CLK
lastStateCLK = digitalRead(CLK);
}
void loop(){
//Short void loop. Read the KY40 count, print it.
counter = KY40Function();//call the KY40 function
Serial.println(counter);//print the KY40's counter
}
//The KY40 FUNCTION. Button pressed is normally high. When button pressed, use the While statement to exit and call the AA function.
int KY40Function(){ //begin KY40 function
int btnState = digitalRead(SW);
while(btnState= HIGH){;//needs boolean trigger ???
static int counter;
// Read the current state of CLK
currentStateCLK = digitalRead(CLK);
// If last and current state of CLK are different, then pulse occurred
// React to only 1 state change to avoid double count
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so decrement
if (digitalRead(DT) != currentStateCLK) {
counter --;
currentDir ="CCW";
} else {
// Encoder is rotating CW so increment
counter ++;
currentDir ="CW";
}
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
delay(2000);//Holds the count for 2-seconds
}
// Remember last CLK state
lastStateCLK = currentStateCLK;
// Read the button state
btnState = digitalRead(SW);
//If we detect LOW signal, button is pressed
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
Serial.println("Button pressed!");
}
// Remember last button press event
lastButtonPress = millis();
}
// Put in a slight delay to help debounce the reading
delay(20);
return counter;
}
}
//KY40 function end
void AA(){
delay(2000);
Serial.print("This is function AA");
delay(5000);}