Implementación de una luz de respiración LED utilizando el microcontrolador 51

Jun 11, 2026 Dejar un mensaje

[Introducción]


La tecnología de microcontroladores es una tecnología convencional indispensable en la automatización industrial moderna, la electrónica, la ingeniería eléctrica y el Internet de las cosas (IoT). A medida que nuestras vidas se vuelven cada vez más inteligentes, la tecnología de microcontroladores ha permeado prácticamente todos los aspectos de nuestra vida diaria, como en ollas arroceras inteligentes, parlantes inteligentes y más.


Con esto en mente, la serie de artículos "Reaprender el microcontrolador 51" tiene como objetivo ayudar a los principiantes a iniciarse en la tecnología de microcontroladores. Comenzaremos con la tarea más simple: -encender un solo LED- y gradualmente progresaremos hasta implementar módulos como controles de botones, la pantalla LCD1602, los sensores de temperatura DS18B20 y DS1302 y la comunicación entre dos microcontroladores. También cubriremos protocolos de comunicación de hardware como UART, I²C y SPI. Al combinar estos conceptos con técnicas de programación en C, usaremos proyectos de ingeniería del mundo real-para ilustrar enfoques de programación, lo que le permitirá aplicar de manera flexible estructuras y punteros de C para lograr una programación modular.


Ahora, volvamos al tema principal: usar un microcontrolador 51 para controlar un LED y crear un efecto de luz respiratoria.

 

[Cómo funcionan las luces respiratorias]


Primero echemos un vistazo a cómo funciona un efecto de luz respiratoria.
Una luz respiratoria se ilumina gradualmente y luego se atenúa gradualmente, repitiendo este ciclo de una manera que se asemeja a la respiración. Sin embargo, dado que los pines de un microcontrolador solo pueden generar un 1 (encendido) o un 0 (apagado), ¿cómo se puede lograr un efecto de transición gradual?
Esto se debe a la persistencia de la visión en nuestros ojos. Cuando miramos algo, la imagen formada por nuestros ojos persiste durante 0,04 segundos (esta cifra se encontró en línea).
Si calculamos en base a 0,04 segundos, eso equivale a 40 ms. Por lo tanto, cuando el LED está encendido y apagado durante 20 ms cada uno, al ojo humano le parece como si estuviera constantemente encendido.

图片

¿El efecto de que un LED parpadee durante 20 ms y se apague durante 20 ms es el mismo que si permanece encendido todo el tiempo?

 

Jaja, definitivamente es diferente. Cuando la luz se enciende y apaga alternativamente cada 20 milisegundos, el efecto que vemos es más tenue que cuando permanece encendida continuamente. Si asumimos que el brillo de una luz encendida continuamente es del 100%, entonces el brillo de una luz que alterna entre encendido y apagado cada 20 milisegundos es del 50%. En base a esto, podemos ajustar el brillo del LED.

图片

 

En este punto, podemos ajustar el brillo del LED (configurando la duración del nivel alto dentro del ciclo de 40 ms). Este es el principio detrás del conocido método-PWM (modulación de ancho de pulso) de control de brillo, y establecer la duración del nivel alto equivale a ajustar el ciclo de trabajo (es decir, la duración del nivel alto dividida por el ciclo total: 20/40=50%).


Aquí, el factor más importante es este ciclo de trabajo. Por ejemplo, si el período es de 20 ms, con el LED alternando entre 10 ms encendido y 10 ms apagado, el brillo percibido sigue siendo del 50 % (es decir, el ciclo de trabajo es 10/20=50%).

A continuación, veamos cómo se implementa esto en el programa.

 

[Implementación del programa]


Encendiendo un LED
Primero, comencemos encendiendo un LED y luego implementaremos gradualmente un efecto de luz de respiración. El hardware que usaremos es el siguiente:

Junta de Desarrollo Placa de desarrollo de formación de microcontroladores ZeroOne
Modelo de microcontrolador STC89C52
Interfaz LED Pasador P4^4
图片

 

En el esquema, podemos ver que el LED está conectado al pin P4^4 del microcontrolador. Cuando el microcontrolador genera un 1, el LED se enciende; cuando genera un 0, el LED se apaga. Por tanto, el programa para encender un LED es bastante sencillo, como se muestra a continuación:

info-299-230

 

 

El programa para encender un LED es bastante sencillo; Estoy seguro de que todos saben cómo hacerlo.
 

Ajuste del brillo del LED


A continuación, implementaremos una función que nos permite ajustar el brillo (es decir, ajustar el ciclo de trabajo), de la siguiente manera:

info-400-538


 

Defina una variable estática `duty_cycle` para almacenar el ciclo de trabajo. Cuando "flag" es 1, el ciclo de trabajo aumenta gradualmente a 255, luego establece "flag" en 0 y "duty_cycle" disminuye gradualmente de 255 a 0. Repita este ciclo.
Jaja, en este punto, podrías pensar que la luz de respiración ya está funcionando, pero no es así. Si no me cree, pruebe el código anterior.

Entonces, ¿dónde está exactamente el problema?


