Rotary Phone toggle switch with analog write

Hi,
I'm working on a light/doorbell from an old rotary phone. My problem is I can figure out how to make a toggle switch, turn the light on/off but keep the brightness. Currently the toggle code uses digitalWrite and its either HIGH or LOW which is 100% or off.
I'm using the rotary dial to get a number between 1 and 10 and that corresponds to 10%-100% brightness. The brightness works great with the rotary. I'm multilying by 25.5 to get a value between 0 and 255 for the LED OUTPUT. Now the only thing left is using the answer/hangup as my toggle and somehow keeping the selected brightness.

Happy Holidays,
Adam

//Rotary Dial
int needToPrint = 0;
int count;
int in = 2;
int lastState = LOW;
int trueState = LOW;
long lastStateChangeTime = 0;
int cleared = 0;
int dialHasFinishedRotatingAfterMs = 100;
int debounceDelay = 10;

// LED light 

int ledState=LOW;
const int brightness=3;
int buttonPin=11;
int buttonStateNew; //current state of button
int buttonStateOld; //previous state of button

void setup()
{
Serial.begin(9600);
pinMode(in, INPUT);
pinMode(brightness, OUTPUT);
pinMode(buttonPin,INPUT_PULLUP);
buttonStateNew = digitalRead(buttonPin);
}

void loop()
{
int reading = digitalRead(in);

if ((millis() - lastStateChangeTime) > dialHasFinishedRotatingAfterMs) {
// the dial isn't being dialed, or has just finished being dialed.
if (needToPrint) {
// if it's only just finished being dialed, we need to send the number down the serial
// line and reset the count.
Serial.println(count, DEC);

//output for pin 3 LED brightness from 1 to 255. 
analogWrite(brightness, 25.5 * count);

//reset the count
needToPrint = 0;
count = 0;
cleared = 0;
}

//on-off switch from headset. normally open on pin 11. 
buttonStateOld = buttonStateNew;
buttonStateNew = digitalRead(buttonPin);

if(buttonStateOld == HIGH && buttonStateNew == LOW)
{
  ledState = !ledState;
 digitalWrite(brightness, ledState);
}
}




if (reading != lastState) {
lastStateChangeTime = millis();
}
if ((millis() - lastStateChangeTime) > debounceDelay) {
// debounce - this happens once it's stablized
if (reading != trueState) {
// this means that the switch has either just gone from closed->open or vice versa.
trueState = reading;
if (trueState == HIGH) {
// increment the count of pulses if it's gone high.
count++;
needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)
}
}
}
lastState = reading;
}

IMHO, you should be able to do just that if you change this part of your code:

if(buttonStateOld == HIGH && buttonStateNew == LOW)
{
  ledState = !ledState;
  digitalWrite(brightness, ledState);
}

to this:

if(buttonStateOld == HIGH && buttonStateNew == LOW)
{
  ledState = !ledState;
  
  if(ledState == LOW) digitalWrite(brightness, LOW);
  else analogWrite(brightness, 25.5 * count);
  //here assuming the LED is ON when 'brightness' is HIGH.
  //do the conversive if the LED is ON when 'brightness' is LOW.
}

hope that helps...

Thank you sherzaad, I agree with the logic of the program. So what I think is hppening it is running through this loop and counting, the second it finishes it outputs the number and resets to zero. If i move the //reset the count, it outputs the values and adds then together infinately. dialing 4 and 9 yeilds 13… etc. so I know I need to reset it. If i move the chunk of code you helped me with before the reset, it turns the led off, but not back on. i think thats because its still resetting the ‘count’ for led brightness, so its always ‘LOW’… so the digitalWrite(brightness, LOW) always happens.

Granted I’m not a great, or even moderately good programmer, so I appreciate the help greatly. Been enjoying the learning experiance.

Cheers,
Adam

//output for pin 3 LED brightness from 1 to 255.
analogWrite(brightness, 25.5 * count);

//reset the count
needToPrint = 0;
count = 0;
cleared = 0;
}

//on-off switch from headset. normally open on pin 11.
buttonStateOld = buttonStateNew;
buttonStateNew = digitalRead(buttonPin);


if(buttonStateOld == HIGH && buttonStateNew == LOW)
{
  ledState = !ledState;
 
  if(ledState == LOW) digitalWrite(brightness, LOW);
  else analogWrite(brightness, 25.5 * count);
  //here assuming the LED is ON when 'brightness' is HIGH.
  //do the conversive if the LED is ON when 'brightness' is LOW.
}

'count' does seem to get reset after a dial. so your deduction seems sound! :wink:

