Servomotor de control con microcontrolador ATmega328p

Durante un tiempo, he estado trabajando con Arduino, pero hace aproximadamente un mes, cambié a usar únicamente el microcontrolador ATmega328-PU. Yo uso el IDE de Atmel Studio. Hasta ahora, he hecho parpadear con éxito un LED, he usado programas que involucran botones/interruptores y he usado la función Fast PWM para atenuar un LED. Actualmente, estoy intentando conducir un servomotor usando Fast PWM, pero he tenido poco éxito. No he encontrado ningún código fuente que funcione para las necesidades específicas de mi microcontrolador, y realmente no tengo la capacidad de cambiar todos los parámetros, ya que todavía estoy aprendiendo.

El siguiente es el código que he desarrollado. No funciona, pero esperaba que alguien pudiera arreglarlo. El servo se mueve en una dirección, pero no se detiene y simplemente termina moliendo el engranaje del eje del motor, lo que indica que esto podría ser un problema con la longitud de onda. Una pregunta adicional: ¿existe una ecuación para convertir grados a longitud de onda PWM? ¡Gracias!

Especificaciones del microcontrolador:

  • Modelo - ATmega328-PU
  • cristal de 16.000.000 hz
  • 28 pines
  • Usando un temporizador de 8 bits

servo:

  • Servomodelo: Torre Pro SG90
  • Servofrecuencia 50 hz (¿esto es estándar?)

Código:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{

    DDRD |= (1 << DDD6);
    // PD6 is now an output - corresponds to OCR0A

    TCCR0A |= (1 << COM0A1);
    // set non-inverting mode

    TCCR0A |= (1 << WGM01) | (1 << WGM00);
    // set fast PWM Mode

    ICR1 = 39999;

    OCR0A = ICR1 - 2000;
    // gives servo motor position

    TCCR0B |= (1 << CS01);
    // set prescaler to 8 and starts PWM


    while(1)
    {
    }
}
Formalmente, debe leer la hoja de datos. De manera más práctica, escriba un boceto de Arduino que ordene la posición deseada, y luego lea e imprima los valores de registro de hardware que ha estado tratando de establecer. Luego puede usarlos en su propio programa AVR C como lo intentó.
@ChrisStratton ¡Gracias! Revisé la hoja de datos del servomotor, pero desafortunadamente, parecía más un anuncio y contenía muy pocos datos útiles para los usuarios que no son de Arduino.
Me refiero a la hoja de datos de ATmega. Es cierto que es complicado, pero la información está ahí. Ver lo que los bocetos de Arduiono realmente están haciendo con los registros y luego buscarlos en la hoja de datos puede ser más informativo que abordarlo en frío. También ha habido una serie de reseñas en ese sentido en línea que puede encontrar fácilmente.

Respuestas (1)

Hay varios problemas con su código: -

  1. En el modo de no inversión, el pulso PWM comienza con un conteo de 0 y termina con la coincidencia de comparación, por lo que debe cargar el ancho de pulso directamente en el registro de comparación (no restarlo del período).

  2. ICR1 es parte del Timer1 de 16 bits, no del Timer0 de 8 bits.

  3. Un temporizador de 8 bits no aceptará valores de 16 bits.

Para producir PWM de 16 bits, debe usar Timer1, luego los números 2000 (para un ancho de pulso de 1 ms) y 3999 (para un período de 20 ms) funcionarán correctamente. Así que cambie todas las referencias de Timer0 a sus equivalentes de Timer1, es decir. TCCR0A -> TCCR1A, COM0A1 -> COM1A1, etc. y configure PB1 para generar el pulso del servo.