JM9 XRCU Tutorials 0.0.1a
Learn how to program XRCU
Loading...
Searching...
No Matches
Buttons

Buttons are the easiest way to talk to your robot without a computer. You can press a button to start your robot, to choose a program, or to change a setting.

XRCU has 4 buttons below the monitor. From left to right, they are called SW1, SW2, SW3 and SW4.

In this chapter, we will learn how to read these buttons in a few different ways.

Warning
Do not hold any button while you turn ON XRCU. Some buttons have special jobs when XRCU starts up. For example, holding SW2 or SW3 while turning ON XRCU will make XRCU wait for a new program instead of running the menu. If this happens by accident, just turn XRCU OFF and ON again.

Reading Buttons with digitalRead

In the last chapter, we learnt that SW1 to SW4 are pin names. So we can read a button with digitalRead(...), like this:

void setup() {
// Activate the serial monitor.
Serial.begin(9600);
}
void loop() {
// Read button SW1 and print the result.
Serial.println(digitalRead(SW1));
delay(100);
}

If you try this, you will see something strange. The serial monitor prints 1 (HIGH) when the button is NOT pressed, and prints 0 (LOW) when the button IS pressed. It is upside down!

This is because of how the buttons are wired on XRCU. When you press a button, the pin is connected to GND, so the pin becomes LOW.

It is easy to get confused by this. So XRCU gives us a better tool: the Buttons library.

The Buttons Library

A library is some code that someone else has written for us, so we can use it directly. To use the Buttons library, write this line at the very top of your program:

#include <Buttons.h>

After that, we can use 4 ready-made buttons:

Name in code Button on XRCU
button1 SW1
button2 SW2
button3 SW3
button4 SW4

To ask a button something, we write its name, a dot ., then the question. You have already done this before with Serial.begin(9600) and Serial.println(...).

Our first question is isPressed(). It gives true if the button is being pressed right now, and false if it is not. No more upside down!

#include <Buttons.h>
void setup() {
// LED_BUILTIN is the small LED on XRCU.
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
// Ask button 1: are you being pressed right now?
bool pressed = button1.isPressed();
if (pressed) {
// Turn ON the LED.
digitalWrite(LED_BUILTIN, HIGH);
} else {
// Turn OFF the LED.
digitalWrite(LED_BUILTIN, LOW);
}
}
Note
You do not need to write pinMode(SW1, INPUT) or anything like that. XRCU gets the 4 buttons ready for you before setup() runs.

Checkpoint 6.1

Upload the code above to XRCU and run it. Press and hold SW1. The LED should turn ON. Release SW1. The LED should turn OFF.