then what you probably need to do is to store the resutls of '25.5*count' to a new global variable (let's call it 'brightness_level') BEFORE 'count' is reset and use that for the 'analogwrite'.

As this new variable will only get updated whenever a dial is done, along with the mod to your does that I already suggested, it should resolve your current issue.

hope that helps...

I know were close! So I added a new global variable called brightnessLevel, and also tried moving the on/off switch before the reset to zero code. Anything after the brackets where the reset to zero code is, even 'brightnessLevel', is reset to a repeating string of zeros. The on/off switch doesn't turn the light on and off inside the bracket, because it seems it runs that code until the rotary is finished dialing, and doesnt read the code again until its dialed again. I think that would explain why it doesn't "see" the code. If I place the on/off after the reset of 'count', all values are a srting of zeros, so its stuck in LOW. I added a few more comments on the code to hopefully help.

Cheers.
Adam

//Rotary Dial
int needToPrint = 0;
int count;
int in = 2;
int lastState = LOW;
int trueState = LOW;
long lastStateChangeTime = 0;
int cleared = 0;
int dialHasFinishedRotatingAfterMs = 100;
int debounceDelay = 10;


// LED light 

int brightnessLevel;
int ledState=LOW;
const int brightness=3;
int buttonPin=11;
int buttonStateNew; //current state of button
int buttonStateOld; //previous state of button

void setup()
{
Serial.begin(9600);
pinMode(in, INPUT);
pinMode(brightness, OUTPUT);
pinMode(buttonPin,INPUT_PULLUP);

}

void loop()
{
int reading = digitalRead(in);


if ((millis() - lastStateChangeTime) > dialHasFinishedRotatingAfterMs) {
// the dial isn't being dialed, or has just finished being dialed.
if (needToPrint) {
// if it's only just finished being dialed, we need to send the number down the serial
// line and reset the count.
Serial.println(count, DEC);
  int brightnessLevel=count; // storing brightnessLevel as a global variable

//output for pin 3 LED brightness from 1 to 255. 
analogWrite(brightness, 25.5 * brightnessLevel);

//on-off switch from headset. normally open on pin 11. 
buttonStateOld = buttonStateNew;
buttonStateNew = digitalRead(buttonPin); //reading pin 11 for open/closed cicuit 

if(buttonStateOld == HIGH && buttonStateNew == LOW)
{
  ledState = !ledState;
  // LED is on when brightness is HIGH
  //do the converse if LED is on and brightness is LOW
  if(ledState == LOW) digitalWrite(brightness, LOW);
  else analogWrite(brightness, 25.5 * brightnessLevel);
}
// anything inside this bracket seems to run, untill the dialer finishes. 

}
//reset the count
needToPrint = 0;
count = 0;
cleared = 0;
// both brightnessLevel and count retuen a string of zeros when placed inside this bracket. 
}





if (reading != lastState) {
lastStateChangeTime = millis();
}
if ((millis() - lastStateChangeTime) > debounceDelay) {
// debounce - this happens once it's stablized
if (reading != trueState) {
// this means that the switch has either just gone from closed->open or vice versa.
trueState = reading;
if (trueState == HIGH) {
// increment the count of pulses if it's gone high.
count++;
needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)
}
}
}
lastState = reading;
}
      buttonStateOld = buttonStateNew;
      buttonStateNew = digitalRead(buttonPin); //reading pin 11 for open/closed cicuit

      if (buttonStateOld == HIGH && buttonStateNew == LOW)

1st line - the button states are set equal

3rd line - button states are compared

As is the button states compare will never be true.

Move the 1st line *after * the compare.

Thanks so much to dougp and sherzaad. It works perfectly now. I greatly appreciate your help. I even managed to figure out the one strange occurance when I turn off the light with the hangup/answer–> turn the light back on with the rotary–> then use the hangup/answer to turn off. It would requires 2 pushes because the first one is, ‘in theory’, turning the light back on because it did not know I ran the rotary dial to turn it back on.

Attached is the code, if you have any best practice structure changes, let me know.
Again. much appreciated.

//Rotary Dial
int needToPrint = 0;
int count;
int in = 2;
int lastState = LOW;
int trueState = LOW;
long lastStateChangeTime = 0;
int cleared = 0;
int dialHasFinishedRotatingAfterMs = 100;
int debounceDelay = 10;


// LED light 

int brightnessLevel=10;
boolean ledState=LOW;
const int brightness=3;
int buttonPin=11;
boolean buttonStateNew; //current state of button
boolean buttonStateOld; //previous state of button

void setup()
{
Serial.begin(9600);
//rotary input
pinMode(in, INPUT);
//LED input or output
pinMode(brightness, OUTPUT);
pinMode(buttonPin,INPUT);

}

void loop()
{
int reading = digitalRead(in);

if ((millis() - lastStateChangeTime) > dialHasFinishedRotatingAfterMs) {
// the dial isn't being dialed, or has just finished being dialed.
if (needToPrint) {
// if it's only just finished being dialed, we need to send the number down the serial
// line and reset the count.
Serial.println(count, DEC);
  brightnessLevel=count;// saves the count as a global variable
  ledState=HIGH; // tells the on/off switch that the LED is ON 

//output for pin 3 LED brightness from 1 to 255. 
analogWrite(brightness, 25.5 * brightnessLevel);

//reset the count
needToPrint = 0;
count = 0;
cleared = 0;
}

//on-off switch from headset. normally open on pin 11.

buttonStateNew = digitalRead(buttonPin); //reading pin 11 for open/closed cicuit
if(buttonStateOld == HIGH && buttonStateNew == LOW)
{
  ledState = !ledState;
  // LED is on when brightness is HIGH
  //do the converse if LED is on and brightness is LOW
  if(ledState == LOW) digitalWrite(brightness, LOW);
  else analogWrite(brightness, 25.5 * brightnessLevel);
  delay(350);// delay for the hang up switch bouncing on return
}
buttonStateOld = buttonStateNew;


}

if (reading != lastState) {
lastStateChangeTime = millis();
}
if ((millis() - lastStateChangeTime) > debounceDelay) {
// debounce - this happens once it's stablized
if (reading != trueState) {
// this means that the switch has either just gone from closed->open or vice versa.
trueState = reading;
if (trueState == HIGH) {
// increment the count of pulses if it's gone high.
count++;
needToPrint = 1; // we'll need to print this number (once the dial has finished rotating)
}
}
}
lastState = reading;
}

It's great you got it working. One important thing is to understand why the code I pointed out must be that way.