Go Down

Topic: [Tutorial] Arduino UNO/MEGA como teclado, mouse, joystick. (Read 1 time) previous topic - next topic

carmeloco

Buenas, primero de todo, quiero dar las gracias a Daniel Gallardo, profesor de  un curso  de Arduino-Processing al que estoy asistiendo, y es quien me ha explicado cómo hacer esto.

Dado que bastante gente quiere usar Arduino como un teclado, mouse o joystick, he decidido hacer este tutorial.

Lo normal, es que cuando se quiere hacer esto, es usar un Arduino Leonardo, Micro, Due o Esplora, que son los que nos permiten esta funcionalidad directamente, usando unos comandos específicos para estos modelos.

El caso es que también se puede hacer con un Arduino UNO o con un Mega. El truco está en re-grabar el firmware del Atmega 16u2 que llevan estos modelos, para la comunicación USB-Serial.

En este tutorial, explicaré cómo hacer que un Arduino UNO, se comporte como un teclado, conectado al USB de un PC con Windows. Todo lo que voy a explicar aquí, es para poder hacerlo bajo Windows, ya que es el sistema operativo del que dispongo.

Bien, pues empecemos, en la siguiente página web:

http://hunt.net.nz/users/darran/

Tenemos toda la información, firmwares y sketches de prueba, para hacer todo esto. Para hacer el teclado, nos basaremos en este:

http://hunt.net.nz/users/darran/weblog/b3029/Arduino_UNO_Keyboard_HID_version_03.html

Lo primero que tenemos que hacer, es subir el sketch al arduino, ya que una vez re-grabado el firmware del 16u2, perdemos la posibilidad de cargar el sketch por el puerto USB, ya que incluso deja de ser detectado por el PC como un arduino, y pasa a detectarse como un teclado. El sketch de prueba es este:

http://hunt.net.nz/users/darran/weblog/b3029/attachments/2d281/kbd_usb_demo.pde

Code: [Select]
/* Arduino USB Keyboard HID demo
*
* Sends Volume up, hello world, and Volume Down to the host PC
*
*/

uint8_t buf[8] = { 0 }; /* Keyboard report buffer */

void setup();
void loop();

#define KEY_LEFT_CTRL 0x01
#define KEY_LEFT_SHIFT 0x02
#define KEY_RIGHT_CTRL 0x10
#define KEY_RIGHT_SHIFT 0x20

void setup()
{
    Serial.begin(9600);
    delay(200);
}

char *str = "+hello world-";

void loop()
{
    char *chp = str;
    delay(5000);
    while (*chp) {
   
 if ((*chp >= 'a') && (*chp <= 'z')) {
    buf[2] = *chp - 'a' + 4;
 } else if ((*chp >= 'A') && (*chp <= 'Z')) {
    buf[0] = KEY_LEFT_SHIFT; /* Caps */
    buf[2] = *chp - 'A' + 4;
 } else {
    switch (*chp) {
    case ' ':
     buf[2] = 0x2c; // Space
 break;
    case '+':
       buf[2] = 128; // Volume up
       break;
    case '-':
       buf[2] = 129; // Volume down
       break;
    default:
        /* Character not handled. To do: add rest of chars from HUT1_11.pdf */
 buf[2] = 0x37; // Period
 break;
    }
 }

 Serial.write(buf, 8); // Send keypress
 buf[0] = 0;
 buf[2] = 0;
 Serial.write(buf, 8); // Release key
 chp++;
    }
}


Este código, según dice el comentario que hay al principio, envía un "subir volumen", después la frase "hello world" tal y como si la hubiésemos tecleado, y un "baja volumen", y esto, lo repite cada 5 segundos. Realmente, no voy a entrar en las particularidades del sketch, ya que quien quiera más información sobre cómo funciona, lo puede ver en el link que dejé más arriba. Lo importante de este post, es el tema de re-grabar el firmware del arduino y demostrar que puede hacerse con un UNO.

Una vez subido el sketch al arduino, lo siguiente que necesitamos es el Atmel Flip.

