Matriz de LED controlada por PWM sobre un registro de desplazamiento

2

Estoy intentando conducir 8 LED conectados a un registro de desplazamiento 74HC595 con PWM. Quiero poder configurar cada LED a un brillo diferente. La señal PWM está conectada al pin Enable Output del registro de desplazamiento (es de baja actividad, por lo que la señal PWM debe invertirse). Seleccionando cada LED (solo un LED a la vez) y configurando la frecuencia PWM, pensé que se habría realizado. Así que actualmente tengo el siguiente enfoque:

  1. establecer la frecuencia PWM
  2. "active" el LED deseado escribiendo el valor correspondiente al registro de desplazamiento (por ejemplo, el primer LED sería 0b00000001
  3. escriba el valor del registro de desplazamiento para cambiar las salidas del registro estableciendo la entrada Latch en 1 y vuelva a borrarlo a 0
  4. comience de nuevo con la nueva frecuencia PWM y el próximo LED

Esto da como resultado el siguiente fallo: Cuando configuro el primer LED en brillo total y el siguiente LED en sin brillo (apagado), observo que durante un breve tiempo el brillo completo del primer LED aparece en el próximo LED . Este comportamiento le da al segundo LED un poco de brillo, lo cual es malo porque no quiero brillo (apáguelo). Sé que podría saltar sobre el LED para dejarlo apagado, pero me gustaría controlar solo el brillo de los LED al configurar la frecuencia PWM. También tengo este efecto al configurar, por ejemplo, el primer LED para brillo total y el siguiente LED para brillo medio. Siempre hay un brillo del LED anterior en el siguiente LED por un corto tiempo.

Creo que es porque no puedo controlar la salida de PWM, ya que puedo controlar la salida del registro de desplazamiento mediante su cierre. La frecuencia PWM se aplica tan pronto como la establezco en mi código. Esto provoca un breve parpadeo con el brillo del LED anterior. También intenté cambiar el orden de los pasos en mi enfoque.

¿Tienes alguna idea de cómo resolver este problema?

Algunas líneas de mi código real (si el pseudo código no es suficiente):

OCR0A = 0; // set PWM to full brightness
SPDR = 0b00000001; // select first LED
while(!(SPSR & (1<<SPIF))); // write to shift register
PORTB = 0; // latch outputs
PORTB = 1;
_delay_ms(1);

OCR0A = 255; // set PWM to no brightness (off)
SPDR = 0b00000010; // select second LED
while(!(SPSR & (1<<SPIF)));
PORTB = 0;
PORTB = 1;
_delay_ms(1);

Mi hardware de destino es un ATmega168 sincronizado a 20 MHz. Estoy usando avr-gcc .

    
pregunta arminb

3 respuestas

3

Creo que necesitas desactivar PWM mientras cambias el contenido del 595.

OCR0A = 255; // set PWM to no brightness (off)
_delay_a_little_more;
SPDR = 0b00000001; // select first LED
while(!(SPSR & (1<<SPIF))); // write to shift register
PORTB = 0; // latch outputs
PORTB = 1;
OCR0A = 0; // set PWM to full brightness
_delay_ms(1);

OCR0A = 255; // set PWM to no brightness (off)
_delay_a_little_more;
SPDR = 0b00000010; // select second LED
while(!(SPSR & (1<<SPIF)));
PORTB = 0;
PORTB = 1;
OCR0A = 255; // set PWM to no brightness (off)
_delay_ms(1);

En una nota al margen: hay una forma más eficiente de hacer lo que quiere (es decir, controlar el brillo de varios LED con 595 y el pin EN). Se llama modulación de código binario. enlace

    
respondido por el BarsMonster
2

Esto es un poco viejo y probablemente ya lo hayas descubierto, pero si lo comprendo correctamente, intentabas usar PWM en el pin output_enable para controlar la salida de cada registro de forma independiente, lo que simplemente no puede funcionar, porque ese pin afecta a todas las salidas.

El registro de desplazamiento no "recuerda" el ciclo PWM que estaba activo cuando ingresó un bit (el valor en cada canal siempre está "activado" o desactivado), y no almacena ninguna información analógica.

Para obtener PWM independiente, debe controlar los ciclos de trabajo en el software, alternando cada registro a través de un patrón de bits que coincida con el PWM (o BCM) que desea, mientras deja la salida habilitada. Hay algunas bibliotecas que hacen la mayor parte del trabajo por usted (por ejemplo, ShiftPWM).

Básicamente, si quisieras que el primer LED tuviera un ciclo de trabajo del 25%, el segundo que tuviera el 50% y el tercero que tuviera el 100%, harías que pasaran por algo como esto:

B00000111

B00000100

B00000110

B00000100

Aún puede conectar output_enable a un pin PWM para afectar a todos los LED, pero luego tendrá que tener cuidado de hacer que la actualización del software sea un múltiplo de la frecuencia PWM del hardware, o puede obtener resultados extraños.

    
respondido por el Mark Roberts
0

He tenido la necesidad exacta en un proyecto, así que escribí una biblioteca que hace que los pines de registro de desplazamiento sean compatibles con PWM. En pocas palabras, lo que se hace es configurar una interrupción del temporizador que a su vez actualiza los pines de salida del registro de desplazamiento en una frecuencia PWM seleccionada. Puede encontrar una descripción detallada aquí: ShiftRegister PWM Library (74HC595)

La biblioteca funciona bien con el ATmega328 pero también puede ser portada a otros microcontroladores. Utiliza el temporizador 1.

    
respondido por el Timo Denk

Lea otras preguntas en las etiquetas