Every µC has some GPIO (General-Purpose I/O) pins, which can be used as inputs or outputs. This was used in the [[Blinking an LED]] example to control an on-board LED attached to one pin. ## First preparations Let's avoid having to create a new project folder for each example: copy the files from the [[Speeding things up]] page into a new folder (perhaps called "`gpio`"), which has all the settings and general configuration in place to add more examples as individual source files. Right now, this folder should have the following files in it: ```text . ├── defs.h ├── logf.cpp └── platformio.ini ``` To add a new example, such as the next one, create a "`toggle.cpp`" source file and add one line to `platformio.ini`: "`[env:toggle]`". To build and run this new example, we can now use the command "`pio run -t upload -e toggle`". More examples can be added the same way. ## Push-button toggle This example toggles the (on-board) LED when pressing the (on-board) "KEY" button: ```c++ #include <jee.h> #include <jee/hal.h> using namespace jeeh; #include "defs.h" int main () { initBoard(); while (true) { if (!button) { // pressed led.toggle(); do cycles::msBusy(50); while (!button); // still pressed cycles::msBusy(50); } } } ``` As mentioned above, there is no need to create a new project area for this. Simply save the above file in `toggle.cpp` and add an `[env:toggle]` line to the `platformio.ini` file. Since the LED and button are both on-board, they're always available. For this reason, their definitions are added to `defs.h` and included in each example. Insert this at the top of `defs.h`: ```c++ const Pin led {"C13","P"}; // push-pull output mode const Pin button {"A0","U"}; // pull-up input mode ``` This ties the definition of `led` to the "PC13" pin and `button` to the "PA0" GPIO pin (the P is implicit), and configures their mode. With pull-up mode, as long as the button is *not* pressed, the pin will stay high. Pressing it shorts it to ground, hence the `if (!button) ...` check. Unfortunately, mechanical buttons tend to suffer from [contact bounce](https://en.wikipedia.org/wiki/Switch#Contact_bounce), which causes the transitions to quickly repeat for a few milliseconds. The code above detects a button press, toggles the LED, and checks every 50 ms whether the button has been released. Then it waits another 50 ms to ignore the contact bounce during release. The push button readout is now "debounced". Pressing it will toggle the LED on or off without missing a beat or double-takes. ## Pull-ups and pull-downs Not to be confused with _push-ups_, which is beyond the realm of what a microcontroller can do ... GPIO pins used as digital inputs should not be left floating. On STM32, the default mode for a pin is "input, no pull-up or pull-down". When read, its value is indeterminate. JeeH uses a string-based convention for defining pins: the name of the pin, and its mode. For simple uses, these can be defined as above, i.e. const Pin <var> {"<name>","<mode"}; The name is an uppercase letter (A..Z) plus a number (0..15). The mode is a combination of letters, which indicate the pin mode, its speed (drive strength) when used as output, and optionally the "alternate mode" to set it to (0..15). An alternate mode is used to connect a pin to a specific hardware peripherals inside the µC, when not used as GPIO pins. These mappings are hard-wired and fully described in detail in the µCs *Reference Manual*. For now, the following partial list of modes will suffice: - `F` - floating input mode (default) - `A` - analog mode - `P` - push-pull output mode - `O` - open-drain output mode With the following modifiers: - `U` - pull-up - `D` - pull-down Another way to configure pins and their modes, is with `Pin::config`: ```c++ void Pin::config (char const* desc, ...); // details omitted ``` The description lists a series of pin definitions, as `<name1>:<mode1>,<name2>:<mode2>,...`. This format can be used to specify an entire group of pins, as will be shown later on. Here is an example, using an otherwise-unconnected pin "PA1": ```c++ #include <jee.h> #include <jee/hal.h> using namespace jeeh; #include "defs.h" const Pin pin {"A1"}; int main () { initBoard(); pin.mode("U"); assert(pin == 1); pin.mode("D"); assert(pin == 0); pin.mode("P"); assert(pin == 0); // off is the default setting pin = 1; assert(pin == 1); pin = 0; assert(pin == 0); logf("OK"); } ``` Save the above and add the line `[env:pull]` to `plaformio.ini`. Then, with a terminal session connected to the serial port, type: `pio run -t upload -e pull` If all is well, the only output will be a line with the startup greeting and a line with "OK".