http://www.atmel.com/tools/flip.aspx

Esto es una aplicación para grabar archivos .hex directamente en el 16u2 a través de puerto USB.

Aquí el link de descarga:

http://www.atmel.com/images/Flip%20Installer%20-%203.4.7.112.exe

Instalamos el Atmel Flip, lo ejecutamos y tenemos esto:



Lo siguiente que tenemos que hacer, es darle al icono del chip que hay a la izquierda del todo, o ir al menu "device/select" y seleccionar el ATmega 16u2 y aceptar.

Ahora, vamos a poner el chip en modo DFU. Para eso, teniendo el arduino conectado al ordenador por el cable USB, hacemos un reset al chip 16u2, haciendo un puente en los pines que aparecen en rojo en la siguiente imagen:



Soltamos el puente que hemos hecho, y Windows, nos reconocerá el arduino como un dispositivo desconocido. Le cargamos el driver que hay en "C:\Program Files (x86)\Atmel\Flip 3.4.7\usb" y ahora sí que nos lo reconocerá como un ATmega 16u2. Dentro del Administrador de dispositivos de Windows, lo podemos ver dentro de la categoría "Atmel USB Devices".

En el link que puse antes:

http://hunt.net.nz/users/darran/weblog/b3029/Arduino_UNO_Keyboard_HID_version_03.html

Tenemos el .hex que es el firmware que debemos cargar al 16u2 con el programa Atmel Flip. Aquí el link de descarga:

http://hunt.net.nz/users/darran/weblog/b3029/attachments/03237/Arduino-keyboard-0.3.hex

Lo descargamos, y en Flip, en el Menu "File/Load HEX file..." cargamos el archivo.hex que nos acabamos de descargar que será el "Arduino-keyboard-0.3.hex". Después, le damos al icono con forma de cable USB y seleccionamos USB, también podemos hacerlo desde el menu "Settings/Communication/USB" y en la nueva ventana que nos aparece en la que pone "USB Port Connection" seleccionamos "Open".

Vamos al menu "device/Erase" y luego "Device/program". Con esto ya tenemos el Arduino re-programado como un teclado. A partir de este momento, para poder comprobar que funciona, abrimos un "Wordpad" de windows, desconectamos el USB del arduino y lo volvemos a conectar, para que el 16u2 salga del modo DFU y sea detectado por el PC como un teclado USB.

Veremos que cada 5 segundos aparece la frase "hello world". Lo de subir y bajar el volumen, la verdad es que yo no lo he visto en ningún momento, pero sí que nos escribe en el PC la frase, tal y como si la hubiésemos tecleado.

Pues bien, ya tenemos el UNO como un teclado. En el siguiente mensaje de este post, os enseñaré cómo volver a dejar el arduino como estaba antes.

carmeloco

Bien, como había prometido, paso a explicar como dejar el arduino como estaba. Esto también es válido, si queremos modificar el Sketch del teclado, para poderlo cargar por el USB. Podríamos volver a poner el chip como Arduino UNO, cargar el nuevo sketch modificado, y volver a poner el chip 16u2 con el firmware de teclado, como expliqué anteriomente.

Si acabamos de usar el programa Atmel Flip para programar el 16u2 con el firmware de teclado, un consejo es que lo cerremos y lo volvamos a abrir para cargar el firmware de Arduino Uno, ya que lo de quitar el USB y volverlo a conectar, a veces no le sienta muy bien y se queda un poco colgado.

Para que el arduino no nos moleste escribiendo cosas, hacemos el puente del reset que expliqué en el mensaje anterior, para poner el 16u2 en modo DFU, y que no nos interfiera en lo que hacemos.

Una vez abierto de nuevo el Atmel Flip, abrimos el archivo "Arduino-usbserial-atmega16u2-Uno-Rev3.hex" que encontraremos en la carpeta de instalación del IDE de Arduino, en la ruta "C:\Program Files (x86)\Arduino\hardware\arduino\avr\firmwares\atmegaxxu2\arduino-usbserial"

