Hi all this is my first post so please be gentle . I have been playing with the ADC and PWM outputs. Attached is a schematic of my setup. I have a voltage divider with a light dependent resistor as R1 and the center node attached to pin PC1 and the center post of a potentiometer connected to pin PC0. I am varying the resistance of the LDR with an LED being driven by pwm from pin PD6.
My goal is to have the voltage of the voltage divider match the voltage coming out of the pot. So if I turn up the pot the duty cycle of the pwm driving the LED is increased making the LED brighter and bringing the voltage from the voltage divider go up to match the output from the pot. Here is the code that I am using.
volatile int pot;
volatile int ldr;
uint8_t channel;
int adcValue[2];
int error;
int pwmValue = 0;
void setup() {
Â
 cli();
Â
 ADMUX |= (1<<REFS0);                  //set adc ref. to AVcc
 ADCSRA |= (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);    //set prescaler to 128
 channel = 0;                      //set channel to 0
 ADMUX = (0xF0 & ADMUX) | channel;           //set multiplexer to ADC0
 ADCSRA |= (1<<ADEN);                  //turn on ADC
 ADCSRA |= (1<<ADIE);                  //enable ADC interrupts
 ADCSRA |= (1<<ADSC);                  //start first conversion
 DDRD = 0b01000000;                   //set OC0A to output
 TCCR0A |= (1<<WGM00) | (1<<WGM01);           //set fast pwm mode
 TCCR0A |= (1<<COM0A1);                 //set compare match mode for pwm
 TCCR0B |= (1<<CS00) | (1<<CS01);            //set prescaler to 64
 Serial.begin(115200);
Â
 sei();                         //enable global interrupts
}
void loop(){
 error = ldr - pot;
 if (error > 0) pwmValue--;
 if (error < 0) pwmValue++;
 OCR0A = pwmValue;
 Serial.print(" ");
 Serial.print(ldr);
 Serial.print(" ");
 Serial.print(pot);
 Serial.print(" ");
 Serial.print(error);
 Serial.print(" ");
 Serial.print(pwmValue);
 Serial.print("\n");
}
ISR (ADC_vect){
 adcValue[channel] = ADC;              //store values from ADC
 pot = adcValue[0];                Â
 ldr = adcValue[1];
 channel++;                     //increment channel
 if (channel >1) channel = 0;
 ADMUX = (0xF0 & ADMUX) | channel;         //change multiplexer
 ADCSRA |= (1<<ADSC);                //start next conversion
       Â
}
As it is right now it works, but if I comment out the Serial.Begin(115200) and all the Serial.print lines it stops working. The led just stays at one fixed brightness and doesn't vary no matter how much I turn the potentiometer. The odd thing is I wrote up the same sketch using software driven pwm and with that it works with the Serial.being and Serial.print lines commented out and doesn't work if I leave them in. Here is that code.
volatile int pot;
volatile int lsr;
uint8_t channel;
int adcValue[2];
int error;
int pwmValue = 0;
int pwmTickCount = 0;
int pwmTotal = 100;
bool pinState = true;
void setup() {
Â
 cli();
Â
 ADMUX |= (1<<REFS0);                  //set adc ref. to AVcc
 ADCSRA |= (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);    //set prescaler to 128
 channel = 0;                      //set channel to 0
 ADMUX = (0xF0 & ADMUX) | channel;           //set multiplexer to ADC0
 ADCSRA |= (1<<ADEN);                  //turn on ADC
 ADCSRA |= (1<<ADIE);                  //enable ADC interrupts
 ADCSRA |= (1<<ADSC);                  //start first conversion
 DDRD = 0b01000000;
 TCCR1A = 0;                      //set entire TCCR1A register to 0
 TCCR1B = 0;                      //same for TCCR1B
 TCNT1 = 0;                      //initialize counter value to 0
 OCR1A = 10;                      //set time for each tick
 TCCR1B |= (1 << WGM12);                //turn on CTC mode
 TCCR1B |= (1 << CS11);                 //set prescaler to 256
 TIMSK1 |= (1 << OCIE1A);                //enable timer compare interrupt
 //Serial.begin(115200);
Â
 sei();                         //enable global interrupts
}
void loop(){
 pwmHandle();
Â
 error = lsr - pot;
 if (error > 0) pwmValue--;
 if (error < 0) pwmValue++;
 /*Serial.print(" ");
 Serial.print(lsr);
 Serial.print(" ");
 Serial.print(pot);
 Serial.print(" ");
 Serial.print(error);
 Serial.print(" ");
 Serial.print(pwmValue);
 Serial.print("\n");*/
}
ISR (TIMER1_COMPA_vect)
{
 pwmTickCount++;
}
void pwmHandle() {
Â
 if(pinState == true) {
  if(pwmTickCount >= pwmValue)
   pinState = false;
  } else {
    if (pwmTickCount >= pwmTotal){
     pinState = true;
     pwmTickCount = 0;
    }
   }
 if (pinState == true) {
  PORTD = (0b01000000);
 }
 if (pinState == false) {
  PORTD = (0b00000000);
 }
}
ISR (ADC_vect){
 adcValue[channel] = ADC;
 pot = adcValue[0];
 lsr = adcValue[1];
 channel++;
 if (channel >1) channel = 0;
 ADMUX = (0xF0 & ADMUX) | channel;
 ADCSRA |= (1<<ADSC);
Â
}
I thought it might be related to what timer I was using so I rewrote both of them using different timers with the same results. I am stumped by this and would appreciate any help.
Such low level code is hard to analyze. Why don't you use the standard functions? Why interrupts? Why T0?
Serial.begin() may initialize further registers, which you don't handle in your setup.
Even if a LDR is not very fast, you may get out of it kind of a square wave, according to the PWM signal of the LED.
DrDiettrich:
Why don't you use the standard functions?
By the standard functions do you mean analogRead and analogWrite? I was trying to stay away from those because of their overhead. I am just practicing using the using the adc and the pwm outputs for use in a project, so I was trying to save on cpu time.
DrDiettrich:
Why interrupts? Why T0?
I wrote other sketches doing the same thing without the interrupts. I was using the macro loop_until_bit_is_clear but I didn't know what the cpu was doing while it was waiting for the bit to be clear, this made me wonder if interrupts would be more efficient. I picked T0 because its output pin was one of the only open pwm pins for my project.
f I comment out the Serial.Begin(115200) and all the Serial.print lines it stops working
Post the non-working code.
uint8_t channel;
int adcValue[2];
These may not work properly in an interrupt routine, because they are not declared volatile.
I agree with DrDiettrich: it is much easier to use analogRead to read the pot and the LDR (with a capacitor to filter the ripple) and analogWrite to light the LED. Five or so lines of code total.
As for "overhead" are you concerned about a few extra microseconds/loop?
I don't see anything obviously wrong and it is certainly not obvious what the failure might have to do with serial.print().
On the other hand, Timer0 is normally in use by the Arduino for other purposes, and interfering with that may cause problems.
As already pointed out, writing low level code is difficult and the result is hard to debug. Not only does every bit have to be set correctly, it is easy to forget setting or clearing other bits that are required for proper function. You need to read the processor data sheet with a magnifying glass, usually several times, to avoid those sorts of mistakes.
The canned analogWrite and analogRead spare you this effort, but do cost a few microseconds extra.
Not sure what you're trying to do here.
You talk about getting the voltage on the LDR divider the same as on the pot.
Remember that you're using PWM. LED fully on, fully off.
Only your brain thinks it's dimming.
You're relying on the LDR being slow?
Leo..
The question isn't whether or not the setup with the LDR works. I got that to work it just stops working when I remove Serial.begin and Serial.print from the sketch.