The Caffeine Button

In a couple of previous posts (here and here) I've shown how easy and cheap it is to go from a prototyped setup using an Arduino to a standalone circuit built from just a handful of components. While those posts were more of an academic exercise to prove it was possible I've also now built, and blogged about, such a circuit that I'm actually using in anger. The problem is that an actual Arduino isn't just an Atmel ATMega328P-PU it also has accompanying electronics which enable you to talk to a computer via the USB connection which is great both for debugging and for interfacing external hardware to a PC.

When you connect an Arduino to a PC what actually happens is that the supporting circuitry creates a USB CDC ACM device which emulates a good old fashioned RS-232 serial port. If I wanted to add similar functionality to my standalone circuits then the most common way of doing so would be to use an FT232RL, but the chip alone would almost double the cost of the circuit plus it is only available as a surface mount part making it difficult to experiment with on a breadboard and I'm not sure my soldering skills are good enough to deal with surface mount parts either.

After pondering this for a bit and doing a little research I came across a potential solution in the form of V-USB. V-USB is a software only implementation of low speed USB for Atmel microcontrollers, such as the ATMega328P-PU. Unfortunately the distribution doesn't directly support the Arduino (it supports the ATMega328P-PU but not through the Arduino IDE etc.), however, I did find a previous attempt to add Arduino support although this project seems to have been abandoned as it hasn't seen any updates in over three years. It did, however, give me a good point to start from.

So far I haven't managed to emulate a serial port, but I have managed to make the Arduino behave like a USB keyboard which means that I can use it for debugging by having it pretend to press lots of keys in sequence, which is better than nothing. Before we get to looking at how to make use of V-USB we need to wire a USB plug up to the Arduino.

USB Connection Parts List
PartUnit CostQuantity
USB Socket, Type B£0.501
3.6V, 0.5W Zener Diode£0.0712
68Ω Resistor£0.0082
2.2kΩ Resistor£0.0081
As you can see it isn't a particularly complex circuit to build. Essentially we have the two data lines D- and D+ linked to pins 2 and 4 of the Arduino and as the USB spec states that these run on 3.3V we restrict the voltage using two 3.6V zener diodes to step down from the 5V output of the Arduino. The Arduino itself is powered from the other two USB pins which provide 5V/GND (this also means that you could use USB to power a standalone ATMega328P-PU without needing a voltage regulator and smoothing capacitors). The final connection is between pin 5 and D- via a 2.2kΩ pull-up resistor which allows the connection to be connected/disconnected from within software (in theory you can link this to V+ instead if you don't need this flexibility but I found that this meant that the hardware wasn't always recognized correctly when it was connected to a PC). For the USB plug itself, I opted to use a Type B plug (the same as the Arduino) so that I could get away with a single cable snaking across my desk, but you should be able to use any USB plug with the same circuit. One thing to be careful with when constructing the circuit is that in most cases the metal case of the USB plug is connected to the ground pin, so be careful that you don't end up with any of the other connections catching the case otherwise you might end up with them pulled to ground which will cause weird things to happen; depending which pin is involved either your PC won't recognize you have anything plugged in or it might end up thinking you have a high speed or high power device connected and things won't work properly.

Now we have the hardware what we need is some working software we can upload to the Arduino. As I said above I'm using a previous attempt to get this working as my starting point. This code hasn't been updated for over three years and I'm guessing that a number of things have changed within the Arduino libraries since then as the code didn't just work. After a bit of trial and error I discovered that the problems were mostly related to timer code that had been added to get V-USB to work with the Arduino and which was now doing the exact opposite. Removing this code got me to a point where when I plugged in the cable the Arduino was now being recognized as a USB v1.01 HID Keyboard, which I know is my device because of the vendor and product strings being shown in this screenshot.

Having got the code running I then took the plunge to update the version of V-USB being used to the latest version (currently 20121206) which, after a few little tweaks, was a success. Unfortunately because of the way the library has to be configured a single copy can't be shared between multiple projects, but in the rest of this post I'll explain how to customize the library and show you a fully worked example: TheCaffeineButton.

Firstly I've had problems compiling the library through the Arduino IDE, so I'd recommend compiling any sketches that use the library via the arduino-mk project that I discussed in a previous post. This allows you to have libraries local to a sketch by putting them in a libs subfolder. A basic sketch to use the libary then looks like the following:
// pull in the USB Keyboard library
#include <USBKeyboard.h>