Seguimos el mismo procedimiento que antes, conectamos el dispositivo por "settings/communication/USB", le hacemos el borrado (device/erase) y luego lo programamos (device/program).

Desconectamos el arduino del USB y los volvemos a conectar, y ya lo tenemos como un arduino normal. Podemos probar que vuelve a funcionar normalmente cargando el ejemplo del "Blink"

Como dije, esto también lo podemos hacer con el Mega. Para el teclado usaremos el mismo firmware que descargamos anteriormente, pero para volverlo a dejar como estaba, tendremos que cargar el firmware "Arduino-usbserial-atmega16u2-Mega2560-Rev3.hex" que está en el mismo directorio de la instalación del IDE de arduino, donde encontramos el del UNO.

max_saeta

Saludos.
Me salta una duda, se puede hacer que este Atmega8U2 funcione como un leonardo?

Y tengo un problema mi MEGA no entra en modo DFU, que puedo hacer?

carmeloco

A la primera pregunta, en principio, se puede, pero hay un pequeño problema, y es que el ATmega 8u2, tiene solo 8 KB de flash y 512 bytes de SRAM, frente a los 32 KB de flash y 2,5 KB de SRAM del leonardo, de forma que, no creo que haga falta que te explique qué problemas te puedes encontrar  :)

A la segunda pregunta, si tienes un MEGA con ATmega 8u2, eso significa que es un R1 o un R2 (yo hablaba de las versiones R3 tanto del UNO como del MEGA.

En el caso de usar un ATmega 8u2, hay veces que es necesario poner una resistencia de 10K. Hay un enlace que lo explica:

http://arduino.cc/en/Hacking/DFUProgramming8U2

Lo que pasa es que en el caso del UNO queda claro de donde hay que poner la resistencia, cosa que en el mega, no queda tan claro...

Buscaré a ver si encuentro algo, aunque yo no lo podré probar, ya que mis arduinos llevan el 16u2.

carmeloco

Por cierto, se me olvidaba. Siempre se puede usar un programador ISP y programar el 8u2 por el puerto ICSP del 8u2.

Edito: Acabo de ver que en la R2 ya incluyen la resistencia. Debes de tener una R1.

http://arduino.cc/en/Main/ArduinoBoardMega2560

Quote
Revision 2 of the Mega2560 board has a resistor pulling the 8U2 HWB line to ground, making it easier to put into DFU mode.

carmeloco

max_saeta, prueba a poner una resistencia PULLUP de 10K en el pin de reset del conector ICSP del 8u2, o sea, una resistencia, que una pata esté en el pin de arriba del puente que se hace para ponerlo en DFU, y la otra a 5V.

El pin de reset es el que sale en la siguiente foto:



Es un UNO, pero en el MEGA es exactamente igual, ya que el ICSP está colocado de la misma forma.

max_saeta

Saludos
Realmente si tengo la R1, luego de mucho usarla nunca me había dado cuenta. Carmeloco te comento que ya tiene el resistor de 10K entre reset y Vcc, ahora sera colocar el diodo paralelo a la resistencia y polarizada inversamente.

Pero mi pregunta: Puedo cargar el soft de la R3 a esta R1?

Por cierto en la UNO me funciono correctamente tu tutorial.

Lo de leonardo te lo preguntaba para ver la posibilidad futura de simularla y que el resto del programa este en el Atmega 328P.

max_saeta

Carmeloco

Gracias he aprendido bastante hoy con tu tutorial.

Para responder a mi pregunta halle esto: Reflashear 8u2

carmeloco

Lo de cargar el firmware de una R3 en la R1, no lo se, ya que la R3 usa un 16u2, aunque todo es probarlo. siempre se puede volver atrás.

Lo del leonardo, lo veo complicado, ya que, ¿cómo hacemos para que el 16u2 se comunique con el 328p? Habría que hacer un "custom firmware", vamos, un intermedio entre el firmware real del leonardo y los firmwares específicos que puse el link de Darran, que sí que se comunican con el 328p.

No sé si se podría, pero se me ocurre que en el leonardo hay 2 serials. Es posible que pudiéramos usar el serial para comunicación usb y el serial1 para comunicación con el 328p, pero la parte del 328p, habría que grabarla, o antes de grabar el 16u2 como leonardo, o directamente por ICSP.

Me alegro de que el tutorial sirva para algo.

Por cierto, interesante también el link que has puesto.

max_saeta

Carmeloco, ya cargue el firmware del Mega R3 al Mega R1, hasta ahora trabajando normalmente.

Aun asi para que entre en modo DFU hay que colocar el reset y hacer reset en el capacitor que señala el tutorial.

Aqui mi modificacion del codigo de Carmeloco.

Code: [Select]
/* Arduino USB Keyboard HID demo
*
* Sends Volume up, hello world, and Volume Down to the host PC
*
*/

uint8_t buf[8] = { 0 }; /* Keyboard report buffer */

void setup();
void loop();

#define KEY_LEFT_CTRL    0x01
#define KEY_LEFT_SHIFT   0x02
#define KEY_LEFT_OPTION  0x04
#define KEY_LEFT_COMMAND 0x08
#define KEY_RIGHT_CTRL   0x10
#define KEY_RIGHT_SHIFT  0x20
#define KEY_CTRL 0x01
#define KEY_SHIFT 0x02
#define KEY_ALT 0x04
#define KEY_GUI 0x08
#define KEY_LEFT_CTRL 0x01
#define KEY_LEFT_SHIFT 0x02
#define KEY_LEFT_ALT 0x04
#define KEY_LEFT_GUI 0x08
#define KEY_RIGHT_CTRL 0x10
#define KEY_RIGHT_SHIFT 0x20
#define KEY_RIGHT_ALT 0x40
#define KEY_RIGHT_GUI 0x80

#define KEY_ENTER 40

void setup() {
    Serial.begin(9600);
    delay(200);
}


char *str = "?+notepad{-Saludos Señores ya sabes que si se puede usar un Arduino UNO como teclado.{Gracias.\r\n";

void loop() {
    char *chp = str;
    delay(5000);
    while (*chp) {
  if ((*chp >= 'a') && (*chp <= 'z')) {
    buf[2] = *chp - 'a' + 4;
  } else if ((*chp >= 'A') && (*chp <= 'Z')) {
    buf[0] = KEY_LEFT_SHIFT; /* Caps */
    buf[2] = *chp - 'A' + 4;
  } else {
    switch (*chp) {
    case ' ':
      buf[2] = 0x2c; // Space
  break;
    case '+':
    buf[0] = KEY_LEFT_CTRL; /* Caps */
    buf[2] = 'E' - 'A' + 4;          
    break;
    case '-':
    delay(2500);          
    break;
    case '.':
    buf[0] = KEY_LEFT_CTRL; /* Caps */
    buf[2] = 'C' - 'A' + 4;          
    break;
    case '?':
    buf[0] = KEY_LEFT_COMMAND; /* Caps */
    buf[2] = 'R' - 'A' + 4;
    break;
    case '{':
    buf[2] = KEY_ENTER;          
    break;
    default:
        /* Character not handled. To do: add rest of chars from HUT1_11.pdf */
buf[2] = 0x37; // Period
break;
    }
  }
  Serial.write(buf, 8); // Send keypress
  buf[0] = 0;
  buf[2] = 0;
  Serial.write(buf, 8); // Release key
  chp++;

    }
}

carmeloco

Rebuscando un poco, he recordado que tengo un arduino uno, que no es ni original ni R3. Lo tenía medio olvidado, porque es para un proyecto que tengo a medio terminar.

El caso es que este arduino, lleva un chip, en el que lleva escrito mega8u2. Para ponerlo en modo DFU, hay que ponerle una resistencia de 10K así:



Sin esa resistencia, por muchos resets que le hagamos al chip, no entra en modo DFU.

Yo no se la he soldado. Lo que he hecho es sujetar una resistencia con los pines encima de los pads del arduino, con el pulgar, después se conecta el USB al arduino y luego se hace el reset, tal y como expliqué en el primer mensaje de este post. Esto no lo he conseguido a la primera, hace falta un poco de maña para hacer todo esto. Una vez hecho el reset, ya se puede soltar la resistencia.

El chip entra en modo DFU, pero sorpresa, el PC me lo detecta como AT90USB82 y no como ATmega8u2.

Pues bien, en flip, hay que seleccionar, en mi caso el AT90USB82, y en tu caso, el que te salga en el administrador de dispositivos de windows (en otros sistemas operativos, ni idea).

He cargado el .hex del Arduino UNO R3, y funciona perfectamente.

carmeloco

A raíz de un problema que ha tenido un usuario, que no podía poner el chip en modo DFU, he investigado la forma de grabar el firmware en el chip, usando un arduino como isp.

En este ejemplo, usamos un arduino uno como isp, para re-grabar el firmware en el 16u2 de un arduino mega.

Cargamos el código del arduino isp en el arduino uno.

Conectamos los arduinos así:



Nos creamos una carpeta en c: que se llame avrdude

Allí vamos a copiar varios archivos.

Copiamos el archivo avrdude.exe que está en C:\Program Files (x86)\Arduino\hardware\tools\avr\bin
Copiamos el archivo avrdude.conf que está en C:\Program Files (x86)\Arduino\hardware\tools\avr\etc

Copiamos el archivo Arduino-COMBINED-dfu-usbserial-atmega16u2-Mega2560-Rev3.hex que está en C:\Program Files (x86)\Arduino\hardware\arduino\avr\firmwares\atmegaxxu2

Estos archivos, los saco del IDE 1.6.1 de arduino. No se si funciona con otra versión. Con esta, puedo certificar que funciona.

Bien, con estas tres cosas copiadas, abrimos una consola de DOS, ponemos

Code: [Select]
cd c:\avrdude

y después, con el arduino uno conectado por usb al ordenador, ponemos el siguiente comando, cambiando el com3 por el puerto com en el que nos detecte el arduino el pc.:

Code: [Select]
avrdude -p m16u2 -F -P com3 -b19200 -c arduino -U flash:w:Arduino-COMBINED-dfu-usbserial-atmega16u2-Mega2560-Rev3.hex -U lfuse:w:0xFF:m -U hfuse:w:0xD9:m -U efuse:w:0xF4:m -U lock:w:0x0F:m

Con esto saldrán una serie de cosas por la pantalla de DOS, y acabará diciendo un "avrdude done.  Thank you."

Con esto, tedríamos que tener el AtMega 16u2 regrabado como de serie.

Usamos el firmware "COMBINED" para que el chip tenga la funcionalidad de poderlo poner en modo DFU. Si usamos el que usamos normalmente con el software Atmel Flip, perdemos esa capacidad, ya que no estamos grabando en modo DFU, si no que estamos grabando directamente al chip.

carmeloco

Un usuario, me envió este mensaje privado hace unos días:

Hola, estoy mirando tu post sobre cambiar el firmware del arduino UNO para usarlo como teclado, y he querido modificar el codigo pero mis conocimientos son limitados :smiley-cry: ... El caso es que no se como haces el Ctrl y como podria hacer la tecla Windows, si me puedes explicar como te lo agradeceria muchisimo  :)  :)  :) 
Le respondí, que no es correcto pedir ayuda por mensaje privado, y que mejor que pusiese su consulta, directamente en este post. Como veo que no lo hace, pero veo interesante la consulta, pongo la respuesta a continuación:

Los códigos de teclas especiales, los podemos encontrar en la documentación que hay en www.usb.org. Allí tenemos un manual llamado "HID Usage Tables"

HID Usage Tables 1.12

En la página 59, encontramos los códigos para las teclas CTRL.

224 para "Left Control" y 228 para "Right Control"

En la página 56, está el código parala tecla Windows, que es el 101. Dice que es para windows 95. No se si funcionará con el resto de versiones.

Go Up