¿Un temporizador PWM a dos salidas?

2

primera publicación aquí, lo siento por cualquier mal estilo.

Estoy trabajando en un proyecto grupal y uso un Atmega328, sin entrar en detalles, necesito manejar dos ventiladores, dos servos y una función basada en CTC de 3 temporizadores. A mi pregunta entonces; hay registros OCRx A y B que estoy usando para conducir los ventiladores a velocidades variables, y usando un método similar para los servos. Al configurar una secuencia de comandos PWM muy básica, he notado que ambos registros manejarán un ventilador, sin embargo, cuando intento usar cualquiera de los registros de forma independiente (ventilador 1 encendido, 2 apagado, luego cambio), OCRxB no producirá una salida.

Aquí hay un recorte de mi código de configuración:

void setup_timers () {
// Set Timer0 to Fast PWM mode
TCCR0A |= (1 << WGM01) | (1 << WGM00);

// Set Timer0 to clear OCR0 A/B on match
TCCR0A |= (1 << COM0A1) | (1 << COM0A0) | (1 << COM0B1) | (1 << COM0B0);
TCCR0B |= (1 << CS01);
TCNT0 = 0;

// Set OCR0 A/B
DDRD = 0xFF;}

Ahora, idealmente, esto configurará ambos registros en el temporizador 0 para las salidas. Estoy enviando esta señal a un transistor, que luego alimenta a los ventiladores según lo determinado en el siguiente bit:

int main () {
setup_timers();

while (1) {

    /* Timer 0; OCR0A (i = 0, L), OCR0B (i = 1, R), i = 2 denotes both fans */

    for (uint8_t i = 0; i <= 3; i++) {
        // Cycle Fans Left/Right/Both

        for (uint8_t j = 1; j <= 4; j++) {
            // Cycle Speed 

            if (i == 2) {
                // Check motor; run timer 0 A/B as required
                OCR0A = 0xFF * j / 4;
                OCR0B = 0xFF * j / 4;
                _delay_ms(2000);
            }
            else if (i == 1) {
                OCR0A = 0xFF * j / 4;
                OCR0B = 0;
                _delay_ms(2000);
            }
            else if (i == 0) {
                OCR0A = 0;
                OCR0B = 0xFF * j / 4;
                _delay_ms(2000);
            }
        }
    }
}
return 1; }

Ahora sé que esto podría hacerse mejor, este segmento tiene un montón de otras pruebas recortadas. El problema principal aquí es que el Fan 1 se ejecutará (dirigido por OCR0A), pero el Fan 2 se ignora por completo. He leído la hoja de datos varias veces, pero no estaba claro si esto es realmente posible, dijo algo acerca de que OCRxB no se almacenó, y he visto otras publicaciones preguntando después de eso. Por lo que entiendo, son registros independientes, pero ¿es posible que se retenga OCRxA, pero después de escribir OCRxB es imposible de ejecutar?

O tal vez estoy completamente equivocado, ciertamente no sería la primera vez.

    
pregunta Oman

1 respuesta

1

Parece que hubo algún problema con los valores predeterminados, al configurar COM1A0 y COM1B0, el temporizador 1 se puede configurar para proporcionar señales independientes. Este es el código de configuración que funciona:

void setup_timers () {

TCCR1A |= (1 << WGM11) | (1 << WGM10);
TCCR1A |= (1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0);
TCCR1B |= (1 << CS11);
TCNT1 = 0;

DDRB = 0xFF;}

Todavía tengo problemas para controlar correctamente los motores, pero los servos funcionan bien, y se puede hacer.

Nota: el temporizador 1 en realidad tiene dos salidas separadas, pero el temporizador 0/2 no. Para obtener salidas duales, debe alternar los registros WGMx2 y COMxB 0/1. Cuando se configura WGMx2, OCRxA no emitirá correctamente, pero OCRxB lo hará, con algunos problemas. Cuando WGMx2 no está configurado, deshabilita OCRxB, y OCRxA funcionará normalmente, para obtener salidas independientes, deberá tener esto en cuenta.

    
respondido por el Oman

Lea otras preguntas en las etiquetas