He estado tratando de hacer un programa que lea continuamente valores analógicos de 3 pines diferentes y luego haga una señal PWM correspondiente a cada uno de esos 3 pines. Básicamente, 3 canales PWM de salida con diferentes ciclos de trabajo correspondientes a 3 valores analógicos diferentes. El problema es que todos los canales PWM comparten el ciclo de trabajo de lo que noté, pero si ignoro el ADC y simplemente configuro el ciclo de trabajo en el código, funcionan bien. Aquí está el código:
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
void selectADCchannel(uint8_t channel);
void initPWM();
void setupADC();
int main(void){
sei();
initPWM();
//start with 0'th channel; no channel selected needed
setupADC();
while(1){
}
}
ISR(ADC_vect){
//get current channel
uint8_t currentChannel = ADMUX & 0x0F;
//set output compare registers for current channel
switch(currentChannel){
case 0x00: OCR0A = ADCH;
break;
case 0x01: OCR0B = ADCH;
break;
case 0x02: OCR2B = ADCH;
break;
}
//loop through channels from 0 to 2
if(currentChannel == 2)
selectADCchannel(0x00);
else
selectADCchannel(currentChannel+1);
//restart conversion
ADCSRA |= 1<<ADSC;
}
void selectADCchannel(uint8_t channel){
//0xE0 is 11100000
//0x1F is 00011111
ADMUX = (ADMUX & 0xE0) | (channel & 0x1F);
}
void setupADC(){
//enable prescaler (128 for 16MHz => 125kHz)
//would probably work with 250kHZ for 8 bits
//set ADPS bits in ADCSRA to 111
ADCSRA |= 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;
//enable result shift to ADCH to only read ADCH (8 bits)
ADMUX |= 1<<ADLAR;
//enable interrupt
ADCSRA |= 1<<ADIE;
//set voltage reference
//reference is AVcc
ADMUX |= 1<<REFS0;
//turn on ADC
ADCSRA |= 1<<ADEN;
//start conversion
ADCSRA |= 1<<ADSC;
}
void initPWM(){
//TIMER0 (8 bit timer)
//set pins 5D(OC0B) and 6D(OC0A) as output
DDRD |= 1<<DDD5 | 1<<DDD6;
//set fast-pwm mode
TCCR0A |= 1<<WGM00;
//set non-inverting mode for both pins
TCCR0A |= 1<<COM0A1 | 1<<COM0B1;
//set prescaler to 256
TCCR0B |= 1<<CS02;
//TIMER2 (8 bit timer)
//set pins 3D(OC2B) as output
DDRD |= 1<<DDD3;
//set fast-pwm mode
TCCR2A |= 1<<WGM20;
//set non-inverting mode for both pins
TCCR2A |= 1<<COM2B1;
//set prescaler to 256
TCCR2B |= 1<<CS22 | 1<<CS21;
}
Entonces, qué debe hacer el programa, después de la inicialización, lea el valor de uno de los pines ADC y luego configure el registro de comparación PWM del pin correspondiente al valor ADCH. Gracias.