Now change the program, so that:

  1. The LED is controlled by SW3 instead of SW1.
  2. The serial monitor prints pressed when SW3 is pressed, and prints released when SW3 is not pressed. (Hint: don't forget Serial.begin(9600); and a small delay(...).)

Record a video showing the LED and the serial monitor while you press and release SW3 a few times. Submit this video to your assignment portal at checkpoint 6.1.

Pressed or Clicked?

Let's make a click counter. Every time we press SW1, we want the number to go up by 1.

#include <Buttons.h>
int counter;
void setup() {
Serial.begin(9600);
counter = 0;
}
void loop() {
if (button1.isPressed()) {
// Increase the counter by 1.
counter = counter + 1;
Serial.println(counter);
}
delay(10);
}

Try it. Press SW1 once, as fast as you can. You will see the counter jump up by 5, 10 or even more! Why?

Your finger stays on the button for a short time, maybe 0.1 seconds. But loop() runs again every 0.01 seconds. So loop() sees the button being pressed many times during 1 press.

To fix this, we use another question: isClicked().

if (button1.isClicked()) {
counter = counter + 1;
Serial.println(counter);
}

isClicked() works like a doorbell message:

  • When you press the button, XRCU writes down "button 1 was clicked".
  • When your program asks button1.isClicked(), it gets true, and the message is thrown away.
  • If your program asks again, it gets false, until you press the button again.

So 1 press only gives 1 true. That's exactly what a counter needs!

XRCU checks the buttons by itself every 0.05 seconds, in the background. It does this even when your program is busy doing a delay(...). That means a click is remembered until your program asks for it.

Note
Each button only remembers 1 click. If you press it 3 times while your program is busy, isClicked() gives true only once.

Checkpoint 6.2

Upload the click counter with button1.isPressed(). Press SW1 once quickly and observe how much the counter goes up.

Then change button1.isPressed() to button1.isClicked(), and upload again. Press SW1 once quickly again. How much does the counter go up now?

Finally, change delay(10); to delay(3000); and upload again. Press SW1 once quickly, right after a new number is printed. Does the counter still go up, even though your program was waiting when you pressed the button?

Record a video showing the serial monitor in all 3 tests. Submit this video to your assignment portal at checkpoint 6.2.

Click When Pressing, or When Releasing?

Every click has 2 moments:

  1. The pressing moment: your finger pushes the button down.
  2. The releasing moment: your finger lets go of the button.

By default, isClicked() counts a click at the pressing moment. We can tell a button to count the click at the releasing moment instead:

void setup() {
// Button 2 now clicks when it is released.
button2.setSingleClickTransitionEdge(Button::TransitionEdge::RELEASING);
}

Button::TransitionEdge::RELEASING is a long name, but you can read it from left to right: "for a Button, choose the transition edge called RELEASING". The other choice is Button::TransitionEdge::PRESSING.

Note
We only need to choose this once, so we put it inside setup().

Why would we want to click when releasing? Imagine you press a button to start your robot. If the robot starts moving at the pressing moment, your finger is still on the robot! You may push the robot to a wrong direction, or your finger may get hurt. If the robot starts at the releasing moment, your finger has already left the robot.

Remarks
Use RELEASING for buttons that start your robot.

Checkpoint 6.3

Write a program where:

  1. SW1 clicks at the pressing moment (the default). Each click of SW1 turns the LED ON.
  2. SW2 clicks at the releasing moment. Each click of SW2 turns the LED OFF.

Upload and run it. Press and hold SW1 for 3 seconds, then release it. When does the LED turn on? Press and hold SW2 for 3 seconds, then release it. When does the LED turn off?

Record a video showing your fingers and the LED during the test above. Submit this video to your assignment portal at checkpoint 6.3.

Hold to Repeat

Think about the volume button on a TV remote control. 1 click makes the volume go up by 1. If you hold the button, the volume keeps going up by itself. These repeating clicks are called pulse clicks.

Our buttons can do this too. We just need to turn on pulse clicks in setup():

void setup() {
// Holding button 1 now gives clicks again and again.
button1.setPulseClickEnabled(true);
}

With pulse clicks turned on:

  • 1 short press still gives 1 click.
  • If you hold the button for more than 1 second, isClicked() starts giving true again and again, about 20 times every second.
  • When you release the button, the clicks stop.

We can also change these 2 numbers:

void setup() {
button1.setPulseClickEnabled(true);
// Start repeating after holding for 500 milliseconds (0.5 seconds).
button1.setPulseDelayStartPeriod(500);
// Repeat at most once every 200 milliseconds (0.2 seconds).
button1.setPulseClicksMinimumInterval(200);
}
Note
1 second = 1000 milliseconds.
Remarks
Pulse clicks work best with the PRESSING moment (the default). With RELEASING, you would get 1 extra click when you let go.

Checkpoint 6.4

Make a "volume control" that prints a number from 0 to 100 on the serial monitor:

  1. The volume starts at 50.
  2. Each click of SW2 makes the volume go up by 1.
  3. Each click of SW1 makes the volume go down by 1.
  4. The volume must never go above 100 or below 0. (Hint: use if to check the volume before changing it.)
  5. Turn on pulse clicks for both buttons. Start repeating after holding for 0.5 seconds, and repeat at most once every 0.1 seconds.
  6. Only print the volume when it changes.

Upload and run it. Click SW2 a few times one by one, then hold SW2 until the volume reaches 100. Then hold SW1 until the volume reaches 0.

Record a video showing your fingers and the serial monitor during the test above. Submit this video to your assignment portal at checkpoint 6.4.

Secure Mode

In a competition, you may feel nervous and your hands may shake. You may press 2 buttons at the same time by accident, and your robot may run the wrong program!

To protect us from this, buttons have a secure mode. When secure mode is on:

  • If 2 or more buttons are pressed at the same time, none of them gives a click.
  • The buttons only work again after all buttons are released.

Secure mode works best with the RELEASING moment. With PRESSING, the first button already gives its click before you press the second button by accident. With RELEASING, no click is given until you let go, so secure mode can stop all the clicks.

Secure mode must be turned on for every button that you use:

void setup() {
button1.setSecureModeEnabled(true);
button2.setSecureModeEnabled(true);
button3.setSecureModeEnabled(true);
button4.setSecureModeEnabled(true);
}
Remarks
If you have learnt arrays and for loops, the 4 buttons are also stored in an array called buttons. buttons[0] is button1, buttons[1] is button2, and so on. So the code above can be shortened to:
for (int i = 0; i < 4; i++) {
buttons[i].setSecureModeEnabled(true);
}

Checkpoint 6.5

Write a program for all 4 buttons, where:

  1. All 4 buttons click at the releasing moment.
  2. All 4 buttons have secure mode turned on.
  3. When a button is clicked, print its name on the serial monitor, for example SW3 clicked.

Upload and run it, then do these tests:

  1. Click each button one by one.
  2. Press SW1 and SW2 together, then release them together.
  3. Press and hold SW1, then press SW3, then release SW1, then release SW3.
  4. Click each button one by one again.

Which tests print something? Which tests print nothing? Why?

Note
You may see SW4 clicked once, right when your program starts. This is the click you made on SW4 to start your program from the menu.

Record a video showing your fingers and the serial monitor during all 4 tests. Submit this video to your assignment portal at checkpoint 6.5.

Summary

Code What it does
#include <Buttons.h> Lets us use button1 to button4.
button1.isPressed() true if the button is being pressed right now.
button1.isClicked() true once for each click. The click is remembered until we ask.
button1.setSingleClickTransitionEdge(Button::TransitionEdge::PRESSING) Count clicks at the pressing moment (default).
button1.setSingleClickTransitionEdge(Button::TransitionEdge::RELEASING) Count clicks at the releasing moment.
button1.setPulseClickEnabled(true) Holding the button gives repeating clicks.
button1.setPulseDelayStartPeriod(500) Start repeating after holding for 500 ms (default: 1000 ms).
button1.setPulseClicksMinimumInterval(100) Repeat at most once every 100 ms (default: 50 ms).
button1.setSecureModeEnabled(true) No clicks when 2 or more buttons are pressed together.
Previous Next
Digital I/O Analog Inputs