void setup() {
  // TODO: setup like stuff in here...

void loop() {
  // poll the USB connection

  // TODO: whatever you want in here...
You simply include the library (line 2) and then poll the connection every time through the main loop (line 6). As I mentioned though, the library needs customizing for each project and so if you try and compile the sketch at this point you'll end up with an error:
libs/USBKeyboard/usbdrv.h:12:23: fatal error: usbconfig.h: No such file or
V-USB doesn't provide a copy of usbconfig.h as it is project specific, what they do provide is a file called usbconfig-prototype.h which you can copy and rename as a starting point. I've already done a lot of the configuration for you by editing usbconfig-prototype.h leaving just four lines you need to edit for yourself. Firstly you need to set the vendor name property by editing lines 244 and 245:
#define USB_CFG_VENDOR_NAME     'o', 'b', 'd', 'e', 'v', '.', 'a', 't'
and then the device name by editing lines 254 and 256:
#define USB_CFG_DEVICE_NAME     'T', 'e', 'm', 'p', 'l', 'a', 't', 'e'
These values have to be changed and can't be set to any random value because as part of the V-USB license agreement you need to conform to the following rules (taken verbatim from the file USB-IDs-for-free.txt):

(2) The textual manufacturer identification MUST contain either an Internet domain name (e.g. "") registered and owned by you, or an e-mail address under your control (e.g."). You can embed the domain name or e-mail address in any string you like, e.g. "Objective Development".

(3) You are responsible for retaining ownership of the domain or e-mail address for as long as any of your products are in use.

(4) You may choose any string for the textual product identification, as long as this string is unique within the scope of your textual manufacturer identification.
If you glance back at the screenshot I showed earlier of my example device being recognized then you can see that I followed these rules by setting the vendor name to and the device name to TheCaffeineButton.

So having created a valid usbconfig.h file you can now compile the basic sketch shown above. Of course this does nothing other than allow the Arduino to be recognized as a USB keyboard. If you want to actually do something interesting then you need a little more code. As an example, I'll finally introduce you to The Caffeine Button!

Caffeine (usually in the form of coffee) is my one true addiction and so I thought I'd build a device with a single button that when pressed types out the chemical formula for caffeine: C8H10N4O2. The full sketch is fairly simple and assumes the basic circuit above with a push button between pin 12 and ground (it uses the internal pull-up resistor to keep the part list down to the single button):
// pull in the USB Keyboard library
#include <USBKeyboard.h>

// using Bounce makes working with buttons nice and easy
#include <Bounce.h>

// we have the button on pin 12
#define BUTTON_PIN 12

// create a Bounce instance to manage the button
Bounce button = Bounce(BUTTON_PIN, 5);

void setup() {
  // initialise the pin the button is connected to

  // enable the internal pull-up resistor
  digitalWrite(BUTTON_PIN, HIGH);

void loop() {
  // poll the USB connection

  // check the status of the button

  if (button.fallingEdge()) {
    // if the button has just been pressed then...

    // ...print out the formula for caffeine
There are actually four different methods you can use to emulate pressing keys:
void write(byte keycode);
void write(byte keycode, byte modifiers);
void print(const char* text);
void println(const char* text);
The first two method send a USB key usage code (with or without a modifier, such as the shift key) and then release the key, while the last two methods translate alphanumeric characters (and space) into a sequence of keystrokes (followed by the enter key in the println case) to make the library a little easier to use. Unfortunately there is no guarantee that my simple sketch will always result in C8H10N402 being displayed when you press the button.

When you press a key on a keyboard a keycode is sent to the computer which determines which letter has been pressed. This allows the same physical keyboard to be used for different languages simply by changing the printed labels on each key. Unfortunately this makes it impossible to translate a string into a sequence of keycodes which will always display the same on every computer. For example, if you send keycode 28 on a computer with an English keyboard mapping you'll get a 'y', but if the keyboard mapping is German you'll get a 'z'. I've defined a bunch of constants in USBKeyboard.h (i.e. KEY_A) which work for English, and I've used the same mapping in the print and println methods. If you can set the keyboard mapping for the device to English then these methods will work properly for you, if not you might need to tweak the mappings to get what you need. You can find the full list of mappings in chapter 10 of the Universal Serial Bus HID Usage Tables document should you need more details.

So here we have the final working item. As you can see I built the main USB circuit onto a prototyping shield so I can experiment with lots of different circuits without having to keep recreating the basics every time, and in this case have simply jammed the button between pins 12 and ground.

If you've read all the way to here then I'm guessing you might want to know where you can get the library from, well it is available under the GPL licence (a restriction imposed because I'm using the free USB vendor and product IDs from Objective Development) from my SVN repository.

Whilst I haven't yet been able to emulate a serial port I haven't given up and when/if I'm successful I'm sure there will be a post about it and another Arduino library for you to play with.


  1. Have you looked at using the ATmega32u4, as used by the new-ish Arduino Leonardo (

    That one includes the USB implementation on the same chip as the microcontroller, so it may be a simple solution.I've no idea what this chip costs, but it should be cheaper than 2 discrete chips...

    1. I did look at this briefly and it would appear that the ATmega32u4 would cost not much more than the ATMega328P-PU I'm using. The downside is that it is only available as a surface mount part with 44 tiny little pins! Certainly not ideal for breadboarding.

      It also turns out that I can't emulate a CDC ACM device as it requires a high speed USB connection and V-USB only does low speed (it used to work but a change to the linux kernel means that the device won't now work under linux at least). I have managed to send data from the Arduino via the above circuit as a plain USB Human Interface Device and can read that data out using Java. There are a few caveats though and I don't have writing from the PC working yet. Once I do I'm sure there will be another post.