LED Brightness Controller Using Multi-Function Shield

LED Brightness Controller Using Multi-Function Shield

HARDWARE REQUIRED:

  • PICUNO Microcontroller board
  • 1 × Multi-Function Shield
  • USB cable

DESCRIPTION:

This project demonstrates how to use the Analog components of a Multifunction Shield. The shield simplifies the hardware setup by providing pre-wired components, allowing you to focus on the programming. The program turns the shield into a simple light dimmer. You will use the potentiometer (the blue knob) to control the brightness of the onboard LEDs. When you turn the knob, one of the four LEDs will smoothly fade from off to fully bright. Pressing one of the push buttons allows you to select which of the four LEDs you are currently controlling.

CIRCUIT DIAGRAM:

  • Plug the Multi-function Shield directly on top of the PICUNO board. The shield's components have fixed connections to the board's pins.
  • LEDs (D1-D4) are connected to GPIO 13, 12, 11, and 10.
  • Buttons (S1-S3) are connected to Analog Pins A1, A2, and A3.
  • Potentiometer is connected to Analog Pin A0.

SCHEMATIC:

No external wiring is required. Place the Multi-Function shield directly on top of the PICUNO board.

Multi-Function shield:

LEDs (D1-D4) → GPIO 13, 12, 11, 10.

Buttons (S1-S3) → A1, A2, A3.

Potentiometer (VR) → A0

CODE -- C:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// --- Pin Definitions ---
const int LED_1_PIN = 13;
const int LED_2_PIN = 12;
const int LED_3_PIN = 11;
const int LED_4_PIN = 10;
const int ledPins[] = {LED_1_PIN, LED_2_PIN, LED_3_PIN, LED_4_PIN};

const int POT_PIN = A0;
const int BUTTON_PIN = A1;

// --- Global Variables ---
int activeLedIndex = 0;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
const long debounceDelay = 50;

void setup() {
  for (int i = 0; i < 4; i++) {
    pinMode(ledPins[i], OUTPUT);
    digitalWrite(ledPins[i], HIGH); // Turn all LEDs off (active low)
  }
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("LED Brightness Controller Ready.");
}

void loop() {
  // --- 1. Read the potentiometer ---
  int potValue = analogRead(POT_PIN); // Value from 0 to 1023

  // --- 2. Check for button press to switch active LED ---
  int buttonState = digitalRead(BUTTON_PIN);
  if (buttonState == LOW && lastButtonState == HIGH) {
    if ((millis() - lastDebounceTime) > debounceDelay) {
      activeLedIndex = (activeLedIndex + 1) % 4; 
      Serial.print("Controlling LED D");
      Serial.println(activeLedIndex + 1);
      lastDebounceTime = millis();
    }
  }
  lastButtonState = buttonState;

  // --- 3. Set the brightness of the LEDs ---
  for (int i = 0; i < 4; i++) {
    if (i == activeLedIndex) {
      int brightness = map(potValue, 0, 1023, 0, 255);
      analogWrite(ledPins[i], 255 - brightness);
    } else {
      digitalWrite(ledPins[i], HIGH);
    }
  }
  delay(10);
}
analogRead(POT_PIN) - This function reads the physical position of the blue potentiometer knob and converts it into a number between 0 and 1023.

map(potValue, 0, 1023, 0, 255) - This command takes the raw potentiometer value (0-1023) and scales it down to the 0-255 range required for controlling the LED's brightness.

analogWrite(ledPins[i], 255 - brightness) - This is the core of the dimming effect. It sends a PWM (Pulse Width Modulation) signal to the LED pin. The 255 - brightness part is important because the LEDs on this shield are "active low," meaning a lower number makes them brighter. This inverts the logic so the LED gets brighter as you turn the knob up.

activeLedIndex - This variable acts as a "pointer," keeping track of which of the four LEDs is currently selected to be controlled.

Button Logic - The if (buttonState == LOW && lastButtonState == HIGH) block detects when a button is first pressed. This "state change detection" ensures that one press only cycles to the next LED once, preventing it from rapidly skipping through all the LEDs while your finger is held down.

CODE -- PYTHON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from machine import Pin, ADC, PWM
from time import sleep_ms

# LEDs (D1, D2, D3, D4 on shield)
LED_1_PIN = 13
LED_2_PIN = 12
LED_3_PIN = 11
LED_4_PIN = 10
led_pwms = [PWM(Pin(p)) for p in [LED_1_PIN, LED_2_PIN, LED_3_PIN, LED_4_PIN]]
for led in led_pwms:
    led.freq(1000) 

pot = ADC(Pin(26))
button = Pin(27, Pin.IN, Pin.PULL_UP)

# --- Global Variables ---
active_led_index = 0
last_button_state = button.value()

# --- Main Program ---
print("LED Brightness Controller Ready.")
print("Turn the knob to adjust brightness. Press S1 to switch LEDs.")

while True:
    # reading is from 0 (min) to 65535 (max)
    pot_value = pot.read_u16()
    
    # Check for button press to switch active LED
    button_state = button.value()
    if button_state == 0 and last_button_state == 1: 
        active_led_index = (active_led_index + 1) % 4 
        print(f"Controlling LED D{active_led_index + 1}")
        sleep_ms(100) # Debounce
    last_button_state = button_state
    
    # Set the brightness of the LEDs
    for i in range(4):
        if i == active_led_index:
            duty_cycle = 65535 - pot_value
            led_pwms[i].duty_u16(duty_cycle)
        else:
            led_pwms[i].duty_u16(65535)
            
    sleep_ms(20)
PWM(Pin(p)) - This creates a Pulse Width Modulation object for each LED pin. PWM is the technique used to create a dimming effect by turning the LED on and off very rapidly.

ADC(Pin(26)) - This creates an Analog-to-Digital Converter object to read the voltage from the potentiometer.

pot_value = pot.read_u16() - This line reads the potentiometer's position as a number from 0 to 65535.

active_led_index - A variable that keeps track of which LED (0, 1, 2, or 3) is currently being controlled. Pressing the button increments this variable.

Active Low Logic - The LEDs on this shield turn on when the pin is LOW. To achieve this, the code inverts the potentiometer's reading (duty_cycle = 65535 - pot_value) to correctly map the knob's position to brightness.