Boolean data and encoder issue.

Hello everyone, I have a problem figuring out the problem in my code.

#include <Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define  OLED_RESET 4
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define CLK 2
#define DT 3
#define SW 4

Adafruit_SSD1306 display(SCREEN_WIDTH,SCREEN_HEIGHT,&Wire,OLED_RESET);

Servo servo;

int trenutniCLK;
int prosliCLK;
int buttonState;
int counter = 1000;

boolean statusPWM=false;


void setup() {
  servo.attach(9);
  servo.writeMicroseconds(1000);
  pinMode(CLK,INPUT);
  pinMode(DT,INPUT);
  pinMode(SW,INPUT_PULLUP);
  prosliCLK = digitalRead(CLK);
 // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.setTextColor(WHITE);
  display.setTextSize(3);
  Serial.begin(9600);
}

void loop() {
  trenutniCLK = digitalRead(CLK);
  if (trenutniCLK != prosliCLK){
    if (digitalRead(DT) != trenutniCLK) {
      counter=counter+50;
      if (counter>2000)
        counter=2000;
    } else {
      counter=counter-50;
      if (counter<1000)
        counter=1000;
    }
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
  }

  if (Serial.available()>0) {
    int pwm=Serial.parseInt();
    if (pwm>=1000 && pwm<=2000) {
      counter=pwm;
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
    }
    else if(pwm=0) {
      counter==1000;
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
    }

  }

  prosliCLK = trenutniCLK;

  buttonState=digitalRead(SW);

  if (buttonState==LOW && statusPWM==false) {
    servo.writeMicroseconds(counter);
    delay(300);
    while(digitalRead(SW)==LOW);
  }
  if (buttonState==LOW && statusPWM==true){
    servo.writeMicroseconds(1000);
    delay(300);
    while(digitalRead(SW)==LOW);
  }

 
  statusPWM=!statusPWM;
  
}

So, this is my code. Basically, this is a PWM generator, I pick the PWM signal in microseconds, using an encoder and at the same time showing the PWM on my display. I can also input PWM through serial monitor, but I can't seem to type in 0 in serial monitor and get 1000microseconds on the output. That would be the first problem.

Secondly, I can't seem to figure out the problem with the booelan data, statusPWM. Going through the loop, since the statusPWM is false, the first if condition (buttonState==LOW && statusPWM==false) should be evaluated. Second if condition isn't evaluated since statusPWM is still false. At the end of the loop statusPWM is inverted so I get statusPWM=true and going through the loop again should make the first if condition not evaluated, and the second one evaluated. This should basically mean - I pick a PWM value with the encoder, press the encoder button and get that PWM on the output, and when I press again it should go down to 1000 microseconds on the output , meaning it would turn off. The problem is it won't work as expected. It doesn't respond properly. When I press the button , it gets the PWM I wanted, but when I press it again, it doesn't go back to 1000 microseconds, but after a few more presses it does that. I don't understand how should I type the code so the encoder button responds properly everytime, so that with each encoder button press I get a different result, as expected. I put the delay(300) in order to fix the bounce issue, hopefully that's correct. I hope I gave good information, first time writing here. Thanks for the help!

I put the delay(300) in order to fix the bounce issue, hopefully that's correct. I hope I gave good information, first time writing here.

Not completely, for example you're not telling us the result of that attempt to fix it. Your description does suggest some problem in debouncing the switch so that is important. "hopefully that's correct"... well, did you test it or not?

You didn't explain why 1000 microseconds (and where?) would produce a 0 output.

it should go down to 1000 microseconds on the output , meaning it would turn off.

