1212/* Buzzer (digital pin 2) on port D */
1313#define PORTD_BUZZER (1 << 2)
1414
15+ /* Button minimum hold time (ms) -- avoid counting bounces as presses */
16+ #define BUTTON_HOLD_TIME_MS 20
17+
18+
19+ /* Structure to track button presses */
20+ struct button_info {
21+ uint8_t hold_time ; /* Time the button was held down */
22+ uint8_t count ; /* Number of times the button was pressed */
23+ };
24+
25+
26+ /* Static functions */
27+ static void track_button (struct button_info * info );
28+ static uint8_t get_tracked_presses (const struct button_info * info );
29+
1530
1631/* Initializes the LED/button interface. */
1732void init_led_button (void )
@@ -25,55 +40,104 @@ void init_led_button(void)
2540}
2641
2742
28- /* Count the presses on the button during the specified period. */
29- uint8_t count_button_presses (uint16_t wait_ms )
43+ /* Wait the specified amount of time for the button to be pressed. */
44+ bool wait_for_button_timeout (uint16_t led_on_time_ms , uint16_t led_off_time_ms ,
45+ uint16_t timeout_ms )
3046{
31- uint8_t count = 0 ;
32- uint8_t press_time = 0 ;
33-
34- while (wait_ms -- > 0 ) {
35- if (PINB & PORTB_BUTTON ) {
36- /* Button not pressed; if it was previously held a sufficient time,
37- increment the count */
38- if (press_time > 20 ) {
39- count += 1 ;
40- }
41- press_time = 0 ;
42- } else {
43- /* Button pressed; increment the press time */
44- press_time += 1 ;
47+ const uint16_t led_cycle_time_ms = led_on_time_ms + led_off_time_ms ;
48+ uint16_t led_cycle_pos = 1 ;
49+ struct button_info info = {0 , 0 };
50+
51+ while (timeout_ms > 0 ) {
52+ if (led_cycle_pos == 1 ) {
53+ PORTB |= PORTB_LED ;
54+ } else if (led_cycle_pos == led_on_time_ms ) {
55+ PORTB &= ~PORTB_LED ;
56+ } else if (led_cycle_pos == led_cycle_time_ms ) {
57+ led_cycle_pos = 0 ;
4558 }
4659
47- _delay_ms (1 );
48- }
60+ track_button (& info );
4961
50- if (press_time > 20 ) {
51- count += 1 ;
62+ if (info .count ) {
63+ break ;
64+ }
65+
66+ timeout_ms -= 1 ;
67+ led_cycle_pos += 1 ;
5268 }
5369
54- return count ;
70+ /* Will wait for the button to be released */
71+ uint8_t presses = get_tracked_presses (& info );
72+ PORTB &= ~PORTB_LED ;
73+
74+ return presses > 0 ;
5575}
5676
5777
58- /* Blink the LED with the specified delays and count . */
59- uint8_t blink_led (uint16_t on_time_ms , uint16_t off_time_ms , uint8_t count ,
60- bool wait_for_first_press )
78+ /* Blink the LED and wait for the user to press the button . */
79+ uint8_t count_button_presses (uint16_t led_on_time_ms ,
80+ uint16_t led_off_time_ms )
6181{
62- uint8_t button_presses = 0 ;
82+ const uint16_t led_cycle_time_ms = led_on_time_ms + led_off_time_ms ;
83+ uint16_t led_cycle_pos = 1 ;
84+ struct button_info info = {0 , 0 };
85+ uint16_t timeout_ms = 0 ;
86+
87+ while ((info .count == 0 ) || (timeout_ms > 0 )) {
88+ if (led_cycle_pos == 1 ) {
89+ PORTB |= PORTB_LED ;
90+ } else if (led_cycle_pos == led_on_time_ms ) {
91+ PORTB &= ~PORTB_LED ;
92+ } else if (led_cycle_pos == led_cycle_time_ms ) {
93+ led_cycle_pos = 0 ;
94+ }
95+
96+ track_button (& info );
97+
98+ if (info .hold_time ) {
99+ timeout_ms = 500 ;
100+ }
101+
102+ timeout_ms -= 1 ;
103+ led_cycle_pos += 1 ;
104+ }
63105
64- while (count > 0 ) {
65- PORTB |= PORTB_LED ;
66- button_presses += count_button_presses (on_time_ms );
106+ PORTB &= ~PORTB_LED ;
67107
68- PORTB &= ~PORTB_LED ;
69- button_presses += count_button_presses (off_time_ms );
108+ /* Will wait for the button to be released */
109+ return get_tracked_presses (& info );
110+ }
70111
71- if (button_presses || !wait_for_first_press ) {
72- count -= 1 ;
112+ /* Wait a fixed amount of time, blinking the LED */
113+ uint8_t delay (uint16_t led_on_time_ms , uint16_t led_off_time_ms ,
114+ uint16_t delay_ms )
115+ {
116+ uint16_t led_cycle_time_ms = led_on_time_ms + led_off_time_ms ;
117+ uint16_t led_cycle_pos = 1 ;
118+ struct button_info info = {0 , 0 };
119+
120+ while (delay_ms > 0 ) {
121+ if (led_on_time_ms != 0 ) {
122+ if (led_cycle_pos == 1 ) {
123+ PORTB |= PORTB_LED ;
124+ } else if (led_cycle_pos == led_on_time_ms ) {
125+ PORTB &= ~PORTB_LED ;
126+ } else if (led_cycle_pos == led_cycle_time_ms ) {
127+ led_cycle_pos = 0 ;
128+ }
73129 }
130+
131+ track_button (& info );
132+
133+ delay_ms -= 1 ;
134+ led_cycle_pos += 1 ;
74135 }
75136
76- return button_presses ;
137+ PORTB &= ~PORTB_LED ;
138+
139+ /* Will wait for the button to be released */
140+ return get_tracked_presses (& info );
77141}
78142
79143
@@ -84,3 +148,53 @@ void beep(void)
84148 _delay_ms (1 );
85149 PORTD &= ~PORTD_BUZZER ;
86150}
151+
152+
153+ /*
154+ * Track the button presses during roughly 1 ms.
155+ * The info struct must be initialized to all zeros before calling this
156+ * function.
157+ */
158+ void track_button (struct button_info * info )
159+ {
160+ bool button_held = ((PINB & PORTB_BUTTON ) == 0 );
161+
162+ if (button_held ) {
163+ /* The button is held; increment the hold time */
164+ info -> hold_time += 1 ;
165+
166+ } else {
167+ /* Check if the button was just released after being held for
168+ a sufficient time */
169+ if (info -> hold_time > BUTTON_HOLD_TIME_MS ) {
170+ info -> count += 1 ;
171+ }
172+
173+ info -> hold_time = 0 ;
174+ }
175+
176+ _delay_ms (1 );
177+ }
178+
179+
180+ /*
181+ * Count the button presses after a tracking operation.
182+ */
183+ uint8_t get_tracked_presses (const struct button_info * info )
184+ {
185+ uint8_t count = info -> count ;
186+
187+ /* Wait for the button to be released */
188+ while ((PINB & PORTB_BUTTON ) == 0 ) {
189+ /* Nothing */
190+ }
191+
192+ /* Count the last button press (if the button was still held the last time
193+ track_button was called */
194+ if (info -> hold_time > BUTTON_HOLD_TIME_MS ) {
195+ count += 1 ;
196+ }
197+
198+ return count ;
199+ }
200+
0 commit comments