Pregunta:
¿Cómo puedo usar PWM en modo de ahorro de energía (ATmega328)?
stefan
2017-11-24 20:56:52 UTC
view on stackexchange narkive permalink

No puedo usar PWM en el modo de ahorro de energía. La salida se comporta de forma errática. Esto debería ser posible, supongo. El siguiente es un ejemplo de trabajo mínimo:

  / * MWE: No se puede usar PWM en ningún modo de ahorro de energía. Un ejemplo de trabajo mínimo (MWE) que demuestra mi problema al usar PWM mientras se ahorra energía. Intención: Controlar que una carga esté encendida o apagada durante períodos de tiempo más largos (es decir, horas). El brillo de la carga lo establece PWM. Cableado: + 5V | + ------------------ + | + 5V --- | Vin | | | Arduino | C | Pro Mini 9 | ----- / \ / \ / ---- B | < PN2222 | compatible | 1k E | (ATmega328) | | GND --- | GND | | + + ------------------ + LED | - | > < 1k > | | Implementación GND: * Configure el perro guardián para causar una interrupción en intervalos regulares (en este MWE: 2s). Cuente los `ciclos` (MWE: 2 o 3) en cada interrupción del perro guardián. * Si `ciclos` es 0, alternar la salida, establecer un nuevo valor de` ciclos`. El programa real utiliza 7200 ciclos de 8 s durante 16 h antes del próximo cambio. * Vaya a SLEEP_MODE_PWR_DOWN. Esperado: la carga adjunta está encendida durante 4 segundos, atenuada a 32/256. Luego de 6 segundos. Luego repita. Observado: en la mayoría de los casos, no hay salida en el modo de suspensión, el LED solo parpadea antes de dormir. Pero a veces está encendido, así que
¡PWM parece ser posible mientras duerme! El programa real (del cual se deriva este MWE) usa brillo ajustable, se despierta de la suspensión por interrupciones externas, almacena brillo en EEPROM, ... * // * Al establecer lo siguiente en 0 se usa `digitalWrite` en lugar de` analogWrite` para Demuestre que la lógica de vigilancia y de interrupción realmente funcionan. * / # define USE_PWM 1 # incluye <avr / sleep.h> # incluye <avr / wdt.h> # define outputPin 9 // donde está conectada la carga PWM # define onCycles 2 // número de ciclos de vigilancia para permanecer en # define offCycles 3 / número de ciclos de vigilancia para permanecer fuera de brillo = 32; // Ciclo de trabajo de PWM en 1/256, si la carga está encendidaint toggle = 1; // estado actual de encendido / apagado de la carga PWM / * Número de ciclos de vigilancia hasta el próximo cambio. Esto se modificará en el controlador de interrupciones del perro guardián. * / volatile unsigned long wdt_cycles = onCycles; / * Se llama al manejador de interrupciones del perro guardián cuando el perro guardián expira, cuenta los ciclos restantes. No se desborda. * / ISR (WDT_vect) {if (wdt_cycles > 0) wdt_cycles -;} void setup (void) {/ * Configurar el perro guardián. Ver [1] p54, [2] * / cli (); // BEGIN inhabilita las interrupciones MCUSR & = ~ (1<<WDRF); // no se reinicia el sistema en el tiempo de espera de vigilancia WDTCSR | = 1<<WDCE | 1<<WDE; // permitir la configuración del perro guardián WDTCSR = 1<<WDIE // habilitar interrupciones | 1<<WDP2 | 1<<WDP1 | 1<<WDP0 // 2,0 segundos; wdt_reset (); // reiniciar el temporizador sei (); // FIN desactivar interrupciones / * Configurar pines de salida * / pinMode (outputPin, OUTPUT); # if USE_PWM analogWrite (outputPin, brillo); # else digitalWrite (outputPin, alternar? HIGH: LOW); # endif} bucle vacío (void) {if (wdt_cycles < 1) {toggle =! toggle; wdt_cycles = alternar? onCycles: offCycles; #if USE_PWM
analogWrite (outputPin, alternar? brillo: 0); # else digitalWrite (outputPin, alternar? HIGH: LOW); # endif} / * Heartbeat: Parpadeo corto del led incorporado. Esto verifica que realmente estamos durmiendo y despertando. * / digitalWrite (LED_BUILTIN, ALTO); retraso (50); digitalWrite (LED_BUILTIN, BAJO); / * Me dormí, ver [3]. Quiero `SLEEP_MODE_PWR_DOWN`, pero tampoco ninguno de los otros funciona. * / set_sleep_mode (// SLEEP_MODE_IDLE // SLEEP_MODE_ADC // SLEEP_MODE_PWR_SAVE // SLEEP_MODE_STANDBY SLEEP_MODE_PWR_DOWN); sleep_mode ();} / * Referencias [1] https://cdn.sparkfun.com/datasheets/Kits/doc8161.pdf [2] https://forum.arduino.cc/index.php?topic=63651.0 [3 ] https://playground.arduino.cc/Learning/ArduinoSleepCode * /  
Dos respuestas:
Gerben
2017-11-24 22:46:03 UTC
view on stackexchange narkive permalink

Los temporizadores están desactivados durante SLEEP_MODE_PWR_DOWN, por lo que PWM no funciona durante SLEEP_MODE_PWR_DOWN. En su lugar, podría usar SLEEP_MODE_IDLE , pero eso solo ahorra un poco de corriente.

Cuando ponga la MCU en suspensión, el LED mantendrá el estado en el que estaba durante PWM. Entonces, alrededor del 12.5% ​​si el tiempo que los leds estarán encendidos y las otras veces estarán apagados (durante esos períodos de 2 segundos de PWM).

Su segundo comentario explica por qué he visto luz encendida en modo de suspensión y también por qué es difícil de reproducir.
Edgar Bonet
2017-11-25 01:14:27 UTC
view on stackexchange narkive permalink

Solo como complemento a la respuesta de Gerben:

  1. Puede usar SLEEP_MODE_PWR_DOWN durante el período de inactividad, pero SLEEP_MODE_IDLE es la única forma para hacer PWM mientras duerme.
  2. Cuando esté en SLEEP_MODE_IDLE , puede usar la función power _ * _ disable () definida en <avr /power.h> para reducir aún más el consumo de energía.
Muy buena información: "SLEEP_MODE_IDLE es * la única forma * de hacer PWM mientras duerme". No pude encontrar esto en los documentos de ATmega. Estoy usando lo que sugieres, ¡gracias!


Esta pregunta y respuesta fue traducida automáticamente del idioma inglés.El contenido original está disponible en stackexchange, a quien agradecemos la licencia cc by-sa 3.0 bajo la que se distribuye.
Loading...