Last active
August 30, 2024 20:03
-
-
Save erictroebs/3e6ca8aa2b9ed06e0b5527fd38dd2c2f to your computer and use it in GitHub Desktop.
Arduino Micro (ATmega32U4) Ten Finger Touchscreen Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Touch.h" | |
#if defined(_USING_HID) | |
#define CONTACT_COUNT_MAXIMUM 10 | |
#define REPORTID_TOUCH 0x04 | |
#define LSB(v) ((v >> 8) & 0xff) | |
#define MSB(v) (v & 0xff) | |
static const uint8_t _hidReportDescriptor[] PROGMEM = { | |
0x05, 0x0D, // USAGE_PAGE(Digitizers) | |
0x09, 0x04, // USAGE (Touch Screen) | |
0xA1, 0x01, // COLLECTION(Application) | |
0x85, REPORTID_TOUCH, // REPORT_ID (Touch) | |
// define the maximum amount of fingers that the device supports | |
0x09, 0x55, // USAGE (Contact Count Maximum) | |
0x25, CONTACT_COUNT_MAXIMUM, // LOGICAL_MAXIMUM (CONTACT_COUNT_MAXIMUM) | |
0xB1, 0x02, // FEATURE (Data,Var,Abs) | |
// define the actual amount of fingers that are concurrently touching the screen | |
0x09, 0x54, // USAGE (Contact count) | |
0x95, 0x01, // REPORT_COUNT(1) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
// declare a finger collection | |
0x09, 0x22, // USAGE (Finger) | |
0xA1, 0x02, // COLLECTION (Logical) | |
// declare an identifier for the finger | |
0x09, 0x51, // USAGE (Contact Identifier) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
// declare Tip Switch and In Range | |
0x09, 0x42, // USAGE (Tip Switch) | |
0x09, 0x32, // USAGE (In Range) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |
0x75, 0x01, // REPORT_SIZE (1) | |
0x95, 0x02, // REPORT_COUNT(2) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
// declare the remaining 6 bits of the first data byte as constant -> the driver will ignore them | |
0x95, 0x06, // REPORT_COUNT (6) | |
0x81, 0x03, // INPUT (Cnst,Ary,Abs) | |
// define absolute X and Y coordinates of 16 bit each (percent values multiplied with 100) | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
0x09, 0x30, // Usage (X) | |
0x09, 0x31, // Usage (Y) | |
0x16, 0x00, 0x00, // Logical Minimum (0) | |
0x26, 0x10, 0x27, // Logical Maximum (10000) | |
0x36, 0x00, 0x00, // Physical Minimum (0) | |
0x46, 0x10, 0x27, // Physical Maximum (10000) | |
0x66, 0x00, 0x00, // UNIT (None) | |
0x75, 0x10, // Report Size (16), | |
0x95, 0x02, // Report Count (2), | |
0x81, 0x02, // Input (Data,Var,Abs) | |
0xC0, // END_COLLECTION | |
0xC0 // END_COLLECTION | |
// with this declaration a data packet must be sent as: | |
// byte 1 -> "contact count" (always == 1) | |
// byte 2 -> "contact identifier" (any value) | |
// byte 3 -> "Tip Switch" state (bit 0 = Tip Switch up/down, bit 1 = In Range) | |
// byte 4,5 -> absolute X coordinate (0...10000) | |
// byte 6,7 -> absolute Y coordinate (0...10000) | |
}; | |
typedef struct Finger { | |
int contact; | |
int16_t x; | |
int16_t y; | |
} Finger; | |
Finger fingers[CONTACT_COUNT_MAXIMUM]; | |
Touch_::Touch_() { | |
static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor)); | |
HID().AppendDescriptor(&node); | |
for (int i = 0; i < CONTACT_COUNT_MAXIMUM; i++) { | |
fingers[i].contact = 0; | |
fingers[i].x = 0; | |
fingers[i].y = 0; | |
} | |
} | |
void Touch_::begin(void) { | |
} | |
void Touch_::end(void) { | |
} | |
void Touch_::send(uint8_t identifier, uint8_t touch, int16_t x, int16_t y) { | |
// calculate current contact count | |
uint8_t contact = 0; | |
for (int i = 0; i < CONTACT_COUNT_MAXIMUM; i++) { | |
if (fingers[i].contact) { | |
contact += 1; | |
} | |
} | |
// create data array | |
uint8_t data[] = { | |
contact, // contact count | |
identifier, // contact identifier | |
touch, // finger touches display | |
MSB(x), LSB(x), // x | |
MSB(y), LSB(y) // y | |
}; | |
// send packet | |
HID().SendReport(REPORTID_TOUCH, data, 7); | |
} | |
void Touch_::moveFingerTo(uint8_t identifier, int16_t x, int16_t y) { | |
// change finger record | |
fingers[identifier].contact = 1; | |
fingers[identifier].x = x; | |
fingers[identifier].y = y; | |
// send update | |
send(identifier, 1, x, y); | |
} | |
void Touch_::releaseFinger(uint8_t identifier) { | |
// change finger record | |
fingers[identifier].contact = 0; | |
fingers[identifier].x = 0; | |
fingers[identifier].y = 0; | |
// send update | |
send(identifier, 0, 0, 0); | |
} | |
Touch_ Touch; | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef Touch_h | |
#define Touch_h | |
#include "HID.h" | |
#if !defined(_USING_HID) | |
#warning "Using legacy HID core (non pluggable)" | |
#else | |
class Touch_ { | |
private: | |
void send(uint8_t identifier, uint8_t touch, int16_t x, int16_t y); | |
public: | |
Touch_(void); | |
void begin(void); | |
void end(void); | |
void moveFingerTo(uint8_t finger, int16_t x, int16_t y); | |
void releaseFinger(uint8_t finger); | |
}; | |
extern Touch_ Touch; | |
#endif | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define BUTTON 2 | |
#include "Touch.h" | |
void setup() { | |
// initialize touch | |
Touch.begin(); | |
// setup pins | |
pinMode(BUTTON, INPUT_PULLUP); | |
} | |
void loop() { | |
if (digitalRead(BUTTON) == LOW) { | |
int16_t x = 5000; | |
int16_t y = 5000; | |
for (; x <= 6000; x+=4) { | |
for (int i = 0; i < 10; i++) { | |
Touch.moveFingerTo(i, x + i * 100, y + i * 100); | |
} | |
} | |
for (; y <= 6000; y+=4) { | |
for (int i = 0; i < 10; i++) { | |
Touch.moveFingerTo(i, x + i * 100, y + i * 100); | |
} | |
} | |
for (; x >= 5000; x-=4) { | |
for (int i = 0; i < 10; i++) { | |
Touch.moveFingerTo(i, x + i * 100, y + i * 100); | |
} | |
} | |
for (; y >= 5000; y-=4) { | |
for (int i = 0; i < 10; i++) { | |
Touch.moveFingerTo(i, x + i * 100, y + i * 100); | |
} | |
} | |
for (int i = 0; i < 10; i++) { | |
Touch.releaseFinger(i); | |
} | |
} | |
} |
It has been a long time now, I'm not in the project anymore. Thanks anyways! :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@sobrinho Sorry for the late reply: As @francoisnicolas has mentioned, you have to connect a button to pin 2 and ground. I would not recommend to use the script without a button! Otherwise it could be difficult to flash another sketch from the PC while the Arduino is firing touchscreen input commands.
If this does not work for you, I'm afraid I can not help you. I tested the script with a newer version of Android (probably 11), Windows 10 and Linux Mint, but I do neither have access to MacOS nor such an old version of Android.