Is there a way to know the output state of a pin (~3) running a PWM signal?

On my Arduino UNO, I have set pin ~3 to run PWM. Is there a way to know when the signal is ON and when it is OFF?

I am trying to eliminate background noise from an LED light intensity reading, also called background subtraction. I am measuring the light with a phototransistor connected to the same Arduino. I am doing the background subtraction by pulse width modulating the LED and then subtracting the light measure in the OFF part of the PWM (This is the ambient light or noise) from the light measure from the ON part of the PWM (This is the LED and the noise). Which should leave only the light measured from the LED.

I've made a "bad" solution where I have connected pin 3 to pin 4. I then use digitalRead on pin 4 and just read the state of the pin that way. But I am hoping for a more internal solution, something where I for example read a register value.

It didn't work to use digitalread on pin 3, it just comes out 0.

My PWM is set up like this:

void setup(void)
{
  //PWM 490 Hz
  pinMode(3, OUTPUT);    // OCR2B
  pinMode(11, OUTPUT);   // OCR2A
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);  
  TCCR2B = _BV(CS22);

   //PWM 75 duty cycle
  OCR2B = 170;
  OCR2A = 200;
}
void loop(void)
{
// Nothing here
}

Is there a better way to know if Pin 3 is in an ON state or an OFF state?

Thank you.

EDIT:
I've moved OCR2B and OCR2A into the setup part of the code. Since it was a bit of an eyesore to have it in the loop part. As suggested by @aarg

Why are you endlessly resetting OCR2A and OCR2B?

AprilDC:
I've made a "bad" solution where I have connected pin 3 to pin 4. I then use digitalRead on pin 4 and just read the state of the pin that way.

Why is that a bad solution? Does it achieve what you want?

I don't think there is any register to read apart from PORTD itself - which is what digitalRead() does. The digitalWriteFast library also has a digitalReadFast().

I wonder would the changing state of the pin cause a pinChange interrupt - I suspect it would.

If not, you could connect a jumper from your PWM pin to one of the external interrupt pins and use attachInterrupt() to call an ISR when the value changes.

...R

PS. I agree with @aarg

@Robin2 - Thank you for your answer. I am not really sure if it is achieving what I want. I am doing some math on the measurements, and I am not certain that the values are right when the pin switches from ON to OFF.

So I would like to make it more certain by checking internally.

The attachInterrupt() sounds interesting, would it be better than connecting a jumper to pin 4 and using digitalread?

PS. I agree with @aarg

AprilDC:
This sounds interesting, would it be better than connecting a jumper to pin 4 and using digitalread?

Would what be better?

If I have a solution that works and then I discover an alternative that also works I cannot say that either is better unless one of them also solves another problem that was getting in the way of a properly working system.

...R

You can use the PIND register directly, and it gives accurate readings.

// Pin 3 is PD3
if ((PIND & 8) == 0)
{
  // Output is low
}
if ((PIND & 8) != 0)
{
  // Output is high
}

I really thought digitalRead() would have given accurate readings if PIND did. I thought they did the same thing. But my test code on an Arduino UNO falsifies that. digitalRead(3) always returns 0, whereas (PIND & 8 ) returns what I expected. Weird.

Jimmus:
I really thought digitalRead() would have given accurate readings if PIND did.

The difference is timing. digitalRead() is slow and the pin may have changed its value by the time it gets round to reading it.

Try digitalReadFast from the digitalWriteFast library

...R

How are you getting the analog readings? They must be a lot slower than the digital ones.

Well, here's the code in wiring.c that handles digitalRead():

int digitalRead(uint8_t pin)
{
	uint8_t timer = digitalPinToTimer(pin);
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);

	if (port == NOT_A_PIN) return LOW;

	// If the pin that support PWM output, we need to turn it off
	// before getting a digital reading.
	if (timer != NOT_ON_TIMER) turnOffPWM(timer);

	if (*portInputRegister(port) & bit) return HIGH;
	return LOW;
}

So. The digitalRead() function actually has special code to TURN OFF THE PWM TIMER if it was on that pin. And THEN it returns LOW.

No wonder it didn't work.

Jimmus:
So. The digitalRead() function actually has special code to TURN OFF THE PWM TIMER if it was on that pin. And THEN it returns LOW.

No wonder it didn't work.

Good detective work.

It would be interesting to try digitalReadFast() (from the digitalWriteFast library).

...R

@Jimmus -

You can use the PIND register directly, and it gives accurate readings.

That looks perfect. Thank you very much.

Also great that you found the reason digitalRead() didn't work!

@aarg

How are you getting the analog readings? They must be a lot slower than the digital ones.

I am using analogRead(). It takes 100 micro sec. to do a reading, which is enough. But I will have to look out for this!