Por supuesto, puede reemplazar cualquier tipo de bucle y demoras con los temporizadores de hardware. Esto casi siempre resultará en una operación más eficiente y predecible. No ha especificado el número de canales PWM que desea utilizar, ni los ciclos de frecuencia / servicio que desea para ninguno de ellos. Para PWM de "bit banging", está limitado al número 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 CPU en uso. Cuanto más rápido está el reloj, más cosas puede 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 8MHz, reducida a 1MHz internamente. Arduino utiliza típicamente un cristal externo de 16MHz. ¡Este detalle es importante!
Cada temporizador tendrá varios registros de "comparación de coincidencia" para su uso en las solicitudes de servicio de interrupción generadas. Básicamente, el temporizador contará hasta que alcance el valor en un registro de comparación de coincidencias, luego podría desencadenar un ISR, restablecer el conteo, etc. Desde la parte superior de mi cabeza, hay muchas formas de crear múltiples PWM usando un solo temporizador:
PWM múltiples de la misma frecuencia y ciclo de trabajo
Este caso es bastante trivial, pero con un solo temporizador, puede establecer cualquier número de pines de salida en "Comparar partido A" (que también restablece el conteo), y borrar estos pines en "Comparar partido B". El valor para "B" sería algo desde 1 hasta el valor de "A", dependiendo del ciclo de trabajo deseado.
PWM múltiples de la misma frecuencia con diferentes ciclos de trabajo
Esto es un poco más complicado, pero definitivamente es factible. Al igual que en el primer caso, usaremos "A" para configurar todos los pines de PWM y restablecer el conteo. El ISR "B" es un poco más complejo, pero aquí está lo esencial:
- cree una matriz global de valores de tiempo, que representa el "tiempo de inactividad" de cada pin PWM.
- Establezca el registro de comparación de coincidencia B en el más pequeño de estos "tiempos de inactividad"
- En el ISR "B", verifique si el valor del registro es igual al "tiempo de apagado" de cada línea PWM en la matriz de tiempo (siempre debería ser igual a uno de ellos cuando active el ISR) y luego apagar ese pin (s).
- Recorra la matriz de tiempo para el siguiente tiempo de apagado, y configure el registro "B" en ese valor, que se utilizará para activar el próximo ISR.
Este proceso le dará la cantidad de pines PWM que desee con diferentes ciclos de trabajo (variables) (veces) pero todos deben tener la misma frecuencia.
PWM múltiples 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 dispara el temporizador ISR. Cada vez que este ISR se activa, ha transcurrido una cantidad exacta y conocida de tiempo, por lo que es libre de 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, mientras que 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 debería parecer familiar: es esencialmente lo que estaba haciendo su código en el bucle del programa principal, simplemente ha trasladado esta funcionalidad a los temporizadores de hardware y ha generado ISR sin el duros retrasos, liberando su bucle principal y CPU para hacer cosas más importantes que mirar a los "NOP" de ASM durante miles de ciclos de reloj.
Notas adicionales
No he usado ningún código aquí, pero puedo agregar algunos si eres más específico con tus requisitos, o dar una pista sobre lo que ya sabes cómo hacer.
También, asumo 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 número entero de 32 bits para un valor constante de 5 es tonto ... use uint8_t para cualquier cosa menos de 256.
Si está realmente preocupado por el poder y el tamaño del código, elimine las cosas de Arduino y las capas innecesarias de abstracción.