Friday, May 22, 2020

ATOM Matrix: The User Button

The ATOM Matrix has two buttons: a user button on the front of the device, and a reset button on the side. The user button is directly behind the 5 x 5 RGB LEDs, so to click the user button, just press on the display. The M5 API handles debouncing, and provides the following methods for working with button events:

  • M5.Btn.isPressed()
  • M5.Btn.isReleased()
  • M5.Btn.wasPressed()
  • M5.Btn.wasReleased()
  • M5.Btn.pressedFor(uint32_t ms)
  • M5.Btn.releasedFor(uint32_t ms)
All of these return Booleans. There also methods for immediately reading the button state as well as for determining when the last change occurred.

There doesn't seem to be a way to treat these events as interrupts - the methods must be used inside the application's loop.


Reading Button Events

The following code demonstrates how to use all of these events. The serial monitor should be open and the baud rate set to 115200.

 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
/**
 * Button01.ino
 *
 * By: Mike Klepper
 * Date: 26 April 2020
 *
 * Demonstrates all button events implemented in M5Stack's API
 *
 * See blog post on patriot-geek.blogspot.com
 * for instructions.
 */
 

#include "M5Atom.h"

void setup() 
{
  M5.begin(true, false, true);
  delay(10);
}

void loop() 
{
  // Is the button currently down?
  if(M5.Btn.isPressed())
  {
    Serial.println("isPressed");
  }

  // Is button currently up?
  if(M5.Btn.isReleased())
  {
    Serial.println("isReleased");
  }

  // Corresponds to onMouseDown
  if(M5.Btn.wasPressed())
  {
    Serial.println("wasPressed");
  }

  // Corresponds to onClick
  if(M5.Btn.wasReleased())
  {
    Serial.println("wasReleased");
  }

  // Long press
  if(M5.Btn.pressedFor(2000))
  {
    Serial.println("pressedFor");
  }

  // Long period of inactivity
  if(M5.Btn.releasedFor(2000))
  {
    Serial.println("releasedFor");
  }

  delay(50);
  M5.update();
}

Some things to notice in the output:

  • The isPress event is repeated
  • The releaseFor is also repeated


Dice Roller Application

As we just saw, the wasReleased() method is the most useful, as it corresponds to a mouse up event. The releasedFor(t) can be used to clear the display after a period of inactivity. Here is an application that uses those two events to simulate rolling a 6-sided die when the button is pressed. The idea is simple: we pick a random integer, then use the the drawArray function from the previous blog post to draw the corresponding digit.

  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
/*
 * Button03.ino
 * 
 * By: Mike Klepper
 * Date: 26 April 2020
 * 
 * This app makes the ATOM Matrix work like a single 6-sided die!
 * 
 * When the button is pressed
 *  - A brief animation is displayed
 *  - A random integer between 1 and 6 inclusive is displayed
 *  - If left untouched for 10 seconds, the display is cleared
 *  
 * See blog post on patriot-geek.blogspot.com
 * for more info.
 */

#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 activeColor = GRB_COLOR_RED;

int colorList[] = {GRB_COLOR_BLACK, activeColor};

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 *displayNumbers[6] = { one, two, three, four, five, six };

void setup() 
{
  randomSeed(analogRead(0));
  M5.begin(true, false, true);
  delay(20);
}

void loop() 
{
  if(M5.Btn.wasReleased())
  {
    int numberToShow = random(0, 6);

    Serial.println(numberToShow + 1);
    randomPixelAnimation(activeColor);

    drawArray2(displayNumbers[numberToShow], colorList);
  }

  if(M5.Btn.releasedFor(10000))
  {
    M5.dis.clear();
  }

  delay(50);
  M5.update();
}

void drawArray2(int arr[], int colors[])
{
  for(int i = 0; i < 25; i++)
  {
      M5.dis.drawpix(i, colors[arr[i]]);
  }
}

void randomPixelAnimation(int pixelColor)
{
  M5.dis.clear();
  
  for(int i = 0; i < 50; i++)
  {
    int currentPixel = random(0, 25);
    M5.dis.drawpix(currentPixel, pixelColor);
    delay(1);
    M5.dis.drawpix(currentPixel, GRB_COLOR_BLACK);
    delay(1);
  }
}

In a later post, the other button events will be used to build a sophisticated application.

Click here to go to the table of contents for this series.

No comments:

Post a Comment