String numeric output with V-USB HID

This discussion centers on code by:
http://www.obdev.at/products/vusb/license.html
http://code.rancidbacon.com/ProjectLogArduinoUSB
www.avdweb.nl/arduino/hardware-interfacing/temperature-measurement.html
et al.
ARDUINO 1.0.1

I have built many V-USB toys using the ATtiny85. They all work, they are all fun projects, but they do require that you drop down to C code and use the command line to compile, link, and flash the '85. Rancid Bacon's V-USB library for Arduino Google Code Archive - Long-term storage for Google Code Project Hosting. provides a great enhancement and is easy to utilize, especially the samples he provides.

However, as a HID keyboard emulator, it is awkward to send data to the PC on a keystroke by keystroke method. As an example of this difficulty, I took on the task of reading the internal temperature of the ATmega328P-PU on the UNO from the code library by Albert van Dalen (AvdWeb link above.) I pondered the issues for a while and considered two generalized methods; character array or Strings.

The code below needs to be polished, but works. The hardware required is minimal, two zener diodes, and three resistors. Please see refer to Rancid Bacon's site for the hardware build. I built mine on a UNO prototype shield from Adafruit. The nice thing about this is that you can run both the Arduino GUI and the USB HID port simultaneously. (Just do not connect +5 on the port being used for HID... ground, D+ and D- are all that is needed and reference the +5 back to the UNO main board.)
PLEASE NOTE that my ChipTemp.h file is local for quick changes, not in my user library.

I used a pushbutton on pin 10 so that the program would not start spooling characters across HID after I programmed the UNO and before I could change focus to Notepad with my mouse! Program the UNO, open Notepad and/or click in Notepad to set focus, then press the button on pin 10 to start the program. I cannot attest to the accuracy of the temperature, but I did one test where the UNO was off for an hour and then powered on. The UNO started with a reading near room temperature and the indication was that the temperature climbed higher, 6F degrees total, over a period of about 5 minutes. This leads me to believe that the temperature diode is monitoring the internal temperature.

I had to "mess around" with the ChipTemp.h file and change the calibration values before I could get a decent room temperature. Using a different 'known good' 386P chip on a breadboard resulted in a large change in the calibration value. Your results may vary.

Obviously you can use any temperature sensor and simply change the assignment in the line
sOut.concat(String(chipTemp.fahrenheit()));

The String object is very versatile in Arduino, so have a look at the Reference page
http://arduino.cc/en/Reference/StringObject Have a look at the UsbKeyboard.h file for all of the defined key combinations... this will allow you to build alphanumeric strings for output.

Have fun.

Update:
Here is the same with alphanumeric output:

// MRB 20121201 Tested using String Object
// UNO Profile: Binary sketch size: 7,694 bytes (of a 32,256 byte maximum)

#include "UsbKeyboard.h"
#include <avr/pgmspace.h>
#include "./ChipTemp.h"

#define BUTTON_PIN 10

ChipTemp chipTemp;

String sOut;

void delayMs(unsigned int ms) {    // Safe delay
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}


void setup() {
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH);
  TIMSK0&=!(1<<TOIE0);            // disable timer 0 overflow interrupt (used for millis)
  while (digitalRead(BUTTON_PIN) != 0){
      UsbKeyboard.update();
      delayMs(20); 
  }
}


void loop() {
    digitalWrite(13, !digitalRead(13));    // flash LED
    UsbKeyboard.update();
    sOut = "INTERNAL CHIP TEMP = ";
    sOut.concat(String(chipTemp.fahrenheit()));  // chipTemp.celsius() | chipTemp.deciCelsius()  | chipTemp.fahrenheit() | chipTemp.deciFahrenheit()
    KeyStrokeAlpNum(sOut);
    delayMs(20);    // Interrupt safe since V-USB utilizes interrupt
}


