With only one user button, it seems to be impossible to build a full application on the ATOM Matrix! The purpose of this post is demonstrate one way of doing so, by making use of the available button events beyond the onRelease event.
The goal of this project is to build a menu system. Here are the desired properties of our application:
- The menu choices will be displayed as the digits 0 - 9
- The only action each of those choices will perform is to print the digit in the Serial monitor window
- When the button is pressed, the app "wakes up" and displays the current choice
- To advance to the next choice, release the button
- Advancing past choice 9 sets the choice back to 0
- To select the current choice, hold the button down for 2 seconds
- The action for the selected choice must fire only once - no repeated actions when we hold it down for more than 2 seconds!
- After the button has been released for 2 seconds, the display goes "to sleep"
- If the button has been released for 30 seconds, the current choice returns to 0
- Otherwise, the choice is unchanged
How do we implement this? We have all the concepts and tools from the previous posts in this series. Briefly, here is how we will implement each of the above requirements:
- Store the digits in a length 25 array, and use the drawArray to display these single characters
- Serial.println statements will do this
- Use the wasPressed event to "wake up" the device and turn on the display
- The wasReleased event will advance to the next choice
- Use modular arithmetic to cycle through the choices
- To select the current choice, use the pressedFor(2000) method
- Use a boolean to prevent pressedFor from firing if the button is held down for an extended time
- Use releasedFor(2000) to turn-off display
- Resetting the current choice to 0 is done using releasedFor(30000)
- The choice is unchanged otherwise, since we'll store it in a variable
Here is the code, in all its detail!
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | /* * Button04.ino * * By: Mike Klepper * Date: 26 April 2020 * * Demonstrates how to build a menu system with just one button! * * See post on patriot-geek.blogspot.com * for details */ #include "M5Atom.h" int GRB_COLOR_WHITE = 0xffffff; int GRB_COLOR_BLACK = 0x000000; int GRB_COLOR_RED = 0x00ff00; int GRB_COLOR_ORANGE = 0xa5ff00; int GRB_COLOR_YELLOW = 0xffff00; int GRB_COLOR_GREEN = 0xff0000; int GRB_COLOR_BLUE = 0x0000ff; int GRB_COLOR_PURPLE = 0x008080; int colorList[] = {GRB_COLOR_BLACK, GRB_COLOR_BLUE}; int activeColorList[] = {GRB_COLOR_BLACK, GRB_COLOR_GREEN}; int zero[25] = { 0,0,1,1,0, 0,1,0,0,1, 0,1,0,0,1, 0,1,0,0,1, 0,0,1,1,0 }; int one[25] = { 0,0,1,0,0, 0,1,1,0,0, 0,0,1,0,0, 0,0,1,0,0, 0,1,1,1,0 }; int two[25] = { 0,1,1,1,0, 0,0,0,0,1, 0,0,1,1,0, 0,1,0,0,0, 0,1,1,1,1 }; int three[25] = { 0,1,1,1,0, 0,0,0,0,1, 0,0,1,1,0, 0,0,0,0,1, 0,1,1,1,0 }; int four[25] = { 0,0,0,1,0, 0,1,0,1,0, 0,1,1,1,1, 0,0,0,1,0, 0,0,0,1,0 }; int five[25] = { 0,1,1,1,1, 0,1,0,0,0, 0,1,1,1,0, 0,0,0,0,1, 0,1,1,1,0 }; int six[25] = { 0,0,1,1,0, 0,1,0,0,0, 0,1,1,1,0, 0,1,0,0,1, 0,0,1,1,0 }; int seven[25] = { 0,1,1,1,1, 0,0,0,1,0, 0,0,1,0,0, 0,0,1,0,0, 0,0,1,0,0 }; int eight[25] = { 0,0,1,1,0, 0,1,0,0,1, 0,0,1,1,0, 0,1,0,0,1, 0,0,1,1,0 }; int nine[25] = { 0,0,1,1,0, 0,1,0,0,1, 0,0,1,1,1, 0,0,0,0,1, 0,0,1,1,0 }; int *displayNumbers[10] = { zero, one, two, three, four, five, six, seven, eight, nine }; int currentState = 0; bool isAsleep = false; bool wasLongPressed = false; bool commandExecuted = false; void setup() { M5.begin(true, false, true); delay(20); drawArray(displayNumbers[currentState], colorList); } void loop() { if(M5.Btn.wasPressed()) { // Display state number drawArray(displayNumbers[currentState], colorList); commandExecuted = false; } if(M5.Btn.wasReleased()) { Serial.print("isAsleep = "); Serial.println(isAsleep); Serial.print("wasLongPressed = "); Serial.println(wasLongPressed); if(wasLongPressed == false) { if(isAsleep == false) { // Advance to next state in the cycle currentState = (currentState + 1) % 10; } isAsleep = false; commandExecuted = false; Serial.println(currentState); // Display state number drawArray(displayNumbers[currentState], colorList); } wasLongPressed = false; } // Long press if(M5.Btn.pressedFor(1000)) { wasLongPressed = true; // Display state number as active drawArray(displayNumbers[currentState], activeColorList); // Perform corresponding action if(commandExecuted == false) { switch(currentState) { case 0: { performActionZero(); break; } case 1: { performActionOne(); break; } case 2: { performActionTwo(); break; } case 3: { performActionThree(); break; } case 4: { performActionFour(); break; } case 5: { performActionFive(); break; } case 6: { performActionSix(); break; } case 7: { performActionSeven(); break; } case 8: { performActionEight(); break; } case 9: { performActionNine(); break; } } commandExecuted = true; Serial.println("pressedFor"); } } // Clear display after period of inactivity if(M5.Btn.releasedFor(2000)) { M5.dis.clear(); isAsleep = true; commandExecuted = false; } // Reset to initial state after LONG period of inactivity if(M5.Btn.releasedFor(30000)) { currentState = 0; M5.dis.clear(); isAsleep = true; commandExecuted = false; // Serial.println("Reset currentState to 0"); } delay(50); M5.update(); } void performActionZero() { Serial.println("In performActionZero"); } void performActionOne() { Serial.println("In performActionOne"); } void performActionTwo() { Serial.println("In performActionTwo"); } void performActionThree() { Serial.println("In performActionThree"); } void performActionFour() { Serial.println("In performActionFour"); } void performActionFive() { Serial.println("In performActionFive"); } void performActionSix() { Serial.println("In performActionSix"); } void performActionSeven() { Serial.println("In performActionSeven"); } void performActionEight() { Serial.println("In performActionEight"); } void performActionNine() { Serial.println("In performActionNine"); } void drawArray(int arr[], int colors[]) { for(int i = 0; i < 25; i++) { M5.dis.drawpix(i, colors[arr[i]]); } } |
Here's the walk-through:
Line | Comment |
---|---|
16 - 23 | GRB color constants |
25 | Color scheme for the unselected menu item |
26 | Color scheme for when the menu item is selected |
28 - 117 | Definition of the digits corresponding to each menu item |
119 | Pointer to all those digit arrays for easy reference |
121 | The current menu item, will be an integer between 0 and 9 inclusive |
122 | Is the display off? |
123 | Has the menu item been selected? |
124 | Has the corresponding menu command been executed? |
131 | Show the initial value of the currentState, which is zero |
136 | When button is pressed... |
139 | Show the current state |
141 | The command has not YET been executed |
242 - 247 | If there has been 2 seconds of inactivity, clear the display |
250 - 257 | If there has been 30 seconds of inactivity, reset currentState to 0 |
171 | If there was a long press (1 second)... |
176 | Draw the digit as "selected" |
179 | If the corresponding command has not yet been executed... |
181 - 233 | Perform the corresponding command |
235 | Set flag indicating that the command has been performed |
260 | Poll for button events |
263 - 311 | Command implementations (currently trivial) |
313 - 318 | Our friend, the drawArray function |
So, that is how to implement a menu system using only one button! We will use this framework to build a DVD IR remote control in the next post!
Click here to go to the table of contents for this series.
No comments:
Post a Comment