I am prototyping a simple LED dimmer on an Arduino Uno (Atmega328p) and I have issues with the PWM frequency and duty cycle I am trying to adjust. To get a frequency of 200Hz flat I am using the CTC mode and I used the formula in the datasheet (OCR2A = (F_CPU/2N200Hz)-1) to calculate the upper output compare register (OCR2A). It's 38 in my case. The lower output compare register (OCR2B) is being controlled by an ADC input.
The ADC is working fine. I checked it with the serial monitor. So that part of the code can be ignored.
My main gripe is the frequency. According to my cheap handheld oscilloscope the frequency is stuck at 60Hz even if I change OCR2A. I can't explain why.
Then there's a problem with the duty cycle. If OCR2B is at 6 the duty cycle is at ca. 13%. If OCR2B is at 37 the duty cycle is close to 0%. I expected the duty cycle to be much higher the lower OCR2B is. Why is this not the case?
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
void setup() {
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: N=1024
OCR2A = 38; // 200Hz PWM (upper threshold of timer compare register), OCR2A = (F_CPU/2*N*200Hz)-1
}
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*38/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);
}
ISR(TIMER2_COMPB_vect) {
if (OCR2B < 5){
PORTD &= ~(1<<PD7);
} else {
PORTD |= (1<<PD7);
}
}
TCCR2A |= (1<<WGM01); //CTC Mode enabled
). Is it just that you want to use a non PWM pin? \$\endgroup\$TCCR2B |= (1<<WGM22);
? \$\endgroup\$