¿Cómo puedo reescribir lo siguiente para usar temporizadores? Tenga en cuenta que este es un ATtiny que solo tiene Timer0 y Timer1
Esencialmente, estoy tratando de programar PWM en muchos pines de salida, más que en los pines PWM incorporados. El siguiente código está ligeramente simplificado, pero el código real utiliza la manipulación directa de puertos y no hace casi nada más, por lo que el resultado debería ser casi tan bueno como el PWM integrado.
La aplicación prevista está diseñada para funcionar con una batería pequeña, por lo que el ahorro de energía es un objetivo de diseño importante. Además, dado que se trata de ATtiny, cada byte del espacio del programa es importante.
O, convénceme de que no vale la pena intentar usar 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);
}
}
Por supuesto, puede 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 ha especificado la cantidad de canales PWM que desea usar, o la frecuencia/ciclos de trabajo que desea para ninguno de ellos. Para PWM "bit-banging", está limitado a la cantidad de líneas de E/S disponibles (aunque, siempre puede agregar registros de desplazamiento externos para aumentar considerablemente este límite).
También está limitado en la frecuencia de uso de la CPU. Cuanto más rápido corre el reloj, más cosas puedes hacer en la misma cantidad de tiempo. Esto será más importante a medida que agregue canales PWM. La velocidad de reloj AVR predeterminada es de 8 MHz, reducida a 1 MHz internamente. Arduino normalmente usa un cristal externo de 16 MHz. ¡Este detalle es importante!
Cada temporizador tendrá varios registros de "coincidencia de comparación" para usar en las solicitudes de servicio de interrupción generadas. Básicamente, el temporizador contará hasta que alcance el valor en un registro de coincidencia de comparación, luego podría activar un ISR, restablecer el conteo, etc. En mi opinión, existen numerosas formas de crear múltiples PWM con un solo temporizador:
Múltiples PWM de la misma frecuencia y ciclo de trabajo
Este caso es bastante trivial, pero con un solo temporizador, puede configurar cualquier número de pines de salida en "Comparar coincidencia A" (que también restablece el conteo) y borrar estos pines en "Comparar coincidencia B". El valor de "B" sería algo entre 1 y el valor de "A", según el 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 factible. Similar al primer caso, usaremos "A" para configurar todos los pines PWM y restablecer el conteo. El ISR "B" es un poco más complejo, pero aquí está la esencia:
Este proceso le dará tantos pines PWM como desee con diferentes ciclos de trabajo (variables) (tiempos) pero todos deben tener la misma frecuencia.
Múltiples PWM con diferentes frecuencias y diferentes ciclos de trabajo
Este último caso que presentaré se basa en las ideas de los anteriores, pero agregará una variable de conteo que se incrementa cuando se activa el temporizador ISR. Cada vez que se activa este ISR, ha pasado una cantidad de tiempo exacta y conocida, por lo que puede usar variables de contador para decidir cuándo ocurre un evento. Por ejemplo, podría usar una variable para contar hasta 100 antes de establecer un pin, luego contar hasta 100 antes de borrarlo, todo mientras otra variable cuenta hasta 200 para hacer lo mismo. Son 2 variables para 2 canales PWM independientes.
Por supuesto, este método es el más complicado en términos de código, pero debería parecer familiar: es esencialmente lo que su código estaba haciendo en el bucle del programa principal, simplemente movió esta funcionalidad a los temporizadores de hardware y generó ISR sin los retrasos. liberando su bucle principal y CPU para hacer cosas más importantes que mirar los "NOP" de ASM durante miles de ciclos de reloj.
Notas adicionales
No he usado ningún código aquí, pero puedo agregar algo si es más específico con sus requisitos, o dar una pista sobre lo que ya sabe hacer.
Además, supongo que estás usando un AVR de 8 bits aquí. Si es así, le recomiendo que preste atención a los tipos de variables requeridos. Usar un entero de 32 bits para un valor constante de 5 es una tontería... use uint8_t para cualquier valor menor a 256.
Si está realmente preocupado por la potencia y el tamaño del código, deje las cosas de Arduino y las capas innecesarias de abstracción.
¿Cómo puedo reescribir lo siguiente para usar temporizadores?
Escribí esto hace un tiempo para controlar los servos, pero el concepto básico es el mismo: producir ciclos de trabajo variables de forma independiente en cualquier cantidad de pines.
tiene enlaces a otros enfoques que usan diferentes periféricos en PIC y AVR, pero el concepto básico es el mismo.
puede modificar los parámetros para adaptarlos a sus necesidades.
el código se ejecuta en su totalidad en el isr, por lo que su ciclo principal puede hacer lo que sea necesario, como alterar los ciclos de trabajo...
tom carpintero
broma
jimmyb
Dmitri Grigoriev
J Halcres
Transistor