byte analogReadPWM(uint8_t pin) returns the current PWM value

I propose a new funciton byte analogReadPWM(uint8_t pin) to return the value set earlier to the PWM analog output pin. The code complies and is functioning.

in a nutshell, I ran across a need to retrieve the value I set into the PWM output pin The value was set and adjusted in several parts of my program and I needed to figure out what it got changed to.

so i came across this solution by creating an adaptation to wiring_analog.c

the testing code makes a change to the PWM pin 11 within a function randomly. then after leaving the function i retrieve the value using my new function analogReadPWM() which returns the value I set there earlier.

the results are similar to digitalRead for digital output pins but instead returns the value set to the analog output

void setup()
{
 Serial.begin(57600);
 pinMode(11, OUTPUT);
 analogWrite(11, 100);
}

void loop() {
 delay(2000);
 setPWM();
 int MyPWMVal = analogReadPWM(11); // this doesn't work but it is what i need to do... HOW can I do this  and is it even possible?
 Serial.print("My PWM Value is:");
 Serial.println(MyPWMVal);
}
void setPWM(){ // represents special code setting the PWM output to some value
 int x = random(0,255);
 Serial.print("Lets set the PWM Value to:");
 Serial.println(x);
 analogWrite(11, x);
}


// THE FOLLOWING FUNCTION IS DERIVED FROM:

/*
 wiring_analog.c - analog input and output
 Part of Arduino - http://www.arduino.cc/

 Copyright (c) 2005-2006 David A. Mellis

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General
 Public License along with this library; if not, write to the
 Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 Boston, MA  02111-1307  USA

 Modified 28 September 2010 by Mark Sproul

 $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/


// Right now, PWM output only works on the pins with
// hardware support.  These are defined in the appropriate
// pins_*.c file.  For the rest of the pins, are default
// to digital output.
byte analogReadPWM(uint8_t pin){
   byte val;
   switch(digitalPinToTimer(pin)) // returns timer location if it is on a timer see NOT_ON_TIMER 
   {
           // XXX fix needed for atmega8
           #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
           case TIMER0A:
                   val = OCR0;  // get pwm duty
                   break;
           #endif

           #if defined(TCCR0A) && defined(COM0A1)
           case TIMER0A:
                   val = OCR0A; // get pwm duty
                   break;
           #endif

           #if defined(TCCR0A) && defined(COM0B1)
           case TIMER0B:
                   val = OCR0B; // get pwm duty
                   break;
           #endif

           #if defined(TCCR1A) && defined(COM1A1)
           case TIMER1A:
                   val = OCR1A; // get pwm duty
                   break;
           #endif

           #if defined(TCCR1A) && defined(COM1B1)
           case TIMER1B:
                   val = OCR1B; // get pwm duty
                   break;
           #endif

           #if defined(TCCR2) && defined(COM21)
           case TIMER2:
                   val = OCR2; // get pwm duty
                   break;
           #endif

           #if defined(TCCR2A) && defined(COM2A1)
           case TIMER2A:
                   val = OCR2A; // get pwm duty
                   break;
           #endif

           #if defined(TCCR2A) && defined(COM2B1)
           case TIMER2B:
                   val = OCR2B; // get pwm duty
                   break;
           #endif

           #if defined(TCCR3A) && defined(COM3A1)
           case TIMER3A:
                   val = OCR3A; // get pwm duty
                   break;
           #endif

           #if defined(TCCR3A) && defined(COM3B1)
           case TIMER3B:
                   val = OCR3B; // get pwm duty
                   break;
           #endif

           #if defined(TCCR3A) && defined(COM3C1)
           case TIMER3C:
                   val = OCR3C; // get pwm duty
                   break;
           #endif

           #if defined(TCCR4A)
           case TIMER4A:
                   val = OCR4A; // get pwm duty
                   break;
           #endif

           #if defined(TCCR4A) && defined(COM4B1)
           case TIMER4B:
                   val = OCR4B; // get pwm duty
                   break;
           #endif

           #if defined(TCCR4A) && defined(COM4C1)
           case TIMER4C:
                   val = OCR4C; // get pwm duty
                   break;
           #endif

           #if defined(TCCR4C) && defined(COM4D1)
           case TIMER4D:				
                   val = OCR4D; // get pwm duty
                   break;
           #endif


           #if defined(TCCR5A) && defined(COM5A1)
           case TIMER5A:
                   val = OCR5A; // get pwm duty
                   break;
           #endif

           #if defined(TCCR5A) && defined(COM5B1)
           case TIMER5B:
                   val = OCR5B; // get pwm duty
                   break;
           #endif

           #if defined(TCCR5A) && defined(COM5C1)
           case TIMER5C:
                   val = OCR5C; // get pwm duty
                   break;
           #endif

           case NOT_ON_TIMER:
           default:
                   val = digitalRead(pin);
   }
    return(val);
}

Thank you for considering this addition.
ZHomeSlice

zhomeslice:
in a nutshell, I ran across a need to retrieve the value I set into the PWM output pin

I find myself forgetting things too. Old age, I guess.

Why not just have a variable to hold the latest value and update it every place the PWM value gets changed. It would make for much shorter and simpler code.

Better still why not write your program so the PWM value is only changed in one piece of code thus avoiding duplication and errors.

...R

:slight_smile:

my thought was to retrieve the values without having to search for them just simply get them directly from the register where they are finally stored.

It probibly isn’t a critical function to have like you said creating a variable to handle things works fine. what made me think of this is a trick i use to toggle a digital point of an off

   digitalWrite(13,!digitalRead(13)); // toggles the pin 13 to its opposite state in one line.

if I had direct access to the value there I could adjust the output by a value on a one line

  analogWrite(11,(byte) constrain( analogReadPWM(11)+X, 0, 255));

I was thinking convenience rather than Forgetfulness lol

function ShowAllOutputsNow(){
  for (Pin = 0;Pin<=13;Pin++){
    Serial.println(analogReadPWM(Pin));
  }
}

See arduino leonardo - Directly read analog voltage using PWM duty cycle timer registers - Arduino Stack Exchange.