LED dimmer not switching

Hello,

I am using the Arduino Uno to prototype an LED dimmer based on an ADC input but the LED just stays on and doesn’t switch. I checked that with an oscilloscope too.
The ADC is working as intended. I checked it with the serial monitor and with different voltages.

I am using the timer output compare registers to create a 200Hz PWM with a variable duty cycle.

Pin 7 will be connected to the gate of an N-channel mosfet.

Any idea what could be wrong? I suspect it has something to do with the ISRs because if I comment them out the LED is off. (duh)

#define F_CPU 16000000UL       

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

void setup() {
    Serial.begin(115200);   
    sei();
    DDRC = 0;                      // Input for ADC
    DDRD |= (1<<PD7);         // PWM Output
    ADMUX = 0;                  // use ADC0
    ADMUX |= (1 << REFS0);    // use AVcc as the reference
    ADMUX |= (1 << ADLAR);    // Right adjust for 8 bit resolution
    ADCSRA |= (1 << ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);  // Enable the ADC, 128 prescale 
    
    TIMSK2 |= (1<<OCIE2B)|(1<<OCIE2A)|(1<<TOIE2); // enable Timer/Counter Output Compare Match B Interrupt, enable Timer/Counter Output Compare Match A Interrupt, Ebable Timer/Counter Overflow Interrupt
    TCCR2A |= (1<<WGM01); //CTC Mode enabled
    TCCR2B |= (1 << CS22)|(1<<CS21)|(1<<CS20); //prescale 1024
    OCR2A = 39; // 200Hz PWM (upper threshold of timer compare register)
}

void loop() {


  ADCSRA |= (1 << ADSC)|(1 << ADIF);    // Start the ADC conversion -> ADSCRA = 0101 0000
      
      
  while(ADCSRA & (1 << ADIF) == 0); //ADSCRA = 0101 0000 & 0001 0000 = 1 ---- 0100 0000 & 0001 0000 = 0 -> conversion finished
  
    
  OCR2B = ADCH*39/255; //scaling of OC2RB, since OC2RB (lower threshold of timer compare register) must not be higher than OC2RA!

  

}

ISR(TIMER2_COMPA_vect) {

   PORTD |= (1<<PD7);         // LED is off (N-FET shorts current to ground)
}

ISR(TIMER2_COMPB_vect) {

  if (OCR2B > 5){                 // if OCR2B is lower than 5 LEDs are off (N-FET shorts current to ground)
    PORTD |= (1<<PD7);    

  } else {
    PORTD &= ~(1<<PORTD1);   // LED turns on
  }
}
PORTD |= (1<<PD7);   

  } else {
    PORTD &= ~(1<<PORTD1);   // LED turns on

Why the different mask constants?

That was just a copy paste error. Oops.
I changed it to 1<<PD7 but it’s still not switching sadly.

Hi,
Welcome to the forum.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
You do have the source of the MOSFET and gnd of the LED supply and the UNO gnd connected together?
What MOSFET do you have?

Thanks..Tom.. :slight_smile:

Hi,

I should have mentioned that my current breadboard design looks a bit different and is much simpler. No MOSFET or LED driver IC is involved yet as I am just testing the software.

Here's a simple schematic as requested.

I tested the code without the ADC and I manually gave OCR2B a value in the setup. It outputs a square wave atleast but as I intended I want OCR2B to be changed by the ADC.

The error seems to boil down to this line:

ISR(TIMER2_COMPB_vect) {

  if (OCR2B > 5){                 // if OCR2B is lower than 5 LEDs are off (N-FET shorts current to ground)
    PORTD |= (1<<PD7);

Which made me realize I had written my code with the inverting MOSFET in mind and the compare arrow pointed in the wrong direction!

ISR(TIMER2_COMPA_vect) {
   PORTD &= ~(1<<PD7);
}

ISR(TIMER2_COMPB_vect) {
  if (OCR2B < 5){
    PORTD &= ~(1<<PD7); 
  } else {
    
    PORTD |= (1<<PD7); 
  }
}

Now it works as intended. Double oops.
My only issue is that the frequency doesn't match what I had estimated. It's 60Hz according to my oscilloscope.
I used this formula from the datasheet to calculate :

fOcnx is the desired 200Hz. I solved for OCRNx which is 39 with a scale N of 1024. CPU speed is 16MHz.