Pi Pico Macropad With a Touchscreen
by AZDelivery in Circuits > Microcontrollers
1063 Views, 7 Favorites, 0 Comments
Pi Pico Macropad With a Touchscreen

Turn your Raspberry Pi Pico into a USB-HID device with a touchscreen interface! In this project, we’ll set up the programming environment in the Arduino IDE, configure libraries for the 3.5" Pico Touch LCD shield, test basic functionality, create simple buttons (for copy & paste), display custom icons, and even use Windows environment variables to launch programs.
Supplies
Raspberry Pi Pico (RP2040)
3.5" Pico Touch LCD Shield (here is a bundle for both)
USB Cable (micro USB for the Pi Pico)
Computer with the Arduino IDE installed
(Optional) Additional icons or graphics you want to display
Setting Up the Programming Environment (Pico Board, Libraries)
Install the Raspberry Pi Pico Board Package
Open the Arduino IDE and go to File > Preferences
In the field Additional Boards Manager URLs, add:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
and Click OK.
Next go to Tools > Board > Boards Manager.
Type "Pico" in the search field.
Install Raspberry Pi Pico/RP2040 (by Earle F. Philhower, III) (e.g., version 3.9.1).
Select Raspberry Pi Pico under Tools > Board > Raspberry Pi RP2040 Boards.
Install Necessary Libraries
Go to Tools > Manage Libraries.
Search for and install each of the following libraries:
- TFT_eSPI (latest version by Bodmer)
- TFT_eWidget (latest version by Bodmer)
- Adafruit_TinyUSB (latest version by Adafruit)
Configuring the TFT_eSPI Library
The TFT_eSPI library requires a User_Setup_Select.h file that includes or points to the correct setup configuration for your display.
Locate the TFT_eSPI installation folder (often in Documents > Arduino > libraries > TFT_eSPI).
Download the correct setup files for the 3.5" ILI9341-based Pico shield. (User_Setup_Select.h, Setup60_RP2040_ILI9341.h)
And place "User_Setup_Select.h" into the main TFT_eSPI folder, place "Setup60_RP2040_ILI9341.h" into TFT_eSPI > User_Setups
This ensures that your display is configured properly.
Initial Test: Hardware and Library Check
Before creating interactive buttons or displaying icons, let’s do a quick test with some graphics and touchscreen calibration. Below is an example initialTest.ino sketch.
You will need to hold the bootsel button down while connecting the USB cable, before you upload this sketch let's make sure that the settings under "Tools" is correct:
What this code does:
- Calibrates the touchscreen (storing calibration data in LittleFS).
- Performs a quick graphics test: lines, rectangles, circles, and text.
- Inverts the display color scheme every second to show that everything is running.
Downloads
Creating Simple Buttons: "COPY" and "PASTE"
Next, let’s make the display interactive. Below is an example example_SimpleButtons.ino that creates two large buttons for "COPY" and "PASTE". When touched, they send a respective Ctrl+C or Ctrl+V keystroke via USB HID.
initButtonUL(...)
Purpose: Initializes the button’s position, size, colors, and optional label.
- Coordinates & Dimensions:
- startX, startY specify the top-left corner of the button on the display.
- BUTTON_W, BUTTON_H define the button's width and height in pixels.
- Colors:
- Outline color (e.g., TFT_WHITE)
- Fill color (e.g., TFT_RED)
- Text color (e.g., TFT_YELLOW)
- Label Text and Text Size:
- The string (e.g., "COPY")
- The text size multiplier (e.g., 2 for slightly larger text)
UL stands for “Upper Left” – meaning the coordinates passed are for the top-left corner of the button.
drawSmoothButton(...)
Purpose: Renders the button on the display with anti-aliased (smooth) edges and optional outline width.
- The first parameter indicates if the button should be drawn in its “pressed” style.
- The second parameter is the outline or “frame” thickness.
- The third parameter is the background color around the button (so it can smooth the edges).
setPressAction(...) and setReleaseAction(...)
Purpose: Assign functions (callbacks) to be executed on press or release.
You define two separate functions:
- btn_1_pressAction – runs when the button is touched (pressed)
- btn_1_releaseAction – runs when the touch is lifted (button is released)
In the example, these functions send keyboard shortcuts (Ctrl+C for copy, Ctrl+V for paste) via USB HID.
press(...) and contains(...)
Purpose:
- contains(x, y) checks if a given touch coordinate ‘x‘,‘y‘`x`, `y`‘x‘,‘y‘ lies within the button’s boundaries.
- press(true/false) updates the internal state of the button to pressed or released.
In the loop() function, you’ll typically:
- Get the touchscreen coordinates (t_x, t_y).
- If the screen is pressed, call btn[i]->contains(t_x, t_y) to detect if that specific button is touched.
- If contains(...) is true, call btn[i]->press(true) and then btn[i]->pressAction().
- If the screen is not pressed, call btn[i]->press(false) and then btn[i]->releaseAction().
This sequence ensures each button’s callback fires at the correct time.
Compiler warning note: You may see a warning about converting string literals (e.g., "COPY") to char*. This is because in C++, string literals are constant and should ideally be const char*. The code still functions but you can eliminate the warning by modifying the ButtonWidget class to accept const char*.
Downloads
Displaying Icons: Converting PNG Files to C Arrays
Now, let’s add custom icons instead of just text. We can convert PNG images to C arrays using a tool such as ImageConverter 565 v1.2 (found in some UTFT libraries) or other online converters.
Converting an Image
- Download the UTFT library if needed, or locate a similar image converter.
- Run ImageConverter 565.
- Open your .png file (e.g., arduino.png).
- Save it to generate a .c file with a 16-bit (565) encoded array.
- Copy the generated array into a new header file, for example: ardicon.h.
- Add any missing definitions, such as:
Place ardicon.h in the same folder as your .ino sketch.
Using pushImage() to Display the Icon
- Include the header in your sketch:
- Use tft.pushImage(x, y, width, height, arrayName) to draw the icon at the desired coordinates.
- If colors appear swapped, add tft.setSwapBytes(true); before pushImage().
Assigning Actions Via Windows Environment Variables
To make your custom buttons do something beyond copy/paste, you can assign them to launch programs, open folders, etc. One trick is to create a Windows environment variable that points to a specific .exe file and then reference it via WIN+R.
Creating a Windows Environment Variable
- Open the Control Panel.
- Go to System and Security > System > Advanced system settings.
- Click Environment Variables.
- In User variables or System variables, click New.
- Enter a Variable name (e.g., ARDU) and a Value (the full path to your Arduino IDE.exe).
- Close all dialogs with OK.
Now, you can open the Run window (WIN+R) and type %ARDU% to start the Arduino IDE.
Starting the Arduino IDE from a Button
Below is a snippet from an example_startArduino.ino. When the third button is pressed, it:
- Opens Run with WIN+R.
- Types %ARDU%.
- Presses Enter to launch the IDE.
Expanding the Setup: More Buttons and Icons
Ready to fill the entire screen? You can create multiple rows of buttons, each with icons and different actions. For instance:
- Button to Lock the PC (WIN+L)
- Button to open File Explorer (WIN+E)
- Button to Shutdown or run any custom command
You can add whatever you want.
Here is also the expanded sketch showing six buttons, each with different icons and assigned actions. Please note that if you copy this directly, you must also have all the corresponding icon header files (e.g., Ardicon.h, Exploricon.h, Lockicon.h, Pwdownicon.h) or your own equivalents. The code snippet is quite long, but it follows exactly the same pattern we’ve already discussed.
You now have a fully-functional Raspberry Pi Pico + Touchscreen Shield that:
- Displays graphics and icons.
- Acts as a USB HID keyboard.
- Can map touchscreen presses to Windows shortcuts, environment variables, and commands.
Feel free to customize each button’s actions. You might:
- Launch your favorite apps or games
- Automate text entries
- Use it as a macro keypad for editing software or programming