- Pre-Lab preparation
- Part 1: Button class
- Part 2: Inheritance and Led class
- Part 3: PWM and LED
- Challenges
- References
- ESP32 board with pre-installed MicroPython firmware, USB cable
- Breadboard
- Push button
- Jumper wires
- Understand key object-oriented programming (OOP) concepts like encapsulation, inheritance, and polymorphism.
- Define and use classes and objects in MicroPython.
- Apply OOP to manage hardware components like LEDs, buttons, or sensors.
-
Learn the basic principles of OOP, including encapsulating data and functions in classes, inheritance (sharing functions between classes), and polymorphism (modifying behavior in child classes).
-
Review how to use GPIO pins for input and output with MicroPython. How to configure a pin as an output to control an LED. How to configure a pin as an input (with or without pull-up resistors) to detect button presses.
-
Use breadboard, jumper wires and connect one push button to ESP32 GPIO pin 27 in active-low way.
Notes:
- NC = Empty, Not Connected
- VCC = VCC (5V under USB power supply, Around 3.7V under 3.7V lipo battery power supply)
- Use pins A0, ..., A4 as input only
- Do not use In-Package Flash pins
-
Ensure your ESP32 board is connected to your computer via a USB cable. Open the Thonny IDE and set the interpreter to
ESP32
orESP8266
(depending on your board). You can click the red Stop/Restart button or press the on-board reset button if necessary to reset the board. -
Create a new file in Thonny and enter the following MicroPython code which is a class definition for the
Button
class. It is a blueprint for creating objects that represent a physical button with active-low logic connected to the ESP32 (or other microcontroller) GPIO pin.from machine import Pin class Button: """ A class to manage a button connected to a GPIO pin with pull-up resistor. """ def __init__(self, pin_number): """Initialize the button on a specific GPIO pin with pull-up resistor.""" self.button = Pin(pin_number, Pin.IN, Pin.PULL_UP) def is_pressed(self): """Check if the button is currently pressed (active-low logic).""" if self.button.value() == 0: # Pressed button returns 0 return True return False def demo(): # Example usage of the Button class btn = Button(27) if btn.is_pressed(): print(f"Button {btn} pressed...") else: print(f"Button {btn} released...") if __name__ == "__main__" : # Code that runs only if this script is executed directly demo()
Some important parts:
-
The
__init__
method is the constructor that is automatically called when a new instance of the Button class is created. -
Parameter (
pin_number
) represents the GPIO pin number where the button is connected. -
In Python,
self
is a reference to the current instance of the class and is used to access instance variables and methods within the class. -
The created object is stored in an instance variable (
self.button
), so it can be used in other methods of the class. Each instance ofButton
has its ownself.button
. -
The
is_pressed()
method checks if the active-low button is being pressed. When the button is not pressed, the pin remains at logic 1 due to the pull-up resistor. -
Note that
__name__
is a special built-in variable in Python that holds the name of the module (or script) currently being executed. If the script is being run directly (not imported),__name__
will be set to__main__
. The common usage of theif __name__ == "__main__":
condition in Python is to allow a script to be used both as a module and as a standalone program.
-
-
Save the file as
hw_config.py
in your local folder, run the code and test the button.
Inheritance in Python is a core concept of object-oriented programming that allows a class (called a child or subclass) to inherit attributes and methods from another class (called a parent or superclass). This enables the child class to use or extend the functionality of the parent class without rewriting the same code.
-
Using the
Pin
class, create a subclass to complement the pin behavior for the LEDs. Use methodsself.on()
,self.off()
, andself.value()
inherited from thePin
class.from machine import Pin import time ... class Led(Pin): # Led is a subclass of Pin """ A class to control an LED connected to a specified GPIO pin. """ def __init__(self, pin_number): """Initialize the LED on a specific GPIO pin.""" # Calls Parent's __init__ without needing `self` super().__init__(pin_number, Pin.OUT) def toggle(self): """Toggle the LED state.""" # WRITE YOUR CODE HERE def blink(self, duration=0.5, times=5): """Make the LED blink a certain number of times.""" # WRITE YOUR CODE HERE def demo(): ... # Example of using the Led class led = Led(2) print("LED blinking...") led.blink(times=3) print("Toggling LED...") led.toggle() time.sleep(1) print("Turning LED off...") led.off() time.sleep(1)
Some important parts:
-
Due to inheritance, the
Led
object is also aPin
object, and it can use any methods or attributes defined in thePin
class. -
Method
super()
refers to the parent class (Pin
) and calls its constructor. Python internally usesself
to figure out the instance for whichsuper()
is being called, so there's no need to pass it explicitly. -
Methods
self.on()
andself.off()
rely on theon()
andoff()
methods, which come from thePin
class. This shows how theLed
class can use methods inherited from its parent class to implement higher-level functionality like blinking.
-
-
Complete and test
toggle()
andblink()
methods.
PWM (Pulse Width Modulation) is a technique used to control the amount of energy supplied to a device by rapidly switching the power supply on and off. The ratio of the time the signal is on (high) to the time it is off (low) is called the duty cycle, expressed as a percentage.
By adjusting the duty cycle, PWM can control the brightness of an LED. A higher duty cycle means the LED is on more often and appears brighter, while a lower duty cycle dims the LED. For example, a 50% duty cycle keeps the LED at half brightness, while 100% makes it fully bright.
-
Using the
PWM
class frommachine
module, create a subclass to complement the pin behavior for the LEDs. Use methodsself.freq()
andself.duty()
inherited from thePWM
class.from machine import Pin from machine import PWM import time ... class PwmLed(PWM): # PwmLed is a subclass of PWM """ A class to control an LED using PWM, allowing for brightness adjustment, fading, and on/off control. """ def __init__(self, pin_number, frequency=1000): """Initialize PWM on the given pin with a default frequency and starts with a duty cycle of 0 (LED off).""" pin = Pin(pin_number, Pin.OUT) super().__init__(pin) self.freq(frequency) self.duty(0) def set_brightness(self, brightness): """Set the LED brightness using PWM (0 to 100%).""" duty_cycle = int(brightness / 100 * 1023) # Duty cycle 0 to 1023 self.duty(duty_cycle) def on(self, brightness=100): """Turn the LED on by setting the brightness to 100%.""" # WRITE YOUR CODE HERE def off(self): """Turn the LED off by setting the brightness to 0%.""" # WRITE YOUR CODE HERE def fade_in(self, duration=1): """Fade in the LED by increasing brightness gradually in 100 steps.""" step_duration = duration / 100 for i in range(100): self.set_brightness(i) time.sleep(step_duration) def fade_out(self, duration=1): """Fade out the LED by decreasing brightness gradually in 100 steps.""" # WRITE YOUR CODE HERE def demo(): ... # Example of using the PwmLed class led = PwmLed(2) print("Fading in...") led.fade_in(duration=2) print("LED on at 10% brightness...") led.on(10) time.sleep(1) print("Turning LED off...") led.off() time.sleep(1)
Some important parts:
-
The frequency
freq
can be a value between 0 and 78125. A frequency of 1000 Hz can be used to control the LED brightness. -
The duty cycle can be a value between 0 and 1023. In which 1023 corresponds to 100% duty cycle (full brightness), and 0 corresponds to 0% duty cycle.
-
The
range()
function has the following syntax:range(start, stop, step)
. By default, thestep
parameter is equal to 1.
-
-
Complete and test
on()
,off()
, andfade_out()
methods. -
To test if a class is a superclass or a subclass of another class in Python, you can use the built-in functions
issubclass()
andisinstance()
.The
issubclass()
checks if a class is a subclass of another class. It returnsTrue
if the first argument is a subclass of the second. Theisinstance()
function checks if an object is an instance of a class or a subclass of that class. It returnsTrue
if the object is an instance of the specified class or any subclass thereof.print("Testing class relationship...") print(issubclass(Led, PwmLed)) print(isinstance(led, PWM))
-
Write a program that toggles the LED state (on/off) every time the button is pressed.
-
Control the brightness of an LED using a button. Write a program that increases the brightness by 20% each time the button is pressed. Once it reaches 100%, the next press should reset it to 0%.
-
Create different blinking patterns for an LED based on button presses. Write a program that cycles through three different blinking patterns (e.g., fast, slow, and a double blink) each time the button is pressed.
-
Fred's Cave. MicroPython Class Inheritance
-
MicroPython Documentation. Pulse Width Modulation
-
RandomNerdTutorials.com. ESP32/ESP8266 PWM with MicroPython – Dim LED
-
Real Digital. Project 4 A Pulse-Width Modulator IP Block. Creating and programming a PWM circuit to control LED brightness