¿Cambiar la frecuencia PWM? [cerrado]

0

En este momento estoy tratando de generar una señal PWM usando timer1, pero es un error lamentable.

Estoy usando esta biblioteca disponible desde arduino para conectar el timer1.

enlace

El código que estoy ejecutando es este

#include "test.h"

volatile int step_count = 1;

test::test()
{
  pinMode(10,OUTPUT);
  Timer1.initialize(20);
  Timer1.attachInterrupt(callback);
}


static void test::callback()
{

}


void test::test_pwm()
{

  Serial.print("period: ");
  Serial.println(period_used);
  Serial.print('\n');
  Serial.print("value: ");
  Serial.print(value);
  Serial.print('\n');

  Timer1.pwm(10, (50.0 / 100) * 1023);

}

El constructor inicializa el temporizador.

void TimerOne::initialize(long microseconds)
{
  TCCR1A = 0;                 // clear control register A 
  TCCR1B = _BV(WGM13);        // set mode 8: phase and frequency correct pwm, stop the timer
  setPeriod(microseconds);
}

SetPeriod() debe ser uno que determine la frecuencia de la PWM

void TimerOne::setPeriod(long microseconds)     // AR modified for atomic access
{

  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum

  oldSREG = SREG;               
  cli();                            // Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;

  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                          // reset clock select register, and starts the clock
}

No veo nada malo en la forma en que se implementó, pero estoy bastante seguro de que algo debe estar mal aquí, pero no puedo averiguar dónde está el error.

Y la función pwm está codificada aquí:

void TimerOne::pwm(char pin, int duty, long microseconds)  // expects duty cycle to be 10 bit (1024)
{
  if(microseconds > 0) setPeriod(microseconds);
  if(pin == 1 || pin == 9) {
    DDRB |= _BV(PORTB1);                                   // sets data direction register for pwm output pin
    TCCR1A |= _BV(COM1A1);                                 // activates the output pin
  }
  else if(pin == 2 || pin == 10) {
    DDRB |= _BV(PORTB2);
    TCCR1A |= _BV(COM1B1);
  }
  setPwmDuty(pin, duty);
  resume();         // Lex - make sure the clock is running.  We don't want to restart the count, in case we are starting the second WGM
                    // and the first one is in the middle of a cycle
}

el problema aquí es que no puedo crear una señal PWM que no tenga una frecuencia mayor o menor a 490 hz. Si intenta cambiar el valor, se inicializa el ciclo de trabajo, en lugar de la frecuencia ... ¿Qué podría estar mal aquí?

Molesto por la biblioteca, comencé a configurar las cosas manualmente

Aquí está el código. Debería crear una interrupción cada 1 hz, en la que se alterna el estado del pin. La frecuencia del cambio de pin se produce a 490 hz.

#include "test.h"

test::test()
{
  pinMode(10,OUTPUT);
  //Timer1 setup1 Interrup at 1hz
  cli(); // Stop interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  OCR1A = 15624; // Compare register value = cpu_fre/(interrupt_freq*prescaler)-1 (must be <65536)
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS12) | (1 << CS10); 
  TIMSK1 |= (1 << OCIE1A);

  sei(); //allow interrupts
}

ISR(TIMER1_COMPA_vect)
{
 digitalWrite(10,!digitalRead(10));
}
    
pregunta Carlton Banks

3 respuestas

2

No configure el hardware en un constructor global. Tu constructor hará se llamará antes de main() , y main() llamará a init() para Inicializando la librería core de Arduino. Y init() reconfigurará Temporizador 1 para PWM a 490 Hz.

Es por eso que muchas bibliotecas de Arduino tienen clases que implementan un Método begin() : para retrasar la inicialización del hardware hasta después Se realizó init() .

    
respondido por el Edgar Bonet
1

Como se señaló en el comentario de Gerben, la selección de la fuente de reloj 7 a través de (1 << CS12)| (1 << CS11) | (1 << CS10) configura la fuente de reloj externa en el pin T1, el reloj en el flanco ascendente.

Consulte la Tabla 16-5, Descripción del bit de selección de reloj, en la hoja de especificaciones de ATmega328.

CS12 CS11 CS10 Description
 0    0    0   No clock source (Timer/Counter stopped).
 0    0    1   clkI/O/1 (No prescaling)
 0    1    0   clkI/O/8 (From prescaler)
 0    1    1   clkI/O/64 (From prescaler)
 1    0    0   clkI/O/256 (From prescaler)
 1    0    1   clkI/O/1024 (From prescaler)
 1    1    0   External clock source on T1 pin. Clock on falling edge.
 1    1    1   External clock source on T1 pin. Clock on rising edge.

En lugar de configurar todos los bits de CS12, CS11, CS10, tal vez debería configurar solo uno o dos, según el factor de preescala que desee.

    
respondido por el James Waldby - jwpat7
-1

Debería poder ajustar la frecuencia cambiando la frecuencia del temporizador para el pin que está usando. Por ejemplo, los pines 5 y 6 están controlados por el temporizador 0, que tiene una frecuencia de hasta 62500 Hz. Para cambiar el temporizador, necesita configurar TCCR0B:

Setting     Divisor     Frequency
0x01        1           62500
0x02        8           7812.5
0x03        64          976.5625   <--DEFAULT
0x04        256         244.140625
0x05        1024        61.03515625

TCCR0B = (TCCR0B & 0b11111000) | <setting>;

Puede cambiar los otros temporizadores de forma similar cambiando TCCR1B o TCCR2B, aunque tienen una frecuencia base diferente (31372.55 Hz).

Consulte el tutorial aquí (la fuente de la tabla anterior): enlace

Aquí hay un código de ejemplo que cambia la frecuencia: enlace

    
respondido por el Nathan

Lea otras preguntas en las etiquetas