Pulse Width Modulation (PWM) is a technique to control the average voltage delivered to a load (like an LED) by rapidly switching power on and off. By varying the duty cycle (percentage of "on" time), you can smoothly adjust brightness. Here’s how to implement it on common platforms: ![how-to-make-control-the-light-intensity-of-a-led-using-pwm-1024x576](https://hackmd.io/_uploads/HyGGxugtle.png) **1. PWM Basics** Duty Cycle: Percentage of time the signal is "high" (e.g., 50% = half brightness). Frequency: How fast the signal switches (e.g., 500Hz–1kHz for LEDs). * Too low (<100Hz): Flickering visible. * Too high (>10kHz): LED driver limitations. **2. Hardware Setup** **Components Needed** * LED (+ current-limiting [resistor](https://www.onzuu.com/category/resistors), e.g., 220Ω for 3.3V/5V). * [Microcontroller](https://www.ampheo.com/c/microcontrollers) (e.g., [Arduino](https://www.ampheo.com/c/development-board-arduino), [Raspberry Pi](https://www.ampheo.com/c/raspberry-pi/raspberry-pi-boards), [STM32](https://www.ampheo.com/search/STM32)). **Wiring** ``` text Microcontroller GPIO → Resistor → LED → GND ``` (PWM-capable pin required—check your MCU’s datasheet.) **3. Software Implementation** **A. Arduino (C++)** ``` cpp const int LED_PIN = 9; // PWM-capable pin (~ symbol on Arduino) void setup() { pinMode(LED_PIN, OUTPUT); } void loop() { // Fade in/out for (int brightness = 0; brightness <= 255; brightness++) { analogWrite(LED_PIN, brightness); // 8-bit PWM (0–255) delay(10); } for (int brightness = 255; brightness >= 0; brightness--) { analogWrite(LED_PIN, brightness); delay(10); } } ``` **Key Notes:** * analogWrite() uses hardware PWM (on pins 3, 5, 6, 9, 10, 11 for Arduino Uno). * For non-PWM pins, use software PWM (less precise). **B. Raspberry Pi (Python)** ``` python import RPi.GPIO as GPIO import time LED_PIN = 18 # Broadcom GPIO18 (PWM-capable) GPIO.setmode(GPIO.BCM) GPIO.setup(LED_PIN, GPIO.OUT) pwm = GPIO.PWM(LED_PIN, 1000) # 1kHz frequency pwm.start(0) # Start with 0% duty cycle try: while True: for duty_cycle in range(0, 101, 5): # 0% to 100% pwm.ChangeDutyCycle(duty_cycle) time.sleep(0.1) for duty_cycle in range(100, -1, -5): # 100% to 0% pwm.ChangeDutyCycle(duty_cycle) time.sleep(0.1) except KeyboardInterrupt: pwm.stop() GPIO.cleanup() ``` **Key Notes:** * Only GPIO12, 13, 18, 19 support hardware PWM on Raspberry Pi. * ChangeDutyCycle() accepts 0–100%. **C. STM32 (HAL Library, C)** ``` c #include "stm32f4xx_hal.h" TIM_HandleTypeDef htim; TIM_OC_InitTypeDef sConfigOC; void PWM_Init() { htim.Instance = TIM1; htim.Init.Prescaler = 84 - 1; // 84MHz/84 = 1MHz htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 1000 - 1; // 1MHz/1000 = 1kHz PWM HAL_TIM_PWM_Init(&htim); sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500; // 50% duty (500/1000) sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); } int main() { HAL_Init(); PWM_Init(); while (1) { // Adjust duty cycle dynamically __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, 700); // 70% HAL_Delay(1000); } } ``` **Key Notes:** * Configure timer (TIMx) and channel (TIM_CHANNEL_x). * Pulse = duty cycle value (0–Period). **4. Advanced Techniques** **A. Linear vs. Perceived Brightness** Human eyes perceive brightness logarithmically. For smooth fading, use gamma correction: ``` cpp // Arduino example: Convert linear to gamma-corrected PWM uint8_t gamma_correct(uint8_t input) { return (uint8_t)(pow(input / 255.0, 2.8) * 255); } ``` **B. High-Frequency PWM** * For flicker-free applications (e.g., cameras), use >5kHz. * Example (RPi at 10kHz): ``` python pwm = GPIO.PWM(LED_PIN, 10000) # 10kHz ``` **C. Multiple LEDs (LED Strips)** * Use WS2812B (NeoPixel) libraries for addressable LEDs. * Example (Arduino): ``` cpp #include <Adafruit_NeoPixel.h> Adafruit_NeoPixel strip(60, LED_PIN, NEO_GRB + NEO_KHZ800); strip.setPixelColor(0, strip.Color(255, 0, 0)); // Red at 100% strip.show(); ``` **5. Troubleshooting** ![企业微信截图_20250818171159](https://hackmd.io/_uploads/Sypv0Pgtge.png) **6. Key Takeaways** 1. Duty Cycle controls brightness (0% = off, 100% = full on). 2. Frequency must be high enough to avoid flicker (>100Hz). 3. [Microcontroller](https://www.onzuu.com/category/microcontrollers) Limits: * [Arduino](https://www.ampheoelec.de/c/development-board-arduino): Hardware PWM on specific pins. * [Raspberry Pi](https://www.ampheoelec.de/c/raspberry-pi/raspberry-pi-boards): Limited hardware PWM pins (use software PWM if needed). * [STM32](https://www.ampheoelec.de/search/STM32): Flexible timer configurations. By mastering PWM, you can control not just LEDs but also motors, servos, and more!