1 votos

Sustituir el bucle por los temporizadores en este código ATtiny

¿Cómo puedo reescribir lo siguiente para utilizar temporizadores? Tenga en cuenta que este es un ATtiny que sólo tiene Timer0 y Timer1

Esencialmente estoy tratando de software PWM en muchos pines de salida, más que los pines PWM incorporados. El código de abajo está ligeramente simplificado, pero el código real utiliza la manipulación directa del puerto y no hace casi nada más, por lo que el resultado debería ser casi tan bueno como el PWM incorporado.

La aplicación prevista está pensada para funcionar con una batería pequeña, por lo que el ahorro de energía es un objetivo importante del diseño. Además, dado que se trata de un ATtiny, cada byte de espacio de programa es importante.

O bien, convénzame de que no vale la pena intentar utilizar temporizadores en este caso.

void loop() {
  static int8_t procession = 0;
  static uint32_t lastTime = millis();
  static int8_t pos = 0;

  if (lastTime > millis() + 200) {
    lastTime = millis();
    if (++procession == 9) {
      procession = 0;
    }
  }

  const uint32_t ON_CYCLE = 5;
  const uint32_t OFF_CYCLE = 5;

  digitalWrite(procession, HIGH);

  delayMicroseconds(ON_CYCLE);

  if (OFF_CYCLE > 0) {
    digitalWrite(procession, LOW);
    delayMicroseconds(OFF_CYCLE);
  }
}

1voto

azhar Puntos 21

Por supuesto, puedes reemplazar cualquier tipo de bucle y retraso con los temporizadores de hardware. Esto casi siempre resultará en una operación más eficiente y predecible. No has especificado el número de canales PWM que quieres usar, o la frecuencia / ciclos de trabajo que quieres para cualquiera de ellos. Para el PWM de "golpeo de bits", estás limitado al número de líneas de E/S disponibles (aunque, siempre podrías añadir registros de desplazamiento externos para aumentar en gran medida este límite).

También está limitada la frecuencia de la CPU en uso. Cuanto más rápido sea el reloj, más cosas podrás hacer en la misma cantidad de tiempo. Esto será más importante a medida que añadas canales PWM. La velocidad de reloj por defecto del AVR es de 8MHz, escalada a 1MHz internamente. Arduino suele utilizar un cristal externo de 16MHz. ¡Este detalle es importante!

Cada temporizador tendrá varios registros de "coincidencia de comparación" para utilizarlos en las solicitudes de servicio de interrupción generadas. Básicamente, el temporizador contará hasta que alcance el valor de un registro de comparación, y entonces podría activar una ISR, reiniciar la cuenta, etc. En mi cabeza, hay numerosas maneras de crear múltiples PWMs usando un solo temporizador:

Múltiples PWM de la misma frecuencia y ciclo de trabajo

Este caso es bastante trivial, pero usando un solo temporizador, puedes establecer cualquier número de pines de salida en la "Comparación A" (que también reinicia la cuenta), y borrar estos pines en la "Comparación B". El valor de "B" sería algo entre 1 y el valor de "A", dependiendo de tu ciclo de trabajo deseado.

Múltiples PWM de la misma frecuencia con diferentes ciclos de trabajo

Esto es un poco más complicado, pero definitivamente se puede hacer. Al igual que en el primer caso, usaremos "A" para activar todos los pines PWM y reiniciar la cuenta. El ISR "B" es un poco más complejo, pero esto es lo esencial:

  1. crear una matriz global de valores de tiempo, representando el "tiempo de apagado" de cada pin PWM.
  2. Ajuste el registro de comparación B al menor de estos "tiempos muertos"
  3. En el ISR "B", comprueba si el valor del registro es igual al "tiempo de apagado" de cada línea PWM en la matriz de tiempo (siempre debe ser igual a uno de ellos cuando se dispara el ISR) entonces apaga ese pin(s).
  4. Recorre la matriz de tiempo para el próximo tiempo de desactivación, y establece el registro "B" a ese valor, que se utilizará para desencadenar el siguiente ISR.

Este proceso te proporcionará tantos pines PWM como quieras con diferentes ciclos de trabajo (tiempos de encendido), pero todos deben tener la misma frecuencia.

Múltiples PWMs con diferentes frecuencias y diferentes ciclos de trabajo

Este último caso que presentaré se basa en las ideas de los anteriores, pero añadirá una variable de conteo que se incrementa cuando el ISR del temporizador se dispara. Cada vez que este ISR se dispara, ha pasado una cantidad de tiempo exacta y conocida, por lo que puedes utilizar las variables de conteo para decidir cuándo se produce un evento. Por ejemplo, puedes usar una variable para contar hasta 100 antes de activar un pin, y luego contar hasta 100 antes de desactivarlo, mientras otra variable cuenta hasta 200 para hacer las mismas cosas. Eso es 2 variables para 2 canales PWM independientes.

Por supuesto, este método es el más desordenado en términos de código, pero debe parecer familiar - es esencialmente lo que su código estaba haciendo en el bucle del programa principal, sólo ha movido esta funcionalidad a los temporizadores de hardware y generó ISRs sin los retrasos duros, liberando su bucle principal y la CPU para hacer cosas más importantes que mirar ASM "NOP" durante miles de ciclos de reloj.

Notas adicionales

No he utilizado ningún código aquí, pero puedo añadir algo si eres más específico con tus requisitos, o dar una pista de lo que ya sabes hacer.

Además, supongo que estás usando un AVR de 8 bits. Si es así, te recomiendo que prestes atención a los tipos de variables que necesitas. Usar un entero de 32 bits para un valor constante de 5 es una tontería... usa uint8_t para cualquier cosa inferior a 256.

Si realmente te preocupa la potencia y el tamaño del código, deja las cosas de Arduino y las capas de abstracción innecesarias.

0voto

Jeremy Puntos 424

¿Cómo puedo reescribir lo siguiente para utilizar temporizadores?

Escribí esto hace un tiempo para manejar servos pero el concepto básico es el mismo: producir ciclos de trabajo independientemente variables en cualquier número de pines.

https://dannyelectronics.wordpress.com/2017/02/18/driving-multiple-servos-off-a-pic-timer2-ranged-extended/

tiene enlaces a otros enfoques que utilizan diferentes periféricos en PICs y AVRs - pero el concepto básico es el mismo.

puedes ajustar los parámetros para adaptarlos a tus necesidades.

el código se ejecuta en su totalidad en el isr para que su bucle principal pueda hacer lo que sea necesario, como alterar los ciclos de trabajo....

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X