11# Pedestrian_Button Class
22
3- The ` Pedestrian_Button ` extends the ` machine.Pin ` to provide a debounced, interrupt-driven interface for a pedestrian button, with optional debug output .
3+ The ` Pedestrian_Button ` class extends the ` machine.Pin ` class to provide a debounced button interface specifically designed for pedestrian crossing systems. It uses interrupt-based detection and software debouncing to reliably capture button presses .
44
55## Constructor
66
77``` python
88Pedestrian_Button(pin, debug = False )
99```
10- - ` pin ` : The GPIO pin number the button is connected to.
11- - ` debug ` : Set to ` True ` to enable debug print statements.
10+ - ` pin ` ( ` int ` ) : The GPIO pin number the button is connected to.
11+ - ` debug ` ( ` bool ` , optional): Enable debug print statements. Defaults to False .
1212
1313## Example Usage
1414
1515``` python
1616from pedestrian_button import Pedestrian_Button
17- import time
17+ from time import sleep
1818
19- # Create a Pedestrian_Button on GPIO pin 14 with debug enabled
19+ # Create a Pedestrian_Button on GPIO pin 22 with debug enabled
2020button = Pedestrian_Button(22 , debug = True )
2121
22+ # Main loop
2223while True :
23- # Check if the button has been pressed (pedestrian waiting)
24- if button.button_state:
25- print (" Pedestrian button pressed!" )
26- # Reset the waiting state after handling
27- button.button_state = False
28- time.sleep(0.1 )
24+ # Check if button has been pressed
25+ if button.button_state():
26+ print (" Pedestrian waiting - processing crossing request" )
27+ # Process crossing request
28+
29+ # Reset the button state after handling
30+ button.button_state(False )
31+
32+ sleep(0.1 ) # Small delay to prevent busy waiting
2933```
3034
31- ## Methods and Properties
32-
33- - ** button_state** (property)
34- - Gets: Returns ` True ` if the button is pressed or has been pressed since last reset, ` False ` otherwise. Prints debug info if enabled.
35- - Sets: Allows manual reset of the internal waiting state.
35+ ## Methods
3636
37+ - ** button_state(value=None)**
38+ Multi-purpose method that acts as both getter and setter for the pedestrian waiting state.
39+ - When called with no arguments: Returns the current waiting state
40+ - When called with a boolean argument: Sets the waiting state
41+
3742- ** callback(pin)**
38- Interrupt handler called on button press (rising edge). Handles debouncing and sets the waiting state.
43+ Internal interrupt handler that's called when the button is pressed.
44+ Implements software debouncing (200ms) and sets the pedestrian waiting flag.
3945
40- ---
46+ ## Notes
4147
42- ** Notes: **
43- - The button should be wired between the specified GPIO pin and GND .
44- - The uses the internal pull-down resistor and sets up an interrupt for rising edge detection .
45- - Debouncing is handled in software (200ms ).
48+ - The button should be connected between the specified GPIO pin and 3.3V.
49+ - The class uses the internal pull-down resistor configuration .
50+ - Debouncing prevents multiple rapid detections from a single button press .
51+ - The interrupt triggers on the rising edge (when button is pressed ).
4652
4753## Class Unit Test
4854
4955``` python
50- from time import sleep
5156from pedestrian_button import Pedestrian_Button
57+ from time import sleep
5258
53- # Replace 22 with the GPIO pin your button is connected to
59+ # Create button with debug enabled
5460button = Pedestrian_Button(22 , debug = True )
5561
56- print (" Testing initial button_state (should be False if not pressed)" )
57- initial_state = button.button_state
58- if initial_state is False :
59- print (" Initial .button_state passed" )
62+ print (" Testing initial state (should be False)" )
63+ if button.button_state() == False :
64+ print (" Initial state test passed" )
6065else :
61- print (" Initial .button_state failed" )
62-
63- print (" Please press and release the button within 5 seconds..." )
64- pressed = False
65- for _ in range (50 ):
66- if button.button_state:
67- pressed = True
68- break
69- sleep(0.1 )
70-
71- if pressed:
72- print (" Button press detected: .button_state passed" )
66+ print (" Initial state test failed" )
67+
68+ print (" Testing manual state setting" )
69+ button.button_state(True )
70+ if button.button_state() == True :
71+ print (" Manual state setting test passed" )
7372else :
74- print (" Button press not detected: .button_state failed" )
73+ print (" Manual state setting test failed" )
74+
75+ print (" Press the button within 5 seconds to test interrupt..." )
76+ sleep(5 )
7577
76- print (" Testing button_state setter (reset to False)" )
77- button.button_state = False
78- sleep(0.1 )
79- if button.button_state is False :
80- print (" .button_state setter passed" )
78+ if button.button_state():
79+ print (" Button press detected - interrupt test passed" )
8180else :
82- print (" .button_state setter failed " )
81+ print (" No button press detected " )
8382
84- print (" Manual test complete." )
83+ print (" Testing state reset" )
84+ button.button_state(False )
85+ if button.button_state() == False :
86+ print (" State reset test passed" )
87+ else :
88+ print (" State reset test failed" )
8589```
8690
8791## Class Implementation
@@ -117,36 +121,38 @@ class Pedestrian_Button(Pin):
117121 self .__pin = pin
118122 self .__last_pressed = ticks_ms() # Track the last time the button was pressed
119123 self .__pedestrian_waiting = False
120- self .button_state
121124 self .irq(
122125 trigger = Pin.IRQ_RISING , handler = self .callback
123126 ) # Set up interrupt on rising edge
124127
125- @ property
126- def button_state (self ):
127- """ Get the current state of the pedestrian waiting flag.
128-
129- Returns:
130- bool: True if a pedestrian is waiting (button has been pressed), False otherwise.
128+ def button_state (self , value = None ):
131129 """
132- if self .__debug:
133- print (
134- f " Button connected to Pin { self .__pin} is { ' WAITING' if self .__pedestrian_waiting else ' NOT WAITING' } "
135- )
136- return self .__pedestrian_waiting
130+ Get or set the current state of the pedestrian waiting flag.
137131
138- @button_state.setter
139- def button_state (self , value ):
140- """ Set the pedestrian waiting state manually.
141-
142- This allows external code to reset the waiting state after handling a button press.
132+ - If called with no arguments, returns the current state (getter).
133+ - If called with a boolean argument, sets the state (setter).
143134
144135 Args:
145- value (bool): The new state to set, typically False to reset after handling.
136+ value (bool, optional): If provided, sets the pedestrian waiting state.
137+
138+ Returns:
139+ bool: Current state if called without arguments.
146140 """
147- self .__pedestrian_waiting = value
148- if self .__debug:
149- print (f " Button state on Pin { self .__pin} set to { value} " )
141+ if value is None :
142+ # Getter
143+ if self .__debug:
144+ print (
145+ f " Button connected to Pin { self .__pin} is { ' WAITING' if self .__pedestrian_waiting else ' NOT WAITING' } "
146+ )
147+ return self .__pedestrian_waiting
148+ else :
149+ self .__pedestrian_waiting = bool (
150+ value
151+ ) # Convert to boolean to ensure proper type
152+ if self .__debug:
153+ print (
154+ f " Button state on Pin { self .__pin} set to { self .__pedestrian_waiting} "
155+ )
150156
151157 def callback (self , pin ):
152158 """ Interrupt handler called when the button is pressed (rising edge).
@@ -159,9 +165,7 @@ class Pedestrian_Button(Pin):
159165 pin (Pin): The pin that triggered the interrupt.
160166 """
161167 current_time = ticks_ms() # Get the current time in milliseconds
162- if (
163- ticks_diff(current_time, self .__last_pressed) > 200
164- ): # 200ms debounce delay
168+ if ticks_diff(current_time, self .__last_pressed) > 200 : # 200ms debounce delay
165169 self .__last_pressed = current_time
166170 self .__pedestrian_waiting = True
167171 if self .__debug:
0 commit comments