USB HID Traffic Lights Device with PIC18 Microcontroller


I stumbled upon two very interesting articles ([1], [2]) about making a usb device using PIC microcontrollers. So I immediately decided I have to try it my self. The idea was simple: “Have a traffic lights indicator whether the build of certain codeline is ok or broken”.

The USB Device

Actually the USB specification is a science on its own. If one wants to create a usb device from scratch, they have to first study the USB specification which would be a huge undertaking (the USB 2.0 specification is around 1000 pages technical details!). Fortunately there are microcontrollers with integrated USB ports which provide all the USB connectivity out of the box. For this project I’ve used both PIC18F4550 and PIC18F2550 microcontrollers from Microchip. You can follow these guides: [1] and [2] where you will find schematics as well as instructions how to build the actual device.


The way I build the firmware for my device was to reuse one of the PIC MLA examples.

  1. First download and install the Microchip Libraries for Applications from here: [3].
  2. Then navigate to apps -> usb -> device -> hid_custom -> firmware
  3. Import it into MPLAB
  4. Open the usb_descriptors.c file and edit the Product String Descriptor section. This will be the name under which your device will appear when attached to the computer.

If you now build and program your device you should be able to successfully have it enumerated on your computer.

But what it can do?
The USB HID sub-spec defines a class of devices called Human Interface Devices or the likes of keyboards, joysticks, mice, etc. These are simple devices which can receive commands and act upon them. It is very important that for them you don’t need to write a dedicated USB driver! The operating systems provide one for you! So what we need is that, our device understand a set of commands. They come in the form of numbers: 0x10 switch PORTB pin1, 0x20 switch PORTB pin2. Of course you define what are the commands your device understands. This happens in the app_custom_hid.c file. In the APP_cmd() procedure, there is a switch statement finding the command that the PC sent. It is worth to note that the device can return data back to the host. For example: CMD_DEVICE (0x15) is “send device identification string” .

I have defined twenty commands to switch on and off ten pairs of red – green LEDs (more on that later).

The Traffic Lights Device

Because I wanted to use more powerful LEDs I could not have attached them directly to the microcontroller. What’s more I wanted to use as less as possible of the controller’s input/output pins. That’s why I came up with this simple circuit which toggles red/green LED pairs using only one input signal.


The idea is simple, I use a pair of two bipolar transistors. One of them is NPN the other one is PNP. When there is no signal from the controller the BC547 transistor controlling the red LED is saturated which turns the red light on. When high voltage comes from the microcontroller the first BC547 transistor saturates, which opens path between VCC and ground through the 1k resistor, which in turn switches off the red LED. On the other hand this desaturates the base of the BC557 transistor which makes the green LED turn on. I am not sure this is the easiest way to achieve toggling of LEDs, but honestly this is the first circuit I came up with, on my own, so I don’t care if it is complex 🙂
I wanted to show the status of multiple codelines so, I replicated the circuit ten times. Here is the result.



Control Program

If implemented simple control program to test the device using the HIDAPI library from here [4]. On the web site there is a straight forward example which I used.


Actually the program is pretty self-explanatory you can checkout the code from my github page [5].

The program initially enumerates all usb hid devices. Then opens the traffic lights device

handle = hid_open(0x04d8, 0x003f, NULL);

0x04d8 is the vendor id and 0x003f is the device id which we hardcoded into the USB firmware. If the device is opened successfully the product and manufacturer strings are requested and printed into the console.When one of the ten buttons are pressed in the UI, command is sent with this call:

buf[0] = 0x80;
hid_write(handle, buf, 65);
 where buf is replaced with the respective command - switch on LED 1 or switch off LED 2.
You can check the program and the device in action in the videos below.


video 1

video 2

« 1 of 2 »


Leave a Reply