Recently, I presented a USB keyboard interface in another article. I like to build on things that I know will work so, in that sense, this project is similar to the previous one. The main difference between them is that instead of focusing primarily on an input device, this one centers on an output device.
This project has 16 individually addressable LEDs which can be programmed to your liking: in firmware for stand-alone mode; or controlled via a PC through the USB connection. For added fun, there is a temperature sensor and a Hall sensor. Turning LEDs on and off is fun and all, but why not have a sensor or two that can be useful for something other than the usual light show? With this design, you can use temperature and magnetic fields to wow and amaze your friends.
Let’s jump right into this project. Check out the EAGLE schematic view and the printed circuit board (PCB) layout.
FIGURE 1. EAGLE schematic.
FIGURE 2. Layout.
I’ve created rules for my circuit design that save money and time, and use resources wisely:
Starting at the far left of the layout and moving to the right, I’ll explain the rationale behind some of the parts you see in the following figures.
FIGURE 3. The original work-in-progress prototype. (Boy, is it messy!)
FIGURE 3A. Prototype in plastic enclosure
FIGURE 4. The unpopulated production-quality PCB.
FIGURE 5. First step of PCB assembly; Microchip PIC installed.
FIGURE 6. PIC support components and center LEDs added.
FIGURE 7. PCB side LEDs finish the assembly.
The USB connector (JUSB) is a surface-mount part that has four vias that overlap the SMT pads. That violates a design rule! I added holes so the modified design could use several of the SMT products available for Type-A connectors, as well as some of the through-hole versions. This allows the design to use a wide range of vendor parts for the USB connector. If you have ever tried to source these, you know how much of a variation in price there can be.
There is nothing apparent in the layout design for the Microchip PIC (IC1) that might seem to allow us to use a wider range of these particular microcontrollers, but there is. The original design was for the PIC18(L)F2550 which has 32K of programming space. The PIC18(L)F2450 part has the same footprint with 16K of program space. There are some savings there if your program doesn’t need all that.
Since these USB-enabled parts were released, there are newer drop-in replacement parts available that do not need external clocks (Y1) to function. Namely, these would be the ‘K’ series parts from Microchip. The ‘J’ series parts can work, but this design does not provide for an extra capacitor or voltage source that this series would need. I didn’t overlook these; I just didn’t plan on using them in this design. Besides, the PIC18F25K50 part is plenty cheaper than the original 2550 part.
Remember: The part documentation states that the PIC18LF25K50 does not have a built-in regulator to power the USB connection; however, the PIC18F25K50 does. This circuit design only supports the internal USB regulator parts.
There is no reason to waste space using 5 mm through-hole LEDs when SMT LEDs take up considerably less space. (Refer to the self-imposed design rules.) There are several factors to consider here:
The final items to consider are the voltage regulator (IC3) and its jumper (POW). The previous USB keyboard design had these items too, but they were rarely needed. That PCB didn’t drive any loads by design; it only needed enough current to power the PIC and some switches. The power provided by the USB connection is just fine for that. This design has a bunch of LEDs and those can draw a lot of current depending on the design.
Additionally, this PCB is much more useful than the keyboard design as a stand-alone PCB. The 5 VDC regulator allows for an alternate external power source to be connected so that the PCB can function without a PC.
Speaking of LED current, keep in mind that PICs are typically designed to source only about 10 mA and sink about 20 mA of current. That is why all the LEDs use negative logic (a digital 0, 0VDC) to turn on the individual LEDs. This allows the PIC’s internal transistors to be used in their most current-efficient configuration. However, this does not mean that the PIC will like driving all the LEDs at full current for very long without getting hot. Of course, this doesn’t mean that it cannot. It just means that either we design or program to limit the illumination time of all the LEDs, or we add a heatsink and fan.
I assigned the LED series resistor a value that is slightly higher than it needs to be in order to drop the effective current a bit. If you do the math — assuming a 5 VDC source — typically, you would need about a 100 ohm resistor for each LED. In practice, any resistor value from 100 ohms to 1K ohm will work without much reduction in LED brightness.
I tend to starve LEDs of current in most designs that use them as simple event indicators. I would probably use a 3K ohm resistor which I also used on the previous keyboard circuit. This time, we probably want the LEDs to be bright. You can adjust these values as you see fit. As long as you can see the LED and don’t make the PIC sink too much current, everything should be fine.
This design will not populate LED15 and LED16. If they are connected and you hook up an in-circuit programmer to the program jumper (JPRG) and try to program, those LEDs will demand more current than most in-circuit programmers can handle, thereby ruining most programmers.
Make sure you remove the LEDs before you program. Another option: Use a 10K ohm resistor to connect the two LEDs. Doing so usually reduces the current sufficiently to allow the in-circuit programmers to function. If you choose not to remove the LEDs before you program, they will function but will be noticeably dimmer than the others.
That should cover all of the physical aspects of this circuit. Let’s move on to the firmware. The firmware is quite basic, as is pretty much always the case with good code. The firmware does not follow any formalistic standards. It was written as each part of the functionality was added in order to keep variables and the logical flow easy to understand. Clean code is the best thing that one programmer can give to another programmer.
I do not claim that this is the best code in the world. In fact, it is what I generally call “quick and dirty code” or “Get-R-Done” code (spoken in the voice of Larry, the Cable Guy, of course).
The firmware is divided into three basic sections, listed from the beginning of the file “2550USBLEDs_20121020.c:”
The first two sections are not useful in the context of this article. The main routine contains all of our upper functionality. It starts out initializing the device by configuring ports, the analog-to-digital converters (ADCs), turning off the LEDs, initializing the USB connection subsystem, and waiting a moment or two. It’s not the best code, but it works. You must respond to any new USB connections within the spec time. That is why the usb_task() function is called from time to time within all of the code.
That brings us to the main while loop. By way of a verbal block diagram, the first 10 or so lines are the repeated housekeeping activities — like allowing the USB functionality time to work, blinking an LED to show that we are alive, and clearing out the LEDs after extended periods of non-activity.
Next, we get our temperature data or our Hall magnetic data based on what mode the device is running in. There are four modes defined so far:
The last longwinded section of the main function handles the incoming USB commands. This section requires far more code than displaying and acquiring the sensor data does. However, it is no more complex. Its only functions are making sure there is a connection to the USB and there is data waiting on the line, as well as seeing if any of the incoming data matches one of our supported commands.
The commands are pretty simple. The important ones turn the individual LEDs (A-P and a-p commands) on and off, set the modes mentioned previously (W-Z commands), and produce a help screen (‘?’ command). That’s the main function and its infinite while loop.
The support functions called by the main loop are pretty straightforward. They validate data, perform some calculations, and either return some data or turn LEDs on or off. Don’t get me wrong; I am not over-simplifying things. We are all hobbyists here, so I don’t want to over-explain that which is obvious.
As presented, this design requires a driver file to be loaded on a PC. The driver files (provided by CCS, Inc.; www.ccsinfo.com) produce the compile with which this project was built. The PIC can be programmed to use any driver that you write your own code to utilize. So, technically, you are not limited at all. However, if you want to use the design as-is, you must use the drivers provided, as well as those that are available for download.
I will make a firmware version that also allows the use of the HID interface. These types of devices generally do not require additional drivers. In my previous article, I described what might need to be done if you use a really old PC.
As for troubleshooting, most — if any — issues will concern getting the PC drivers to install correctly. Once that is done, if the device responds to commands issued via a communications port connection (via the virtual USB-to-serial drivers), that is a good sign the device is powered and mostly working. If the LEDs do not illuminate or sensors do not return data, uninstall and reinstall them.
FIGURE 8. Initial LED test in random mode.
FIGURE 9. The serial port output.
On the off chance that a component is bad, replace it. If you cannot get the device to connect via USB and the drivers have been installed, make sure that diode D1 is installed correctly. If it is backwards, the device will not work via the USB power connection alone. If you have diode D1 installed backwards and have an external power supply connected, it would still work, and the USB connection would be active.
However, in this scenario, you would be supplying five volts DC to the PC’s USB data link. In most cases, nothing would happen, but many laptops only provide 3 VDC on their USB devices. In this case, you would probably damage the USB port. Needless to say, I recommend installing diode DI correctly.
I hope this design is simple and straightforward enough to be helpful. I further hope that the logic and rationale used were more beneficial than the core functionality of the design. The physical design is quite simple, but the firmware can make this little circuit do a lot of useful things. Once you add a PC to the USB connection, who knows what a little imagination can bring!
Remember, there is a lot more that you can do with this simple circuit. As long as you stay within general safety and device limitations, you should be just fine. NV
|C1,C3||0.1 µF||CAP 0603||Noise reduction|
|C2||4.7 µF||CAPPOL 3216-18W||Current boost for LEDs|
|C4||0.47 µF||CAP 0603||Required for USB communications|
|D1||1N4148||DIODE-SOD323-W||USB power protection diode|
|D2,D3||3.9V||ZENER DIODE SOT23||USB data line protection|
|IC1||PIC18F2550_28W||PIC18F2550||Main control IC; can substitute PIC18LF2550, PIC18(L)F2450, PIC18F25K50, or PIC18F24K50|
|IC2||LM50||LM50||Analog output temperature IC|
|IC3||LP2950ACZ-5.0||LP2950ACZ-5.0||5 VDC regulator|
|IC4||A1301LH||A1301LH||Analog output Hall sensor|
|JP2||DNP||PINHEADER 1X01||Test/AUX point|
|JP3||DNP||PINHEADER 1X02||Test/AUX point|
|JP4||DNP||PINHEADER 1X04||USB optional through-holes|
|JPRG||PIN HEADER 1X05||*To allow in-circuit programming|
|LED1-16||Any color 5 mm LED|
|R2-R15||100 ohms to 1K ohm||RES 0603|
|R16-R17||10K ohm||RES 0603||*To allow in-circuit programming|
|Y1||20 MHz||Ceramic resonator|