void KeyStrokeAlpNum(String Sc){
    int sPoint = Sc.length();          // Pointer to end-of-String (inc. null)
    for (int x = 0; x < sPoint; x++){
      int y = x + 1;
      if (Sc.substring(x, y) == "A"){  // substring single character: y = x+1
          UsbKeyboard.sendKeyStroke(KEY_A, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "B"){
          UsbKeyboard.sendKeyStroke(KEY_B, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "C"){
          UsbKeyboard.sendKeyStroke(KEY_C, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "D"){
          UsbKeyboard.sendKeyStroke(KEY_D, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "E"){
          UsbKeyboard.sendKeyStroke(KEY_E, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "F"){
          UsbKeyboard.sendKeyStroke(KEY_F, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "G"){
          UsbKeyboard.sendKeyStroke(KEY_G, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "H"){
          UsbKeyboard.sendKeyStroke(KEY_H, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "I"){
          UsbKeyboard.sendKeyStroke(KEY_I, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "J"){
          UsbKeyboard.sendKeyStroke(KEY_J, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "K"){
          UsbKeyboard.sendKeyStroke(KEY_K, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "L"){
          UsbKeyboard.sendKeyStroke(KEY_L, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "M"){
          UsbKeyboard.sendKeyStroke(KEY_M, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "N"){
          UsbKeyboard.sendKeyStroke(KEY_N, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "O"){
          UsbKeyboard.sendKeyStroke(KEY_O, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "P"){
          UsbKeyboard.sendKeyStroke(KEY_P, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Q"){
          UsbKeyboard.sendKeyStroke(KEY_Q, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "R"){
          UsbKeyboard.sendKeyStroke(KEY_R, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "S"){
          UsbKeyboard.sendKeyStroke(KEY_S, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "T"){
          UsbKeyboard.sendKeyStroke(KEY_T, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "U"){
          UsbKeyboard.sendKeyStroke(KEY_U, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "V"){
          UsbKeyboard.sendKeyStroke(KEY_V, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "W"){
          UsbKeyboard.sendKeyStroke(KEY_W, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "X"){
          UsbKeyboard.sendKeyStroke(KEY_X, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Y"){
          UsbKeyboard.sendKeyStroke(KEY_Y, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Z"){
          UsbKeyboard.sendKeyStroke(KEY_Z, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == " "){
          UsbKeyboard.sendKeyStroke(KEY_SPACE);
          }
       else if (Sc.substring(x, y) == "1"){
          UsbKeyboard.sendKeyStroke(KEY_1);
          }
       else if (Sc.substring(x, y) == "2"){
          UsbKeyboard.sendKeyStroke(KEY_2);
          }
       else if (Sc.substring(x, y) == "3"){
          UsbKeyboard.sendKeyStroke(KEY_3);
          }
       else if (Sc.substring(x, y) == "4"){
          UsbKeyboard.sendKeyStroke(KEY_4);
          }
       else if (Sc.substring(x, y) == "5"){
          UsbKeyboard.sendKeyStroke(KEY_5);
          }
       else if (Sc.substring(x, y) == "6"){
          UsbKeyboard.sendKeyStroke(KEY_6);
          }
       else if (Sc.substring(x, y) == "7"){
          UsbKeyboard.sendKeyStroke(KEY_7);
          }
       else if (Sc.substring(x, y) == "8"){
          UsbKeyboard.sendKeyStroke(KEY_8);
          }
       else if (Sc.substring(x, y) == "9"){
          UsbKeyboard.sendKeyStroke(KEY_9);
          }
       else if (Sc.substring(x, y) == "0"){
          UsbKeyboard.sendKeyStroke(KEY_0);
          }
      }
      UsbKeyboard.sendKeyStroke(KEY_ENTER);
      // Return
}

Notepad display:

INTERNAL CHIP TEMP 78
INTERNAL CHIP TEMP 78
INTERNAL CHIP TEMP 78
INTERNAL CHIP TEMP 78
INTERNAL CHIP TEMP 78
INTERNAL CHIP TEMP 78

Note: The "=" does not display because I have not mapped this keystroke! The pix shows the simplicity of the USB interface... I have both USB ports active during development (but only 1 active +5V source.)

More pixs
A UNO stick made with the rancidbacon reference circuit. The USB-Serial converter is fitted to the board for programming via the Arduino GUI and then removed. Alternately, the uC could be removed and flashed with any ISP burner (generally overwrites bootloader, however.)

The strip of protoboard was from Radio Shack... old stock: 910-3804 DIP-Small
The USB-serial adapter is from eBay. I have cut the 3.3V line and the Reset line (not an Arduino reset.) One adapter can be used with many sticks... no reason to throw $2.20 U.S. to the wind to dedicate a serial-USB since the HID connector will provide for serial output. Yes, you could run both USB ports simultaneously (but only use HID +5 and do not connect the CP21xx +5... only Ground reference, Tx, and Rx. Such a configuration could be used to use the Com-USB port for eeprom configuration, customization menu, sensor offsets, one-time keyboard input, etc. and all the pertinent user output could come over HID. Or, the Com serial could be used for diagnostics, etc.

The key takeaway is that USB-Com requires an INF and driver for Windows but HID keyboard is accepted without user driver installation... the OS will load native drivers automatically under Windows, Linux, iOS... even some tablets with USB support.

I did cover the bottom of the hand-soldering of parts with HFT quick setting epoxy to allow the stick to be handled without fear of being overly gentle.

  • Ray

HID keyboard appears just as any USB keyboard, so therefore it can be copied to a text file in a command window! This is pretty cool, since the command: COPY CON filename.txt will start the process. You must terminate the file recording with a Ctrl Z... either from the HID keyboard or the primary keyboard.

Such may be desirable when the accepting program has limitations on the input data, either size or timeouts. The data can be written to a file, a utility used to break the file into manageable pieces, etc. Also, this technique would be appropriate for re-purposing an OLD PC with low RAM capabilities (WinXP with no other applications running) ... since the file size is roughly the character size of input, the buffering could go on for a very long time if backup power was provided.

I have not tried it, but I understand that there are DOS drivers for USB-HID available... so perhaps even Windows would not be required. Also, some newer BIOS will process BOOT HID, but I have not tried this either. I do not even know if I have a copy of DOS to try... maybe an old Windows 98SE? Test for future.

  • Ray

Example of reading all 6 of the default analog (port C0 - C5) values:
(Still uses pushbutton on PIN 10 to start the process to give me time to setup the notepad focus in Windows)

Updated to show use of for() loop construct:

// 20121208 Runs on UNO-clone strip board
// UNO Profile: Binary sketch size: 7,486 bytes (of a 32,256 byte maximum)

#include "UsbKeyboard.h"
#include <avr/pgmspace.h>

#define BUTTON_PIN 10

//const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)

String sOut;

void delayMs(unsigned int ms) {    // Safe delay helper function
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}


void setup() {
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH);
  // Disable timer0 since it can mess with the USB timing. Note that
  // this means some functions such as delay() will no longer work.
  TIMSK0&=!(1<<TOIE0);
  // Clear interrupts while performing time-critical operations
  cli();
  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();

  while (digitalRead(BUTTON_PIN) != 0){
      UsbKeyboard.update();
      delayMs(20); 
  }


}


void loop() {
    digitalWrite(13, !digitalRead(13));    // flash LED
    UsbKeyboard.update();
    
    for (int i = 0; i < 6; i++){
      // read the analog in value:
      sensorValue = analogRead( i );
      // Label the value
      sOut = "ANALOG";
      // String the characters together
      sOut.concat(String(i));
      sOut.concat(" ");
      sOut.concat(String(sensorValue));
      // spool the combined strings
      KeyStrokeAlpNum(sOut);
      UsbKeyboard.sendKeyStroke(KEY_ENTER);
    }
      UsbKeyboard.sendKeyStroke(KEY_ENTER);
    delayMs(5000);    // Interrupt safe since V-USB utilizes interrupt
}


void KeyStrokeAlpNum(String Sc){
    int sPoint = Sc.length();          // Pointer to end-of-String (inc. null)
    for (int x = 0; x < sPoint; x++){
      int y = x + 1;
      if (Sc.substring(x, y) == "A"){  // substring single character: y = x+1
          UsbKeyboard.sendKeyStroke(KEY_A, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "B"){
          UsbKeyboard.sendKeyStroke(KEY_B, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "C"){
          UsbKeyboard.sendKeyStroke(KEY_C, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "D"){
          UsbKeyboard.sendKeyStroke(KEY_D, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "E"){
          UsbKeyboard.sendKeyStroke(KEY_E, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "F"){
          UsbKeyboard.sendKeyStroke(KEY_F, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "G"){
          UsbKeyboard.sendKeyStroke(KEY_G, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "H"){
          UsbKeyboard.sendKeyStroke(KEY_H, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "I"){
          UsbKeyboard.sendKeyStroke(KEY_I, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "J"){
          UsbKeyboard.sendKeyStroke(KEY_J, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "K"){
          UsbKeyboard.sendKeyStroke(KEY_K, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "L"){
          UsbKeyboard.sendKeyStroke(KEY_L, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "M"){
          UsbKeyboard.sendKeyStroke(KEY_M, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "N"){
          UsbKeyboard.sendKeyStroke(KEY_N, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "O"){
          UsbKeyboard.sendKeyStroke(KEY_O, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "P"){
          UsbKeyboard.sendKeyStroke(KEY_P, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Q"){
          UsbKeyboard.sendKeyStroke(KEY_Q, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "R"){
          UsbKeyboard.sendKeyStroke(KEY_R, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "S"){
          UsbKeyboard.sendKeyStroke(KEY_S, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "T"){
          UsbKeyboard.sendKeyStroke(KEY_T, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "U"){
          UsbKeyboard.sendKeyStroke(KEY_U, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "V"){
          UsbKeyboard.sendKeyStroke(KEY_V, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "W"){
          UsbKeyboard.sendKeyStroke(KEY_W, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "X"){
          UsbKeyboard.sendKeyStroke(KEY_X, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Y"){
          UsbKeyboard.sendKeyStroke(KEY_Y, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Z"){
          UsbKeyboard.sendKeyStroke(KEY_Z, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == " "){
          UsbKeyboard.sendKeyStroke(KEY_SPACE);
          }
       else if (Sc.substring(x, y) == "1"){
          UsbKeyboard.sendKeyStroke(KEY_1);
          }
       else if (Sc.substring(x, y) == "2"){
          UsbKeyboard.sendKeyStroke(KEY_2);
          }
       else if (Sc.substring(x, y) == "3"){
          UsbKeyboard.sendKeyStroke(KEY_3);
          }
       else if (Sc.substring(x, y) == "4"){
          UsbKeyboard.sendKeyStroke(KEY_4);
          }
       else if (Sc.substring(x, y) == "5"){
          UsbKeyboard.sendKeyStroke(KEY_5);
          }
       else if (Sc.substring(x, y) == "6"){
          UsbKeyboard.sendKeyStroke(KEY_6);
          }
       else if (Sc.substring(x, y) == "7"){
          UsbKeyboard.sendKeyStroke(KEY_7);
          }
       else if (Sc.substring(x, y) == "8"){
          UsbKeyboard.sendKeyStroke(KEY_8);
          }
       else if (Sc.substring(x, y) == "9"){
          UsbKeyboard.sendKeyStroke(KEY_9);
          }
       else if (Sc.substring(x, y) == "0"){
          UsbKeyboard.sendKeyStroke(KEY_0);
          }
      }
      UsbKeyboard.sendKeyStroke(KEY_ENTER);
      // Return
}

Example of the resulting output in notepad:
(I walked each analog pin with a 10K resistor to ground... other pins were floating.)

ANALOG0 0
ANALOG1 120
ANALOG2 220
ANALOG3 265
ANALOG4 294
ANALOG5 294

ANALOG0 296
ANALOG1 0
ANALOG2 109
ANALOG3 213
ANALOG4 268
ANALOG5 282

ANALOG0 313
ANALOG1 315
ANALOG2 0
ANALOG3 120
ANALOG4 217
ANALOG5 261

ANALOG0 312
ANALOG1 332
ANALOG2 313
ANALOG3 0
ANALOG4 128
ANALOG5 216

ANALOG0 290
ANALOG1 322
ANALOG2 320
ANALOG3 312
ANALOG4 0
ANALOG5 120

ANALOG0 120
ANALOG1 234
ANALOG2 272
ANALOG3 297
ANALOG4 282
ANALOG5 0

Again, the wonderful VUSB library can be leveraged for a very inexpensive uC to PC interface using HID which can directly feed an Excel spreadsheet, sample attached.

The (often seen) push button on pin 10 has been removed and the code edited to wait 10 seconds after the HID device is recognized before sending characters.

ANALOG0 426
ANALOG1 401
ANALOG2 378
ANALOG3 373
ANALOG4 362
ANALOG5 445
DIGITAL 3L 6L 7L 8H 9H 10H 11H 12H

// 20121210 Runs on UNO-clone strip board using 328P-PU
// UNO Profile: Binary sketch size: 8,260 bytes (of a 32,256 byte maximum)
// When freeram function is uncommented: FREE RAM 1506

#include "UsbKeyboard.h"
#include <avr/pgmspace.h>

// #define BUTTON_PIN 10

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)

String sOut;

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

void delayMs(unsigned int ms) {    // Safe delay helper function
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}


void setup() {
  // pinMode(BUTTON_PIN, INPUT);
  // digitalWrite(BUTTON_PIN, HIGH);

  // Disable timer0 since it can mess with the USB timing. Note that
  // this means some functions such as delay() will no longer work.
  TIMSK0&=!(1<<TOIE0);
  // Clear interrupts while performing time-critical operations
  cli();
  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();

  pinMode(3, INPUT);      //  sets the digital pin 3 as input
  pinMode(6, INPUT);      //  sets the digital pin 6 as input
  pinMode(7, INPUT);      //  sets the digital pin 7 as input
  pinMode(8, INPUT);      //  sets the digital pin 8 as input
  pinMode(9, INPUT);      //  sets the digital pin 9 as input
  pinMode(10, INPUT);      // sets the digital pin 10 as input
  pinMode(11, INPUT);      // sets the digital pin 11 as input
  pinMode(12, INPUT);      // sets the digital pin 12 as input

  for (int i = 0; i < 500; i++){            // 10 second delay in lieu of using Button press on pin 10
    digitalWrite(13, !digitalRead(13));
    // while (digitalRead(BUTTON_PIN) != 0)
     UsbKeyboard.update();
     delayMs(20);
   }

  // Tell them who we are...
  sOut = "SIMPLE HID DATA LOGGER USING VUSB WWW.OBDEV.AT";
  KeyStrokeAlpNum(sOut);
  sOut = "ARDUINO PORT BY RANCIDBACON.COM";
  KeyStrokeAlpNum(sOut);
  sOut = "UNO 328P EXAMPLE - RAY BURNETTE C20121210";
  KeyStrokeAlpNum(sOut);
  UsbKeyboard.sendKeyStroke(KEY_ENTER);
  UsbKeyboard.sendKeyStroke(KEY_ENTER); 
}


void loop() {
    digitalWrite(13, !digitalRead(13));    // flash LED
    UsbKeyboard.update();
    
    for (int i = 0; i < 6; i++){
      // read the analog in value:
      sensorValue = analogRead( i );
      // Label the value
      sOut = "ANALOG";
      // String the characters together
      sOut.concat(String(i));
      sOut.concat(" ");
      sOut.concat(String(sensorValue));
      // spool the combined strings
      KeyStrokeAlpNum(sOut);
    }

    sOut = "DIGITAL ";
    if (digitalRead(3) == HIGH){
      sOut.concat("3H ");
    } else {
        sOut.concat("3L ");
    }
    
    if (digitalRead(6) == HIGH){
      sOut.concat("6H ");
    } else {
        sOut.concat("6L ");
    }
    if (digitalRead(7) == HIGH){
      sOut.concat("7H ");
    } else {
        sOut.concat("7L ");
    }
    if (digitalRead(8) == HIGH){
      sOut.concat("8H ");
    } else {
        sOut.concat("8L ");
    }
    if (digitalRead(9) == HIGH){
      sOut.concat("9H ");
    } else {
        sOut.concat("9L ");
    }
    if (digitalRead(10) == HIGH){
      sOut.concat("10H ");
    } else {
        sOut.concat("10L ");
    }
    if (digitalRead(11) == HIGH){
      sOut.concat("11H ");
    } else {
        sOut.concat("11L ");
    }
    if (digitalRead(12) == HIGH){
      sOut.concat("12H");
    } else {
        sOut.concat("12L");
    }

    KeyStrokeAlpNum(sOut);
    UsbKeyboard.sendKeyStroke(KEY_ENTER);
    // sOut = "FREE RAM ";              // Uncomment next 4 lines to check for memory leaks
    // sOut.concat(String(freeRam()));
    // KeyStrokeAlpNum(sOut);
    // UsbKeyboard.sendKeyStroke(KEY_ENTER);
    delayMs(5000);    // Interrupt safe since V-USB utilizes interrupt
}


void KeyStrokeAlpNum(String Sc){
    int sPoint = Sc.length();          // Pointer to end-of-String (inc. null)
    for (int x = 0; x < sPoint; x++){
      int y = x + 1;
      if (Sc.substring(x, y) == "H"){  // substring single character: y = x+1
          UsbKeyboard.sendKeyStroke(KEY_H, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "L"){
          UsbKeyboard.sendKeyStroke(KEY_L, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == " "){
          UsbKeyboard.sendKeyStroke(KEY_SPACE);
          }
       else if (Sc.substring(x, y) == "1"){
          UsbKeyboard.sendKeyStroke(KEY_1);
          }
       else if (Sc.substring(x, y) == "2"){
          UsbKeyboard.sendKeyStroke(KEY_2);
          }
       else if (Sc.substring(x, y) == "3"){
          UsbKeyboard.sendKeyStroke(KEY_3);
          }
       else if (Sc.substring(x, y) == "4"){
          UsbKeyboard.sendKeyStroke(KEY_4);
          }
       else if (Sc.substring(x, y) == "5"){
          UsbKeyboard.sendKeyStroke(KEY_5);
          }
       else if (Sc.substring(x, y) == "6"){
          UsbKeyboard.sendKeyStroke(KEY_6);
          }
       else if (Sc.substring(x, y) == "7"){
          UsbKeyboard.sendKeyStroke(KEY_7);
          }
       else if (Sc.substring(x, y) == "8"){
          UsbKeyboard.sendKeyStroke(KEY_8);
          }
       else if (Sc.substring(x, y) == "9"){
          UsbKeyboard.sendKeyStroke(KEY_9);
          }
       else if (Sc.substring(x, y) == "0"){
          UsbKeyboard.sendKeyStroke(KEY_0);
          }
       else if (Sc.substring(x, y) == "."){
          UsbKeyboard.sendKeyStroke(55);
          }
       else if (Sc.substring(x, y) == "-"){
          UsbKeyboard.sendKeyStroke(45);
          }
       else if (Sc.substring(x, y) == "A"){
          UsbKeyboard.sendKeyStroke(KEY_A, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "B"){
          UsbKeyboard.sendKeyStroke(KEY_B, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "C"){
          UsbKeyboard.sendKeyStroke(KEY_C, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "D"){
          UsbKeyboard.sendKeyStroke(KEY_D, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "E"){
          UsbKeyboard.sendKeyStroke(KEY_E, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "F"){
          UsbKeyboard.sendKeyStroke(KEY_F, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "G"){
          UsbKeyboard.sendKeyStroke(KEY_G, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "I"){
          UsbKeyboard.sendKeyStroke(KEY_I, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "J"){
          UsbKeyboard.sendKeyStroke(KEY_J, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "K"){
          UsbKeyboard.sendKeyStroke(KEY_K, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "M"){
          UsbKeyboard.sendKeyStroke(KEY_M, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "N"){
          UsbKeyboard.sendKeyStroke(KEY_N, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "O"){
          UsbKeyboard.sendKeyStroke(KEY_O, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "P"){
          UsbKeyboard.sendKeyStroke(KEY_P, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Q"){
          UsbKeyboard.sendKeyStroke(KEY_Q, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "R"){
          UsbKeyboard.sendKeyStroke(KEY_R, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "S"){
          UsbKeyboard.sendKeyStroke(KEY_S, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "T"){
          UsbKeyboard.sendKeyStroke(KEY_T, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "U"){
          UsbKeyboard.sendKeyStroke(KEY_U, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "V"){
          UsbKeyboard.sendKeyStroke(KEY_V, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "W"){
          UsbKeyboard.sendKeyStroke(KEY_W, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "X"){
          UsbKeyboard.sendKeyStroke(KEY_X, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Y"){
          UsbKeyboard.sendKeyStroke(KEY_Y, MOD_SHIFT_LEFT);
          }
       else if (Sc.substring(x, y) == "Z"){
          UsbKeyboard.sendKeyStroke(KEY_Z, MOD_SHIFT_LEFT);
          }
      }
      UsbKeyboard.sendKeyStroke(KEY_ENTER);
      // Return
}
  • Have fun, Ray

FIS3CNOHANAZZB1.zip (3.59 KB)

USB_HID_AnalogX6_D8.zip (2.24 KB)

Note:

Only a subset of keyboard codes were defined by Rancidbacon in his .H file.
If you need to add a value not in the include file list, please refer to:
http://www.usb.org/developers/devclass_docs/Hut1_11.pdf
Section 10, Table 12 : Keyboard/Keypad Page

Hi Ray,

Thanks for answering me on Hackster.io.

I'm a little basic in Arduino code so not all things are clear to me.

What have I done:
-I build the circuit as shown on hackster and other sites with connections at D2, D4, D5, Vcc and Gnd.
-I connect a pot to analog A0
-I uploaded the sketch to my arduino UNO.
-I disconnected my UNO from pc, and give it external Vcc.
-I connected the circuit with the USB connector
-And looks in Excel, and wait, and wait, but nothing happens...

When I connect the selfmade usb connector, my pc gives the message that there are no drivers found for this device. Also the sound you hear by connecting gives three low beeps.

If the steps as shown above are right, I have to check my circuit.

Also I have this questions:

  • We will try to use this for measurement up to 2 analog ports. Nothing else. Can I delete all unnecessarry code, p.e. all keystrokes?
  • What do you think about the velocity of this realtime connection? Measuring 50Hz lightflashing, or a 440Hz sound?

Thanks for help so far.
I hope it is useful to us. The PLX-DAQ macro for Excel is realy good too, but the disadvantage is that you have first to install the macro on your system before you can work with it.

Gr.
Johan

Johan,

Welcome!

When I connect the selfmade usb connector, my pc gives the message that there are no drivers found for this device. Also the sound you hear by connecting gives three low beeps.

When the code is working as it should, plugging the completed unit into any PC (Win, Mac, Linux) will cause the enumeration of the device as HID... a virtual keyboard, so no drivers should be needed for Windows or MacOS and I think Linux in recent versions support HID from the kernel. So, the fact that it wants a driver is a sign that it is not working (right.) Did you use the specific zener diode referenced? This is the most critical component in the V-USB design and if the capacitance is too high, the waveform will not be recognized by the PC as a USB device. That is why the zener is a low-wattage.

Have you read RancidBacon's design notes? These things can be tedious.
http://code.rancidbacon.com/ProjectLogArduinoUSB

Using the parts I recommended, which I ordered by the 100 from Newark, everything works everytime for me. I have used it on Nano, Uno, boarduino, and ProMini. I have also used the exact same zener and resistors to clone a Trinket and a Digispark.

My recommendation is to start from the beginning. Use a Uno and the code for the internal temperature in the first article. Hopefully, this will get you going so that you can evolve.

Also I have this questions:

  • We will try to use this for measurement up to 2 analog ports. Nothing else. Can I delete all unnecessarry code, p.e. all keystrokes?
  • What do you think about the velocity of this realtime connection? Measuring 50Hz lightflashing, or a 440Hz sound?
  1. You cannot delete the keystrokes since that is what simulates the HID keyboard. But yes, you can do 1 or more analog ports... in one of the above posts, I do 6.

  2. 9600 BAUD is 960 characters per second. Whether you can encode useful information into that stream from you sensors is an exercise for the test bed. I have no basis to respond with a specific answer.

Ray

Thanks Ray,
I will check my circuit first.
The components comes from Farnell. As far as I know the same kind of shop than Newark. (element 14).

But I set it up right?
-UNO connect to pc - upload sketch - UNO disconnect - connect usb-circuit - open excel?
Otherwise you have two usb-ports in use. So to who should Excel listen?

I will keep you informed.

Gr.
Johan

Johan,

As soon as the sketch uploads, the Arduino reboots and the Arduino USB port keeps the same serial port. The V-USB port is completely separate and can be plugged into the PC at the same time as the Arduino port is active as virtual com. The V-USB side will take on the personality of HID keyboard. If you use two USB ports simultaneously, only one (the Arduino) must power the Uno.

-UNO connect to pc - upload sketch - UNO disconnect - connect usb-circuit - open excel?

  • Program the UNO on factory USB
  • Unplug the UNO
  • Open Excel, load the template, position cursor into A1
  • Plug in the V-USB port noting that power now comes over this connection!
  • After about 10-15 seconds, the Uno will start sending keystrokes to Excel

I usually use ArduinoISP and load the sketch that way because I am working with perfboard designs and it is silly to waste a USB connector for a port that would only be used to program. But for bench testing, etc., you can use two ports... but the PC will see them as two different devices.

Where this differs from the Leonardo, is that the 32U4 is connected to only one USB port and that port can be Comm or that port can be HID, but not both at the same time. Uno can be both since it uses a separate Atmel chip for the serial comms.

Ray

Added:
Excel does not have a clue! As far as Excel is concerned, the keystrokes come from a keyboard and the software cannot determine if there is one or more keyboards connected; all it 'sees' is just keystrokes.

I build the circuit over-and-over, but Zener U$S2 (connected with r2/3) becomes very hot and windows still said that he couldn't find the right drivers for this device.

I bought the 1N5227B. In your article you speak about the 1N5227B-TAP. See comparision:

http://nl.farnell.com/jsp/search/productcompare.jsp?N=0&Ntk=gensearch&Ntt=1N5227B&Ntx=mode+matchallpartial&exposeLevel2Refinement=true&suggestions=false&ref=globalsearch&_requestid=99111

Whats the difference between them?

J.

suffixes on small parts refer to some specification in the data sheet... Temperature, case type, lead materials, etc. Either should work.

If the zeners are hot, you have miswired something! Disconnect, and recheck. Go back to rancidbacon's article and double-check.
http://code.rancidbacon.com/ProjectLogArduinoUSB

Check out these working projects:
http://www.obdev.at/products/vusb/prjobdev.html

Please, if you are not an advanced experimenter that understands electronics, you should not attempt mucking around with your PC USB... YOU CAN DAMAGE THE PORT.

Ray

PS: drivers are HID and are part of every Windows base package.

Works!
The circuit was wrong.
In the usb-connector I used, the sequence of D+, D- etc. was different of the circuit at hackster.io.
I expected that the sequence at the picture was the same of at a real usb-connector. But it was not... :frowning:

I'm happy to play with it.
Thanks for supporting me.

Gr.
Johan

I'm happy to play with it.
Thanks for supporting me.

@jmnijsse:
GREAT, glad it all works.

Ray

Another question:

How is it possible to use the millis() function, because of timer0 is disabled?
Is millis() switchable at different timers?

Johan

How is it possible to use the millis() function, because of timer0 is disabled?

We write our own:

void delayMs(unsigned int ms) {    // Safe delay helper function
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}

Ray

PS: I have not gotten this rolled into the forum yet, but it is way cool.... HID bidirectional and it does not enumerate as a HID keyboard... the downside is that you do have to install the avrisp INF under Windows.
http://www.hackster.io/rayburne/analog-digital-port-viewer-usb

Oke, this is an delay-function.
But I want to write the time in excel since beginning of the program.
So we can draw such as a time-temperature chart.

Or I don't understand it well?

Thanks for hint, but the installation of a driver is just what we don't want.

J.

But I want to write the time in excel since beginning of the program.

Take a look at how to send a string over USB:

sOut = "UNO 328P EXAMPLE - RAY BURNETTE C20121210";
KeyStrokeAlpNum(sOut);

If you have implemented RTC hardware, it is simply a matter of updating the variables from the RTC, concatenating date/time into a string, and using KeyStrokeAlpNum(sTimeDate) to send it over USB into Excel.

The Excel worksheet will require editing because you will be adding additional information.

You can also write an Excel macro (or VBA) with a keyboard shortcut so that the Excel document will time-date stamp, then you simply send the keyboard codes for that macro over the V-USB connection and Excel will oblige. Looking at the existing output, there is currently a blank line being sent so you could put your time/date stamp in the blank cell (Ex: A5, A13, A21, etc.)

If you want to just send the millisecond count from the time the Arduino was last Reset/PoweredOn, then the magic for doing that is similar to:

    for (int i = 0; i < 6; i++){
      // read the analog in value:
      sensorValue = analogRead( i );
      // Label the value
      sOut = "ANALOG";
      // String the characters together
      sOut.concat(String(i));
      sOut.concat(" ");
      sOut.concat(String(sensorValue));
      // spool the combined strings
      KeyStrokeAlpNum(sOut);
    }

Ray