🛠 Contrôler une LED depuis Android
Objectives
Reverse the data flow direction: a brightness slider in the Android application directly controls an LED via PWM on the Mega ADK. This is the control scheme of the old official DemoKit (frames [command][pin][value]) reduced to its essentials. We review the 15 PWM channels (pins 2 to 13 and 44 to 46) and the safe state implementation when the phone is disconnected.
Hardware
- 1 × Arduino Mega ADK + external power supply 7–12 V, 1.5 A recommended
- 1 × LED + 220 Ω resistor on pin 9 (valid PWM pin)
- 1 × Android phone + USB-A → micro-USB/USB-C cable
- Library: USB Host Shield 2.0 (ADK class)
- Pin 7 is forbidden (MAX3421E RST)
Complete code
On the board side (receiving PWM commands):
// mega-adk-controle-led-android.ino — Board: "Arduino Mega ADK"
#include <Usb.h>
#include <usbhub.h>
#include <adk.h>
USB Usb;
USBHub hub0(&Usb);
ADK adk(&Usb, "AtelierADK", "PilotageLED", "LED PWM broche 9",
"1.0", "http://example.org", "SN000003");
const byte LED = 9; // PWM : broches 2-13 et 44-46
void setup {
Serial.begin(115200);
pinMode(LED, OUTPUT);
if (Usb.Init == -1) { Serial.println(F("OSCOKIRQ failed to assert")); while (1); }
}
void loop {
Usb.Task;
if (!adk.isReady) { analogWrite(LED, 0); return; } // état sûr
uint8_t trame[3]; uint16_t len = sizeof(trame);
// trame [0x02][LED][0..255] envoyée par l'application
if (adk.RcvData(&len, trame) == 0 && len == 3 && trame[0] == 0x02) {
analogWrite(trame[1], trame[2]);
Serial.print(F("PWM broche ")); Serial.print(trame[1]);
Serial.print(F(" = ")); Serial.println(trame[2]);
}
delay(5);
}
On the Android side (SeekBar slider 0–255):
// PilotageActivity.java (extrait) — SeekBar -> trame [0x02][9][valeur]
SeekBar curseur = findViewById(R.id.curseurLuminosite);
curseur.setMax(255);
curseur.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener {
@Override public void onProgressChanged(SeekBar s, int valeur, boolean parUtilisateur) {
if (!parUtilisateur || out == null) return;
try {
byte[] trame = { 0x02, 9, (byte) valeur };
out.write(trame); // FileOutputStream sur l'accessoire
} catch (IOException deconnexion) { etatDeconnecte; }
}
@Override public void onStartTrackingTouch(SeekBar s) { }
@Override public void onStopTrackingTouch(SeekBar s) { }
});
// L'activité gère aussi ACTION_USB_ACCESSORY_DETACHED pour griser le curseur.
Expected verification
The slider varies the LED brightness without perceptible latency (3-byte frame on each change). When the cable is removed, the LED turns off (safe state analogWrite(LED, 0)) and the application greys out the slider. The console displays each received command with its value.
Common errors
- LED on a non-PWM pin (for example 14):
analogWritehas no effect — check the list 2-13 and 44-46. - Safe state forgotten: without resetting to 0 when
adk.isReadyis false, the LED remains lit at the last setpoint after disconnection. - Byte order inversion of the frame between Java code and Arduino code: test first with a fixed value (128) before connecting the slider.
- Resetting the setpoint at each
Usb.Task: do not rewriteanalogWritein a loop with a default value, otherwise the slider "does not obey". - Flooding the link with a write per slider pixel: without draining
Usb.Taskoften enough, writes accumulate; keep thedelay(5)on the board side or limit the rate on the application side. - USB permission not granted upon reconnection: the application must request permission again after
ACTION_USB_ACCESSORY_ATTACHED, otherwise the stream remains null.
Other tutorials for this board
Code examples for this board
clignotante.inoArduinobouton-led.inoArduinoscan-hote-usb.inoArduinoadk-chat-android.inoArduinoadk-telemetrie.inoArduinohote-clavier-usb.inoArduino