This is a problem:

    else if(pwm=0) {

It's an assignment statement. Were you trying to compare?

I put different values of the delay, for example I put delay(3000). Doing that, when I chose the PWM value, and when I pressed the encoder button, I couldn't do anything for those 3 seconds... couldn't rotate the encoder ( couldn't pick the new PWM value, neither coud I press it again in order to make the PWM output 1000 microseconds. When I remove the delay completely from both IF functions, this happens - the servomotor which I'm controlling flickers, for example if I want the value of 1800 microseconds, I had to press the encoder button three times in order to get to that position... instead I wanted it to go to 1800 microseconds(first encoder press), than to go back to 1000 microseconds(second encoder press) and with the third press I should go back to the PWM value which I pick with the rotation of the encoder.

Oh my god, I just saw the mistake with the else if(pwm=0), I fixed it.. I had the mistake the line under that as well.. it said counter==1000 , but it should've said counter=1000.. Thanks for that!

You may not have seen the edit that I made. Fix the unintended assignment.

Yes, I saw the edit you've made, and I did correct the mistake.

else if(pwm==0) {
      counter=1000;
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
    }

But now, if I type in different values in serial monitor, for example 1500, it shows 1500 on the display for a second, and than it suddenly changes to 1000. But I wanted it to stay at 1500.

This program should control the speed of a motor, but since I don't have it, I put a servomotor SG90 on the output in order to see how does the servo respond to this program, I don't have anything better to put there.

Do you have line endings set to "none" in the serial monitor?

No, it was set on "Newline", but I switched it to "No line ending" and it works, but with a slight delay of approx. 1 second. I have no idea what every option means though. I just found out that "No line ending" does nothing to the input, it just takes the input as it was written. The rest of those options put something on the end of the input, although I don't know what's the reason why did the my input change everytime I put, for example 1500 microseconds, after 1 second to 1000 microseconds. Will explore it though. Thanks for that, if thats the solution to the problem with the pwm==0!

I'm still figuring out the problem with the boolean and my encoder switching states properly everytime I press the encoder button. I wish I had an oscilloscope in order to actually see the PWM signal, maybe there's a physical problem with the servo or the encoder. Of course that doesn't mean that my code is correctly written. I can't figure out if the issue is in debouncing the encoder button, since the loop evaluates itself fast, so if I hold the encoder button, maybe the loop evaluates for example 3-4 times before I release the switch. Maybe that's the issue? That's why I put the while(digitalRead(SW))==LOW; , in order to tell the code not to evaluate further if the button is still pressed. Also, I switch the statusPWM at the end of the loop in order to correctly pick which if statement will evaluate with every loop iteration. Can't seem to figure out if the problem is in the code written or something actually physically. I tried with many different code versions. I put different delays in each if statement, I tried to evaluate the loop withouth the while statements in each if statement. Neither did work fine for me.

Update : Here's what I was trying to do last couple of hours.

 boolean statusPWM=false;    // before void setup()
 
void loop() {
.......
.......   //same code as the inital code
 buttonState=digitalRead(SW);    

  if (buttonState==LOW && statusPWM==false) {
    Serial.println(counter);
    while (digitalRead(SW)==LOW) {
    }
  }
    if (buttonState==LOW && statusPWM==true){
    Serial.println(1000);
    display.clearDisplay();
    display.setCursor(10,5);
    display.print("PWM");
    display.setCursor(50,35);
    display.print(1000); 
    display.display();
    while (digitalRead(SW)==LOW) {
    }
  }

 
  statusPWM=!statusPWM;

I put while(digitalRead(SW)==LOW) in order to fix the debouncing issue. I also put serial.println(counter) in first if statement and serial.println(1000) in second if statement in order to see if there's something up with the encoder. I opened the serial monitor, and for example I rotate the encoder to 1500 microseconds, press the button and 1500 shows up on serial monitor, then I press it again and I get 1000, then I press it again and I get 1000.. u get the point, serial monitor looks like this after more values -- 1500,1000,1000,1450,1450,1000,1700,1700,1700,1000 etc. I can't figure out what is the issue. I believe its something with the boolean statusPWM, or something with if statements ( maybe there's a delay missing even though I put while(digitalRead(SW)==LOW); in order to fix bouncing issue. I'm really just a beginner so I don't understand everything properly but I really can't find the mistake I'm making.. it's so annoying...

I put while(digitalRead(SW)==LOW) in order to fix the debouncing issue.

I am not sure whether or not that would work in your particular case. However, I can assure you with great certainty, that no such code would work at all, in any working debouncing code that I have ever seen.

I suggest that you look very closely at the digital example sketches that come with the IDE, that demonstrate how to debounce a switch properly. Once you have that working and tested with your switch, begin adding the rest of your functionality to it.

Hey, I tried this out, found it online, hopefully written well. Still no results, same thing happens.. randomly switches even with different debounceDelays. It does something like this - 1000,1500,1500,1000,1400,1400,1000,1000,1300,1000 etc.

#include <Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define  OLED_RESET 4
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define CLK 2
#define DT 3
#define SW 4

Adafruit_SSD1306 display(SCREEN_WIDTH,SCREEN_HEIGHT,&Wire,OLED_RESET);

Servo servo;

int trenutniCLK;
int prosliCLK;
int buttonState;
int lastButtonState=HIGH;
int counter = 1000;
unsigned long lastDebounceTime=0;
unsigned long debounceDelay=50;

boolean statusPWM=false;


void setup() {
  //servo.attach(9);
  //servo.writeMicroseconds(1000);
  pinMode(CLK,INPUT);
  pinMode(DT,INPUT);
  pinMode(SW,INPUT_PULLUP);
  prosliCLK = digitalRead(CLK);
 // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.setTextColor(WHITE);
  display.setTextSize(3);
  Serial.begin(9600);
}

void loop() {
  trenutniCLK = digitalRead(CLK);
  if (trenutniCLK != prosliCLK){
    if (digitalRead(DT) != trenutniCLK) {
      counter=counter+50;
      if (counter>2000)
        counter=2000;
    } else {
      counter=counter-50;
      if (counter<1000)
        counter=1000;
    }
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
  }

  if (Serial.available()>0) {
    int pwm=Serial.parseInt();
     if (pwm>=1000 && pwm<=2000) {
      counter=pwm;
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
    }
    else if(pwm==0) {
      counter=1000;
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
    }

  }

  prosliCLK = trenutniCLK;

  int reading=digitalRead(SW);

  if (reading!= lastButtonState) {
    lastDebounceTime=millis();
  }

  if ((millis()-lastDebounceTime) > debounceDelay) {
    if (reading!=buttonState) {
      buttonState=reading;
      if (buttonState==LOW){
        if (statusPWM==false) {
          Serial.println(counter);
        }
        else if (statusPWM==true) {
          Serial.println(1000);
          display.clearDisplay();
          display.setCursor(10,5);
          display.print("PWM");
          display.setCursor(50,35);
          display.print(1000); 
          display.display();
        }
      }
    }
  }

  statusPWM=!statusPWM;
  lastButtonState=reading;
  
}

Here is the whole code again, but with the debouncing applied. As I said, I tried different values of debounceDelay, and I get the same results as with the while(digitalRead(SW)==LOW); function. I can't seem to get the proper evaluation, and the results such as : 1000,1500,1000,1300,1000,1450,1000,1700 etc.

I suggest that you look very closely at the digital example sketches that come with the IDE, that demonstrate how to debounce a switch properly. Once you have that working and tested with your switch, begin adding the rest of your functionality to it.

Hey, I just woke up, went to my laptop and fixed it in 5 minutes. And yesterday I was fixing this almost whole day. Wow.....

#include <Servo.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define  OLED_RESET 4
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define CLK 2
#define DT 3
#define SW 4

Adafruit_SSD1306 display(SCREEN_WIDTH,SCREEN_HEIGHT,&Wire,OLED_RESET);

Servo servo;

int trenutniCLK;
int prosliCLK;
int buttonState;
int counter = 1000;

boolean statusPWM=false;


void setup() {
//  servo.attach(9);
//  servo.writeMicroseconds(1000);
  pinMode(CLK,INPUT);
  pinMode(DT,INPUT);
  pinMode(SW,INPUT_PULLUP);
  prosliCLK = digitalRead(CLK);
 // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.setTextColor(WHITE);
  display.setTextSize(3);
  Serial.begin(9600);
}

void loop() {
  trenutniCLK = digitalRead(CLK);
  if (trenutniCLK != prosliCLK){
    if (digitalRead(DT) != trenutniCLK) {
      counter=counter+50;
      if (counter>2000)
        counter=2000;
    } else {
      counter=counter-50;
      if (counter<1000)
        counter=1000;
    }
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
  }

  if (Serial.available()>0) {
    int pwm=Serial.parseInt();
     if (pwm>=1000 && pwm<=2000) {
      counter=pwm;
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
    }
    else if(pwm==0) {
      counter=1000;
      display.clearDisplay();
      display.setCursor(10,5);
      display.print("PWM");
      display.setCursor(50,35);
      display.print(counter); 
      display.display();
    }

  }

  prosliCLK = trenutniCLK;

  buttonState=digitalRead(SW);

  if (buttonState==LOW) {
    if (statusPWM==false) {
    Serial.println(counter);
    while (digitalRead(SW)==LOW);
    statusPWM=!statusPWM; }
    else {
       Serial.println(1000);
       display.clearDisplay();
       display.setCursor(10,5);
       display.print("PWM");
       display.setCursor(50,35);
       display.print(1000); 
       display.display();
       while (digitalRead(SW)==LOW);
       statusPWM=!statusPWM; }
    }
  }

The problem was I was changing the statusPWM every single time the loop evaluated itself again and again, and I didn't press the encoder so I had to be lucky to press the encoder at the right time in order to get the value I wanted to get. Now, I change the statusPWM inside the if statement, only when the encoder button is pressed and I put else so that once the if statement is true, it wont evaluate else statement. And now I get the results as expected - 1000,1500,1000,1200,1000,1700,1000 ... etc. Thanks for the help!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.