Volume up/down on Preamp

I have nearly finished my preamp control with the Uno and have run into a issue that I cannot seem to solve and wondered if someone could review the code in lines 140 to 156.

I have the uno connected to two encoders one for volume up and down and one for the selection of input. Everything works beautifully but I cannot seem to get the code to give me the result I seek. I have a wireless remote control that comes in on four of the pins to the uno that operate as expected increments and decrements the volume.

The problem is when the increment volume remote is pressed the value increases but as soon as I release it it goes back to the starting value like wise with the decrement. I wish for the volume to be the final volume position once released.

willow_II_fourth_attempt.ino (4.55 KB)

You are interested in changing the volume only if you detect an attempt to increment or decrement it ?
Why do you detect increments and decrements and also attempt to read a value from the encoder ?

Your code:

  newVolume = finalVolume;
  if (remotepinstate1 == 0 && remotepinstate2 == 0) {
    newVolume = Volume.read();
    finalVolume = newVolume;

  else if (remotepinstate1 == 1 && finalVolume < 255) {
  else if (remotepinstate2 == 1 && finalVolume > 0) {

What happens if you change the code as follows:

  // newVolume = finalVolume;
  // if (remotepinstate1 == 0 && remotepinstate2 == 0) {
  //   newVolume = Volume.read();
  //   finalVolume = newVolume;
  // }

  if (remotepinstate1 == 1 && finalVolume < 255) {
  else if (remotepinstate2 == 1 && finalVolume > 0) {

You don’t anyway appear to be using the variable newVolume.

Thanks 6v6gt for your reply.

Just tried your suggestion and it does not work my encoder needs to have the line

newVolume = Volume.read(); otherewise I do not get the encoder being read at all!

Because I need to read the value of the encoder to establish a reading for finalVolume that is then displayed on the OLED display. Also it is why I have the line finalVolume=newVolume; so the final volume is displayed.

What needs to happen is once I release the remote control button the new value for finalVolume that has been incremented or decremented is the final volume to be displayed.

OK. It looks like I didn't take enough time to understand your set up.
You are using two buttons of a wireless remote control for 'volume' which is somehow connected to pins 10 (up) and 12 (down).
You are also using an encoder to control the volume, and this is connected to pins 2 and 3.
That is, the volume can be changed either through the wireless remote control or through the encoder.
Is this correct ?

Nearly there I'm using two encoders one on pins 2,3 and the other one on A0,A1 one for volume and one for the selection ie Tuner Phone etc.

Encoder Volume(2,3);
Encoder Selector(A0, A1);

I'm then using for the remote control four pins 10,12,A2,A3 for volume up/down and selector up/down.

Then it is talking to a digital volume chip via A4,A5 on the I2C bus.

Everything works well it is just the fact that when I release either volume up or volume down the newVolume; read by the encoder does not take the finalVolume; that has been generated by the if else loops.

If you look at the draw loop it make references to the three draw functions that produce the title page;
bignumbers; and bigletters; which draw the items listed.

I know it is something obvious and very simple but I've been struggling with this for the last few days and would love to finish this project and move onto my CNC machine next so any help would be greatly appreciated.

OK. I see you've commented out the code which writes the volume value to the digital potentiometer.

Anyway, it is clear that the any changes to the value of finalVolume which are made by setting pin 10 or 12 high are lost as soon as these pins are both low because finalVolume is then overwritten from the value read from the encoder by the following statements:

   newVolume = Volume.read(); 

What happens if you comment out the last line like so. Does the remote control work as expected, but the encoder not ?

// finalVolume=newVolume;

Thanks for the reply just tried that and it does not work.

I even tried this,

if (remotepinstate1 == 0 && remotepinstate2 == 0) {
finalVolume = Volume.read();


if(remotepinstate1 == 1 && finalVolume<255) {
else if (remotepinstate2 == 1 && finalVolume>0) {

But what I think is happening is that the register or where the read value when the encoder is read is somehow storing the information but not allowing it to be overridden otherwise either of the volume up or down should create a new value in finalVolume but it reverts back to what it was in the beginning.
That is why I tried to create a new value like newVolume to allow me to do that but it does not take.

I know this is going to be something simple but just cannot spot it at all.

OK. Can you post a link to the encoder you are using and to the library which you are using if you downloaded it.
One thing I don’t understand about your setup, and I am sure there is a good reason for it, is this. If you are OK with setting the volume through buttons on a wireless remote control, why do you use a special encoder. If you want to set the volume locally on the arduino (without the remote control) you could have used two buttons instead of the encoder (or am I missing something?).

Try something like this,declare offsetVolume somewhere it won’t get reset.

    finalVolume = Volume.read()+offsetVolume; //you must ensure this stays between 0 and 255 I guess

  if (remotepinstate1 == 1 && offsetVolume < 255) {
  if (remotepinstate2 == 1 && offsetVolume > 0) {

EDIT: YOU are reverting the finalVolume back to the encoder level by setting it to Volume.read().

Thanks 6v6gt and Smajdalf for your replies.

To answer 6v6gt first, this is a hifi preamp and it is a stand alone device and uses encoders for volume and selection, I have added remote control to it as I have with my other preamp as it is more convenient to use the remote whilst listening to music rather than get out of ones chair to adjust it.

The library I’m using is the one by Paul Stoffregen called “Encoder”. I chose this library as it allows me to use interrupts for both encoders as well as true quadrature reading. So since I’m using a Bourns 64 pulse per revolution encoder each change will give me the 4X to generate the 255 count the digital potentiometer chip needs.

Smajdalf your code nearly works it is so close to working I can taste it!

This is the modified code to suit what variable I have already declared.

finalVolume = Volume.read()+newVolume;
if (remotepinstate1 == 0 && remotepinstate2 == 0) {


if(remotepinstate1 == 1 && newVolume<255) {

else if (remotepinstate2 == 1 && newVolume>0) {


What happens now is the value does indeed increment and stay when the increment button is released but when decrementing it does not go below the initial value of the encoder???
It is as I suspect the value of the encoder is being stored in a register and is not allowed to be changed.

Soo close!

No offence ment but you don’t understand how variables work. Forget registers, it’s differnet very low level thing you won’t meet unless you really know what you are doing.Try to read something about variables. Basicly:
Variables you declare during the program change ONLY when YOU change them in the program such as with =, += or ++ operator. When posting here use the code tags. What you are doing is:

finalVolume = Volume.read()+newVolume;  //there you read the encoder setting and add newVolume and store result into final Volume
 if (remotepinstate1 == 0 && remotepinstate2 == 0) {

 if(remotepinstate1 == 1 && newVolume<255) {
  newVolume++; //there you increment newVolume by one
else if (remotepinstate2 == 1 && newVolume>0) {

Your problem is that newVolume may be only positive - you can only increase the value read from encoder, not decrease!

What WILL work:

//Define variables somewhere to inicialize them only once:
int finalVolume, remoteVolume=0; //values can now be negative which makes things easier
int maxVolume=255;  //change limits as you wish; I expect minimal value is 0

//set new value depending on encoder settings
finalVolume = Volume.read()+newVolume;
//now check if finalVolume is not out of range
if (finalVolume < 0) finalVolume=0;
else if (finalVolume > maxVolume) finalVolume=maxVolume;
//now update settings from the remote
if(remotepinstate1 == 1 && remoteVolume<maxVolume) {
else if (remotepinstate2 == 1 && remoteVolume>(-maxVolume)) {

Smajdalf Many thanks for your reply and no offence taken at all. I'm a newbie at this programming and this is my first Arduino project and I'm eager to learn the intricacies of it all.

Just tried your latest code and unfortunately it does not work it neither increments or decrements. Don,t forget the finalVolume is the variable that is displayed on the screen somewhere there should be a statement that finalVolume = remoteVolume yes?

just added those comments and now it increments and decrements again but does not retain the final value but the old original reading of the encoder.

Understand your comment about the variable changes but what I'm driving at is the value that the encoder has been read into "Volume" is stored all the time and not overridden with such a statement as finalVolume=Volume.read().
So as you and 6v6gt surmised I'm constantly overriding the value of finalVolume with the old retained value of Volume everytime I release the remote button.
I certainly appreciate your help and I'm getting a much clearer understanding how these fabulous Arduino's work and this great Forum.

Sorry, I made a mistake, there should be
finalVolume = Volume.read()+remoteVolume;
instead of
finalVolume = Volume.read()+newVolume;

On this line you read new encoder value and update it with the offset chosen by the remote.

Smajdalf I had to wait all day to get home from work and try this.

It was definitely worth the wait!!

Thank you so much it works like a charm I will post a short video of the preamp when complete.

This is what open source and the internet is all about.