El problema radica en nuestra llamada directa a la función de configuración de brillo-`set_led_luminance()`. Esta función tarda 40 ms en completar un ciclo, lo que significa que el ciclo de trabajo no se puede cambiar durante esos 40 ms; de lo contrario, el ajuste de brillo no funcionará. Echemos otro vistazo a la función `breath_led`. Después de cada llamada a `set_led_luminance()` para establecer el ciclo de trabajo, cambia inmediatamente el valor de `duty_cycle` sin esperar 40 ms.


En este punto, necesitamos agregar un temporizador de software para actualizar el valor de `duty_cycle` después de que hayan transcurrido 40 ms. El programa modificado es el siguiente:

info-495-656

 

 

Nota: La duración del temporizador solo debe ser mayor que 40 ms (lo que significa que el valor de `s_breathCounter` debe ser mayor que 255), pero es mejor configurarlo en un múltiplo del ciclo. Por ejemplo, si nuestro ciclo es 255 (es decir, 256 valores de 0 a 255), podemos configurarlo al doble de ese valor: 256 * 2 - 1=511 (es decir, 512 valores de 0 a 511).
Y ahí lo tienes-¡nuestra luz de respiración está completa! ¿No es así de sencillo? (* ̄︶ ̄)

 

El siguiente paso es la sección de bonificación de hoy.

Aunque hemos logrado el efecto de luz respirable, el código no es lo suficientemente conciso ni elegante-usa un montón de declaraciones if y else. Veamos si podemos simplificarlo más.

Primero, simplifiquemos esta sección de la función set_led_luminance(), como se muestra en la siguiente figura.
 

图片

 

Antes de simplificar esto, veamos un consejo rápido sobre C: la operación AND bit a bit.

info-600-117

 

A partir de esto, sabemos que ya sea 1 o 0, realizar una operación AND bit a bit con 0 da como resultado 0.

Ya sea 1 o 0, realizar una operación AND bit a bit con 1 da como resultado el valor original.

Por conveniencia, utilizamos notación hexadecimal (con el prefijo "0x"); por ejemplo, 0xff corresponde a 255 en decimal. Por lo tanto,

 

Cuando a un número menor o igual a 0xff se le aplica un AND con 0xff, el resultado es el número mismo, como se muestra a continuación

info-534-63

 

 

¿Qué sucede si realiza una operación AND bit a bit entre un número mayor que 0xff y 0xff?

info-551-63

El resultado es el resto cuando este número se divide por (0xff + 1) (es decir, el resultado todavía está entre 0 y 0xff).
Con esta operación AND bit a bit, el código anterior se puede simplificar a

info-550-64

 

 

De esta forma, el valor de s_Counter siempre estará dentro del rango de 0x00 a 0xff.
De manera similar, el temporizador de software en la función Breath_led anterior también se puede simplificar de la siguiente manera:

info-389-353

En la línea 3, 0x1ff es 511 en decimal. La condición es verdadera cuando el valor de s_breathCounter es (0x1ff+1), o 512, porque 512 & 0x1ff=0. El signo de exclamación antes indica una operación NOT bit a bit (para ser precisos, la condición se cumple cuando el valor de `s_breathCounter` es un múltiplo de 512; esto elimina la necesidad de restablecer `s_breathCounter`. Espero que esta explicación sea claro-piénselo bien). Si se cumple la condición, el ciclo de trabajo comienza a aumentar o disminuir.


¿Pero el ciclo de trabajo no está en el rango de 0 a 255? ¿Por qué la línea 5 también se convierte en 0x1ff (511)? No te preocupes-mira la línea 8. Restamos 0xff nuevamente, por lo que el rango del ciclo de trabajo permanece entre 0 y 255.


Las líneas 7 a 10 significan: Cuando `duty_cycle > (0xff)`, es decir, 256–511, restar 0xff equivale a aumentar de 1 a 255, por lo que el brillo aumenta gradualmente.


Cuando el ciclo de trabajo<= 0xff, the duty_cycle increases from 0 to 255, while the set brightness is 255 - duty_cycle. This effectively decreases the brightness from 255 to 0, causing the light to gradually dim. This achieves the breathing light effect.


Jaja, ¿pensaste que nuestra simplificación había terminado?

 

No, no, no

En realidad, las líneas 7 a 10 podrían simplificarse aún más. Aquí es donde la función de valor absoluto resulta útil.

¿Qué? ¿Por qué utilizar la función de valor absoluto?

 

Mire la línea 10: 0xff - duty_cycle es equivalente a duty_cycle - 0xff y luego toma el valor absoluto. Bien, aquí está el código simplificado:

set_led_luminance(ABS(duty_cycle - (0xff)));

 

 

La función macro para tomar el valor absoluto es la siguiente

#definir ABS(N) ((N) < 0? -(N): (N))

 

Finalmente, he incluido el código simplificado completo a continuación.

 

info-562-684

¿Qué opinas? ¿No es sencillo? (* ̄︶ ̄)

Envíeconsulta

whatsapp

Teléfono de contacto

Correo electrónico

Consulta