The story is about when I wanted to create a game controller using Arduino. I had a problem that I could not find any tutorials with a library for Arduino Uno so I resolved to YouTube. Spent hours and hours searching, finally found one. I used its code for 2-3 days and then decided to modify it. I modified it to use 2 external pushbuttons (1 is Work In Progress) so I have decided to share it out. (it works). Please find Components and software in respective places.
Technical Challenge: Why Arduino Uno?
Normally, Arduino Uno uses the main chip ATmega328P, which communicates via Serial (UART), and has an ATmega16U2 chip acting as a USB-to-Serial converter. Making the computer recognize the Uno board as a "Joystick" cannot be achieved through standard Libraries alone. Therefore, I had to spend many hours researching until I found a suitable solution, which relies on specific protocol communication and systematic Pin state management.
Hardware Components and Operation
In building this Controller, I chose fundamental components essential for Embedded Systems, as follows:
- Arduino Uno R3: The core for processing commands.
- External Pushbuttons: Push-button switches that function as digital Inputs.
- Mechanism: When a button is pressed, a Close Circuit occurs, allowing current to flow. The board detects the change in Voltage Level.
- Pull-up Resistor: In this project, I opted to use Arduino's Internal Pull-up to reduce the number of external components. The normal state of the Pin will be
HIGH, and when the button is pressed, the state will change toLOW.
- Jumper Wires and Breadboard: For experimental circuit connections.
Code Logic Analysis and Operation
The key to development is optimizing the code for quick response (Low Latency). I further developed upon the discovered Library to support two additional external pushbuttons (one of which is currently Work In Progress).
// Example of basic operational Logic
const int buttonPin1 = 2; // Define Digital Pin for button 1
const int buttonPin2 = 3; // Define Digital Pin for button 2 (WIP)
void setup() {
Serial.begin(9600);
// Use INPUT_PULLUP for signal stability without external resistors
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
}
void loop() {
// Read state from pushbuttons (LOW = Pressed, HIGH = Released)
int state1 = digitalRead(buttonPin1);
int state2 = digitalRead(buttonPin2);
// Send data to the computer via Serial
// which will be converted into HID Command by auxiliary Software/Firmware
if (state1 == LOW) {
sendControllerData(1); // Send Logic when button is pressed
}
delay(10); // Basic Debouncing to prevent signal noise
}
Logic Explanation:
- Debouncing: In electrical engineering, when we press a button, the signal is unstable for the first fraction of a second (Bouncing). Adding a small
delayor writing Logic to re-check the state helps prevent the Controller from sending redundant commands. - Data Mapping: The code I modified Maps values from Digital Input to the data structure required by the Library, to simulate standard Gamepad button presses.
Development and Results (WIP)
Currently, the system fully supports the first external pushbutton (Tested & Working), and I am in the process of testing the second button to expand the controller's capabilities to support more complex games.
The success of this project is not solely about getting a Controller to work, but in understanding how we can transform a regular Microcontroller board into a specialized device through code modification and comprehending I/O signals.
For anyone looking for a way to create a Custom HID with Arduino Uno, I hope my approach and code customization will be useful in starting your own project development!