DIY ECG with 1 op-amp

I made surprisingly good ECG from a single op-amp and 5 resistors! An ECG (electrocardiograph, sometimes called EKG) is a graph of the electrical potential your heart produces as it beats. Seven years ago I posted DIY ECG Machine on the Cheap which showed a discernible ECG I obtained using an op-amp, two resistors, and a capacitor outputting to a PC sound card’s microphone input. It didn’t work well, but the fact that it worked at all was impressive! It has been one of the most popular posts of my website ever since, and I get 1-2 emails a month from people trying to recreate these results (some of them are during the last week of a college design course and sound pretty desperate). Sometimes people get good results with that old circuit, but more often than not the output isn’t what people expected. I decided to revisit this project (with more patience and experience under my belt) and see if I could improve it. My goal was not to create the highest quality ECG machine I could, but rather to create the simplest one I could with emphasis on predictable and reproducible results. The finished project is a blend of improved hardware and custom cross-platform open-source software (which runs on Windows, Linux, and MacOS), and an impressively good ECG considering the circuit is so simple and runs on a breadboard! Furthermore, the schematics and custom software are all open-sourced on my github!

my heartbeat recorded while filming the YouTube video shown below

Here’s a video demonstrating how the output is shown in real time with custom Python software. The video is quite long, but you can see the device in action immediately, so even if you only watch the first few seconds you will see this circuit in action with the custom software. In short, the amplifier circuit (described in detail below) outputs to the computer’s microphone and a Python script I wrote analyzes the audio data, performs low-pass filtering, and graphs the output in real time. The result is a live electrocardiograph!

The circuit is simple, but a lot of time and thought and experimentation went into it. I settled on this design because it produced the best and most reliable results, and it has a few nuances which might not be obvious at first. Although I discuss it in detail in the video, here are the highlights:


  • The output goes to the microphone jack of your computer.
  • There’s nothing special about the op-amp I used (LM741). A single unit of an LM324 (or any general purpose op-amp) should work just as well.
  • Resistor values were chosen because I had them on hand. You can probably change them a lot as long as they’re in the same ballpark of the values shown here. Just make sure R1 and R2 are matched, and R3 should be at least 10MOhm.
  • Do not use a bench power supply! “BAT+” and “BAT-” are the leads of a single 9V battery.
  • Note that the leg electrode is ground (same ground as the computer’s microphone ground)
  • R5 and R4 form a traditional voltage divider like you’d expect for an op-amp with a gain of about 50.
    • You’d expect R4 to connect to ground, but since your body is grounded, chest 2 is essentially the same
    • R3 must be extremely high value, but it pulls your body potential near the optimal input voltage for amplification by the op-amp.
    • R1 and R2 split the 9V battery’s voltage in half and center it at ground, creating -4.5V and +4.5V.
  • altogether, your body stays grounded, and the op-amp becomes powered by -4.5V and +4.5V, and your body is conveniently near the middle and ready to have small signals from CHEST1 amplified. Amplification is with respect to CHEST2 (roughly ground), rather than actual ground, so that a lot of noise (with respect to ground) is eliminated.
DIY ECG made from 1 op-amp, 5 resistors, a 9V battery, and 3 penny electrodes

For those of you who would rather see a picture than a schematic, here’s a diagram of how to assemble it graphically. This should be very easy to reproduce. Although breadboards are typically not recommended for small signal amplification projects, there is so much noise already in these signals that it doesn’t really matter much either way. Check out how good the signals look in my video, and consider that I use a breadboard the entire time.


The most comfortable electrodes I used were made for muscle simulators. A friend of mine showed me some muscle stimulator pads he got for a back pain relief device he uses. As soon as I saw those pads, I immediately thought they would be perfect for building an ECG! They’re a little bit expensive, but very comfortable, reusable, last a long time, and produce brilliant results. They also have 3.5 mm (headphone jack) connectors which is perfect for DIY projects. On you can get 16 pads for $11 with free shipping. I decided not to include links, because sometimes the pads and cords are sold separately, and sometimes they have barrel connectors and sometimes they have snap connectors. Just get any adhesive reusable electrodes intended for transcutaneous electrical nerve stimulation (TENS) that you can find! They should all work fine.


You can make your own electrodes for $0.03! Okay that’s a terrible joke, but it’s true. I made not-awful electrodes by soldering wires to copper pennies, adding strength by super-gluing the wire to the penny, and using electrical tape to attach them to my chest. Unless you want a tattoo of an old guy’s face on your torso, wait until they cool sufficiently after soldering before proceeding to the adhesion step. I suspect that super gluing the penny to your chest would also work, but please do not do this. Ironically, because the adhesive pads of the TENS electrodes wear away over time, the penny solution is probably “more reusable” than the commercial electrode option.

I put pennies on wood to help them get hot as I solder to them.
I put pennies on wood to help them get hot as I solder to them.


penny electrodes match the minimalist style of this project
penny electrodes match the minimalist style of this project


this ECG was captures using penny electrodes
This ECG was captured using penny electrodes. It’s pretty darn good!


Notes on filtering: Why didn’t I just use a hardware low-pass filter?

  1. It would have required extra components, which goes against the theme of this project
  2. It would require specific value components, which is also undesirable for a junkbox project
  3. I’m partial to the Chebyshev filter, but getting an extremely sharp roll-off a few Hz shy of 50Hz would take multiple poles (of closely matched passive components) and not be as trivial as it sounds.

Notes on software: This a really cool use of Python! I lean on some of my favorite packages numpy, scipy, matplotlib, pyqrgraph, and PyQt4. I’ve recently made posts describing how to perform real-time data graphing in Python using these libraries, so I won’t go into that here. If you’re interested, check out my real-time audio monitor, notes on using PlotWidget, and notes on using MatPlotLib widget. I tried using PyInstaller to package this project into a single .EXE for all my windows readers who might want to recreate this project, but the resulting EXE was over 160MB! That’s crazy! It makes sense considering packagers like PyInstaller and Py2EXE work by building your entire python interpreter and all imported libraries. With all those fun libraries I listed above, it’s no wonder it came out so huge. It may be convenient for local quick-fixes, but not a good way to distribute code over the internet. To use this software, just run it in Python. It was tested to work with out-of-the-box WinPython-64bit- (not the Qt5 version), so if you want to run it yourself start there.

Notes on safety. How safe is this project? I’m conflicted on this subject. I want to be as conservative as I can (leaning on the side of caution), but I also want to be as realistic as possible. I’m going to play it safe and say “this may not be safe, so don’t build or use it”. As an exercise, let’s consider the pros and cons:

  • PROS:
    • It’s powered from a 9V battery which is safer than a bench power supply (but see the matching con).
    • The only connections to your body are:
      • leg – ground. you ground yourself all the time. using a wrist grounding strap is the same thing.
      • chest 1 – extremely high impedance. You’re attaching your chest to the high impedance input of an op-amp (which I feel fine with), and also to a floating battery through a 10MOhm resistor (which also I feel fine with)
      • chest 2 – raises an eyebrow. In addition to a high impedance input, you’re connected to an op-amp through a 100k resistor. Even if the op-amp were putting out a full 4.5V, that’s 0.045mA (which doesn’t concern me a whole lot).
    • I don’t know where to stick this, but I wonder what type of voltages / currents TENS actually provide.
    • It’s powered from a 9V battery. So are many stun guns.
    • If the op-amp oscillates, oscillations may enter your body. Personally I feel this may be the most concerning issue.
    • Small currents can kill. I found a curiously colored website that describes this. It seems like the most dangerous potential effect is induction of cardiac fibrillation, which can occur around 100mA.

Improving safety through optical isolation: The safety of this device may be improved (albeit with increased complexity) through the implementation of opto-isolators. I may consider a follow-up post demonstrating how I do this. Unlike digital signals which I’ve optically isolated before, I’ve never personally isolated analog signals. Although I’m sure there are fully analog means to do this, I suspect I’d accomplish it by turning it into a digital signal (with a voltage-to-frequency converter), pulsing the output across the optoisolator, and turning it back into voltage with a frequency-to-voltage converter or perhaps even a passive low-pass filter. Analog Devices has a good write-up about optical isolation techniques.

Do you have comments regarding the safety of this device? Write your thoughts concisely and send them to me in an email! I’d be happy to share your knowledge with everyone by posting it here.

Did you build this or a device similar to it? Send me some pictures! I’ll post them here.

Source code and project files:

LEGAL: This website is for educational purposes only. Do not build or use any electrical devices shown. Attaching non-compliant electronic devices to your body may be dangerous. Consult a physician regarding proper usage of medical equipment.


Python Real-time Audio Frequency Monitor

A new project I’m working on requires real-time analysis of soundcard input data, and I made a minimal case example of how to do this in a cross-platform way using python 3, numpy, and PyQt. Previous posts compared performance of the matplotlib widget vs PyQtGraph plotwidget and I’ve been working with PyQtGraph ever since. For static figures matplotlib is wonderful, but for fast responsive applications I’m leaning toward PyQtGraph. The full source for this project is on a github page, but here’s a summary of the project.



I made the UI with QT Designer. The graphs are QGraphicsView widgets promoted to a pyqtgraph PlotWidget. I describe how to do this in my previous post. Here’s the content of the primary program:


from PyQt4 import QtGui,QtCore
import sys
import ui_main
import numpy as np
import pyqtgraph
import SWHear

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
    def __init__(self, parent=None):
        pyqtgraph.setConfigOption('background', 'w') #before loading widget
        super(ExampleApp, self).__init__(parent)
        self.grFFT.plotItem.showGrid(True, True, 0.7)
        self.grPCM.plotItem.showGrid(True, True, 0.7)
        self.ear = SWHear.SWHear()

    def update(self):
        if not is None and not self.ear.fft is None:
            if pcmMax>self.maxPCM:
            if np.max(self.ear.fft)>self.maxFFT:
        QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    form = ExampleApp()
    form.update() #start with something

note: this project uses a gutted version of the SWHEar class which I still haven’t released on githib yet. It will likely have its own project folder. For now, take this project with a grain of salt. The primary advantage of this class is that it makes it easy to use PyAudio to automatically detect input sound cards, channels, and sample rates which are likely to succeed without requiring the user to enter any information.

All files used for this project are in a GitHub folder

2016-09-05: Okko adapted this project into a screenlet (cross platform) which also includes an installer for Windows. That Githib page is here: Below is a screenshot of me running it on my Windows 10 machine



Live Data in PyQt4 with PlotWidget

After spending a day comparing performance of MatplotlibWidget with PlotWidget, when it comes to speed PlotWidget wins by a mile! Glance over my last post where I describe how to set up the window with QT Designer and convert the .ui file to a .py file. With only a few changes to the code, I swapped the matplotlib MatplotlibWidget with the pyqtgraph PlotWidget. I easily got a 20x increase in speed (frame rate), and I’m likely to favor PyQtGraph over matpltolib for python applications involving realtime display of data. Just like the previous example using matplotlib, this one uses the system time to control the phase and color of a sine wave in real time. You can grab the full code from my github folder.



When designing the GUI with QT Designer, add a QGraphicsView widget then assign it to become a PyQtGraph object. To do this, follow the steps found on the pyqtgraph docs page:

  1. In Designer, create a QGraphicsView widget.
  2. Right-click on the QGraphicsView and select “Promote To…”.
  3. Set “Promoted class name” to “PlotWidget”.
  4. Under “Header file”, enter “pyqtgraph”.
  5. Click “Add”, then click “Promote”.
  6. apparently this only needs to be done once per project

promoted widgets

In addition to faster frame rate, the PyQtGraph method is easy to interact with. Clicking and dragging scrolls the data, and right-clicking and dragging zooms on each axis. Here’s the program code:

from PyQt4 import QtGui,QtCore
import sys
import ui_main
import numpy as np
import pylab
import time
import pyqtgraph

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
    def __init__(self, parent=None):
        pyqtgraph.setConfigOption('background', 'w') #before loading widget
        super(ExampleApp, self).__init__(parent)
        self.grPlot.plotItem.showGrid(True, True, 0.7)

    def update(self):
        points=100 #number of data points
        print("update took %.02f ms"%((time.clock()-t1)*1000))
        if self.chkMore.isChecked():
            QtCore.QTimer.singleShot(1, self.update) # QUICKLY repeat

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    form = ExampleApp()
    form.update() #start with something

All files used in project can be downloaded from the GitHub page.


Live Data in PyQt4 with MatplotlibWidget

I keep getting involved in projects which require live data to be graphed in real time. Since most of my back-end is written in Python, it makes sense to have a Pythonic front-end. Cross-platform GUI programming in Python is frustratingly non-trivial, as there multiple window frameworks available (TK, GTK, and QT) and their respective graphical designers (torture, Glade, and QT Designer) and each has its own way of doing things. Add different ways to plot data in the mix (gnuplot, matplotlib, and custom widgets) and it can become a complicated mess. Different framework combinations favor different features (with unique speed / simplicity / elegance), so my goal is to slowly test out a few combinations most likely to work for my needs, and add my findings to a growing github repository. The first stab is using PyQt4 and matplotlib’s widget (MatplotlibWidget). Rather than capture data from the sound card (my ultimate goal), I’m going to generate a sine wave whose phase and color is related to the system time. Matplotlib plotting is a bit slow, but the output is beautiful, and their framework is so robust. Here’s the output of my first test showing the sine wave generated as well as the console output (showing that each call to the plotting function takes about 40 ms. At this rate, I can expect a maximum update rate of ~25 Hz.



Designing this project was easy, but it was surprisingly hard to figure out how to do this based on examples I found on the internet. This is part of why I wanted to place this example here. The downside of many internet examples is that they did not use Qt Designer to make the window, so their code to create a window and insert the MatplotlibWidget wasn’t copy/paste compatible with my goals, and often more complex than I needed. Some internet examples did use Qt Designer to make the window, but left a frame empty which they later manually filled with a widget and attached to a matplotlib canvas. This is fine, but more complex than I need to get started.

First, I designed a GUI with Qt Designer. I dropped a MatplotlibWidget somewhere, and used its default name. I saved this file as ui_main.ui (which is an XML file, ready to be used for multiple programming languages).

pyqt4 designer

Next, I converted the UI file into a .py file with a standalone python script that’s an alternative to using pyuic from the command line. The script to do this is and it calls PyQt4.uic.compileUi():

from PyQt4 import uic 
fin = open('ui_main.ui','r')
fout = open('','w')

I then created my main program file which populates the matplotlib widget with data. I called it and running it will launch the app. The code explains it all, and there’s not much more to say! It produces the output at the top of this post.

from PyQt4 import QtGui,QtCore
import sys
import ui_main
import numpy as np
import pylab
import time

class ExampleApp(QtGui.QMainWindow, ui_main.Ui_MainWindow):
    def __init__(self, parent=None):
        super(ExampleApp, self).__init__(parent)
        self.matplotlibwidget.axes.hold(False) #clear on plot()

    def update(self):
        points=100 #number of data points
        Y=np.sin(np.arange(points)/points*3*np.pi+time.time()) # random color
        self.matplotlibwidget.axes.get_figure().tight_layout() # fill space
        self.matplotlibwidget.draw() # required to update the window
        print("update took %.02f ms"%((time.time()-t1)*1000))
        if self.chkMore.isChecked():
            QtCore.QTimer.singleShot(10, self.update) # QUICKLY repeat

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    form = ExampleApp()
    form.update() #start with something

All files used in project are available on GitHub


Opto-Isolated Laser Controller Build

I just finished building a device to interface a modern fiber-coupled DPSS laser used for optogenetic experiments with 15 year old scientific hardware. I finished this project in one afternoon, and I’m very happy with how it came out! This project has a blend of analog and digital circuitry, microcontrollers, and lasers (all the fun stuff!) and turned out to be a pretty cool build, so I’m sharing the design and construction with the hope that it will be inspiring to someone else. I don’t intend anyone to replicate this project (it’s designed to fill a very small niche), but I’ve learned a lot over the years by reading other peoples’ project build web pages and I’m happy every time I get the opportunity to make one of my own. The hardware I needed to interface is made by Coulbourn Instruments and is essentially just a large multi-channel computer-controlled DAC/ADC and it does its job well (turning lights on and off, recording button presses, etc.), but this new task requires millisecond resolution and modulation patterns which [most likely] lie outside the specs of this system and software. My goal was to utilize a free hardware output line to signal to a device that I build to modulate the laser in a special way. This way there would be no modification to any existing equipment, and no software to install. Further, since this hardware isn’t mine, I don’t like the idea of permanently modifying it (or even risking breaking it by designing something which could damage it by connecting to it). The specific goal is to allow the existing software to cause the laser to fire 20 ms pulses at 15 Hz for a few dozen cycles of 5s on, 5s off. It’s also important to have some flexibility to reprogram this firing protocol in the future if a change is desired. What’s more is that experiments are already underway and I needed this device to be complete within a couple of days! As much as I’d love to go to the internet and order the perfect, cheap components from China and have a beautiful build completed after the 6-8 weeks of shipping time, I had to build this only using parts I already had at my home.

After a little poking around, I found an auxiliary output which could be controlled by software. This AUX port has a frustratingly rare connector 1mm dual keyhole touchproof connector which I couldn’t buy in bulk on eBay or amazon, and couldn’t figure out the part numbers of on Mouser or Digikey. Luckily the laboratory had an old (broken) device with that connector on it they said I could cannibalize. (The manual even says “you may find it convenient to fit them with CI-type connectors” which makes me wonder why it wasn’t designed this way in the first place) After plugging in the connector, I used a volt meter to measure the output. To my surprise, it wasn’t a TTL signal! I expected to see my volt meter read 5V, but it read 28V! After consulting the manual I found mention of this: “Graphic State Notation software is designed for use with our Habitest animal-behavior-analysis environments or any other animal-behavior-testing apparatus that operates on the industry-standard 28-Volt control voltage.” I was surprised that 28V signals is a standard for any industry. But wait, there’s more! Elsewhere in the manual I found the phrase “The power base is capable of delivering 8 Amps of -28 VDC” which made me question the voltage reading I took earlier. The voltmeter showed 28V, but that’s the difference between one keyhole connector output and the other. I became apparent that it really may be 0V and -28mV (an even more curious “industry standard”). I wondered if connecting the negative terminal to ground would destroy the unit (think about how easy this would be to do! If it were a TTL signal, the first thing you would do is connect the negative terminal to ground and start sampling the positive terminal). There was even talk of me interfacing with a different output port (which I hadn’t probed, so I didn’t know the voltage). Moving forward, I realized I had to tread very carefully. Doing something like connecting two grounds together could permanently damage this system! Not really knowing if I should design to expect a TTL signal, a +28V signal, or a -28V signal, I decided to design a circuit to accomodate all of the above, all the while respecting total electrical discontinuity from the circuit that I develop. I’m going to accomplish this using an opto-isolator on the input. I sketched the schematic on paper while I built the device, and only later came back and formally made it in KiCad. I considered laying out a PCB (I have most of these components in SMT form factors too) but I knew I wouldn’t manage a one day turnaround if I went that far so I let that idea go.

A major points about this circuit design: 

  • The input should be able to accomodate any signal (TTL, CMOS, 28V, etc)
  • The input is totally isolated electrically, so this should be very safe on the hardware
  • The microcontroller is a socketed ATTiny85 which I programmed with a Bus Pirate.
  • I decided to rely on a crystal rather than the internal RC clock to improve temporal precision of the output signal. A 11.0592 MHz crystal was chosen because I have a bucket of them (they’re perfect for serial communication at all common baud rates). Any crystal could be used, as long as it’s frequency is defined in software.
  • Capacitors were added more to ensure oscillation initiates than to bring down the oscillation frequency. (I’m told that omitting them may cause a case where the crystal doesn’t resonate as well, but I’ve never found this in my personal experience.) A good note on microcontroller clocks is in a Microchip PIC application note.
  • I included a “test” button (momentary switch) to simulate having an input signal.
  • Note that R1 must be able to handle the current applied to it. It was mistakenly designed as 1k, and later replaced with 10k. See the bodge note at the bottom of this post for details.

This design could still benefit from:

  • Forward protection diodes on the input could protect accidental reverse polarity
  • Adding an ICSP header would prevent de-socketing of the MCU if reprogramming is desired
  • The BNC output is directly from a MCU pin. It should be at least transistor-buffered to deliver higher current.

Because there is a possibility that a different output (laser control) pattern may be desired in the future, I considered whether or not I should make the output pattern user-configurable. Adding buttons, a display, and designing a menu system in software would be a lot of work and no one’s really strongly asking for it, so I concluded that I’m going to build this device to the specific task at hand. If the end user eventually wants the ability to modulate the pattern on their own, the device they ask for would be a very different one than the one I was tasked to create. Since the current pattern is burned into a microchip, a compromise is that I could have new patterns burned into new microchips, and the end-user could change the chip (as long as it’s an infrequent occurrence).

Wait a minute, turning 20 ms pulses at 15 Hz sounds like an easy task for a 555 timer without the need for digital circuitry. Also, it would be easy for the end user to adjust both of these features by turning a knob! Is a microcontroller overkill? I struggled with this question for a while, but concluded that the advantage of the MCU (crystal-disciplined time precision of the output pulses) outweighed the convenience of  a purely analog circuit. A 555 timer in astable / multi-vibrator configuration would mostly get the job done, but you would either (1) only allow one output pattern and rely on precision passive components (which I don’t have on hand), or (2) allow the end-user to adjust duty/frequency with potentiometers (which would require the output to be quantitatively monitored on an oscilloscope). I considered a blend of analog and digital circuitry by using analog components (with knobs) to adjust the duty/frequency, and microcontroller to measure the pulse width and period and display this on a screen (essentially building the oscilloscope into the device). Again, this is more work, and without being asked by the end-user to have an adjustable product (they just indicated interest when I proposed it), I decided I’d continue with the simplest-case, high-resolution design. Also I’ll note that I’m relying on an external crystal (rather than the internal RC clock) to maximize precision from day to day use. Since this device will be used for scientific experimentation, I want to minimize the influence of temperature on the temporal precision of the output signal.


Luckily I had an enclosure ready to go. I always buy enclosures in bulk, and even though nice ones tend to be expensive, having them on hand encourages me to build devices as I think of them, rather than making flaky hardware which I have a history of doing which sometimes borders on ridiculousness. I usually stock unfinished Hammond diecast aluminum enclosures (which I write on with sharpie) for making quick RF projects, and generic fancier boxes with feet and side vents, but for this task I decided to (mostly) seal everything inside a typical (but a little more costly) aluminum enclosure (most likely an eBay special from China, but I can’t remember where I got it). I love using low current LEDs, and I started going with frosted instead of clear LEDs because they’re easier on the eyes. Also, I switched to mostly 3mm LEDs instead of 5MM because I think they look cooler. I have black bezels but they don’t snap in as well as I’d hope, so I find myself having to add a dot of super glue to retain the LED and the bezel in position.

I used nicer perfboard with platted-through holes to build this circuit. Normally I use cheap ubiquitous perfboard with little copper rings glued to one side.  It’s easy to solder to because the copper is so thin it heats quickly, but it’s not always a good long-term solution because the copper pads have a tendency to un-stick. I rarely use this nicer perfboard (it is more expensive, I order from China on ebay), but again I value having things like this stocked at my home ready to go at a moment’s notice!

I marked areas of optical isolation with a black marker. This makes it obvious where the potentially dangerous, potentially high-voltage (well, higher than TTL) input comes in. No wires or connections should invade this space on the board. The special connector which will connect this device to the scientific hardware is at the laboratory, and I’ll have to solder it at the time of delivery/installation. I left an extra hole in the back which I guesstimated would fit the wire. I didn’t have any rubber grommets stocked at my home… I need to get some!

Strong copper wires hold the front panel onto the circuit, but this wasn’t actually intentional. I first screwed down the circuit board, soldered everything together, and after I realized a change was needed on the underside of the board an unscrew was required. That’s when I realized that I could unscrew the front panel rather than desolder it, and it held its shape great! At first glance this doesn’t look like a robust construction technique, but is it really any different than soldering stiff coated wires?


Once it was all together, the device seemed to perform well. The test button on the back made it easy to inspect the output. My RF background made me instinctively terminate the output into a 50 ohm resistor for the measurements, but the square waves looked like super wonky RC curves and I realized 50 ohms is far too low impedance. If it’s a TTL signal, let’s assume it’s virtually infinite impedance, and not worry about it. Note that this is a testament to the relatively low maximum output current of the microcontroller pin, and the potential need for a buffered output if anything more than high impedance TTL is to be driven. I think the datasheets suggests limiting its current to 20 mA per pin (requiring termination of no less than 250 Ohms) A 50 Ohm resistor pulled it out of spec. Oh well, I removed it and it survived fine, so let’s make some measurements

An important thing to note is that absolute time precision is preferred over accuracy. Specifically, I want this device to perform identically for years, and highly favor precision over accuracy. With that said, I trust the pulses to be 20ms wide, but not exactly 15 Hz. To do 15 Hz, I’d need 20ms on and 46.666667 ms off. I could probably get pretty close if I wanted to, but I rounded it to 20 ms on and 46 ms off. This gives time for the instruction cycles toggling the output pins to occur (although it’s on an order of magnitude faster time scale), which slightly biases the time in the right direction. I considered adding a _delay_us(666) after the _delay_ms(46) but I’m satisfied with it this knowing it’s within 1% accuracy of 15 Hz and that precision is locked to that of the crystal (around 10 ppm, or 0.001%).

Admittedly the _delay_ms() method of timekeeping is a little clumsy. I considered a few other methods of time keeping, but decided not to implement them (yet?). The schools of thought were largely on three categories, but all relied on the AVR timers. Here’s an awesome guide on the topic, and here’s another. Timers would be preferred if I wanted the program code of the microcontroller to be free to do other things like drive menus or multiplex a display. Think of hardware timers on a MCU like multi-threading on a computer – it helps you out by running in the background.

  • Thought 1: timers: Set the timer to overflow every 1 ms. On overflow, a counting variable would be incremented and a function would be called to determine what to do. At pre-programmed time points (with respect to the counting variable), the output pin would be toggled, or the counting variable would be reset.
  • Thought 2: output compare registers: Utilize the built-in OCR (output compare register) to turn the output signal on and off. Set the timer to overflow at 15 Hz, turning the output on. Set the OCR (to the fractional point between 0 and the maximum timer value) such that when it is passed, the output is turned off. This way 15 Hz, 20 ms pulses would be continuously running without any code being executed. Input sensing could simply enable and disable the timer.
  • Thought 3: input interrupts: Why stop at timers? Polling the input pin for a TTL signal puts the chip in an infinite loop. Relying on the AVR’s external (pin change) hardware interrupts could eliminate this as well. I always rely heavily on the datasheet when setting these interrupts.

Altogether these improvements could come in handy if a more accurate time source is desired, an advanced display is added, or menus are implemented which would benefit from letting the pulsing output operate in the background. For now, I’m happy with my dirt-simple code, and I’m still far within my one afternoon construction timeline goal!

After I was satisfied with construction, I started labeling the enclosure. I want to tip my hat to Onno Hoekstra on this one, as his webpage demonstrating how good clear labels make custom ham radio equipment look (and a personal email he sent me recently) made me start making clear labels for all of my custom equipment. FYI I’m using a DYMO LetraTag LT-100T Plus label maker and clear tape. It’s important to enable the black outline around the text, then cut carefully slightly outside the outline with regular scissors. The results look fantastic!

The morning I delivered my product, I added the final connector which I didn’t have at home. It’s an inelegant knot-retained configuration, but I think it’ll get the job done! Again this is a surprisingly rare fully shielded touchproof connector apparently used only in medical applications. At this point, I’m thinking this figure was chosen to (A) protect the user from accidentally shorting a 28V 8A power source (that’s over 200 watts!), (B) to prevent you from damaging the equipment by plugging in something that doesn’t belong (could you imagine what would happen if this -28V high current source had a BNC connector and you plugged this into something expecting a 5V TTL input?), and (C) prevent you from plugging in anything that wasn’t made by this company. The last option is more likely consumer protection rather than the company trying to maintain a status of sole distributor of accessories, but it does make you wonder. I would have preferred power pole sockets (that’s the ham in me), molded connectors like those on motherboards, or even barrel connectors! Surely there’s a more standard touchproof connector for moderate voltage/currents (although, to be honest, I’m struggling to think of one at the moment). CL-type connectors seem expensive and bulky.

I plugged the device in to the computer, attached the laser, and it worked immediately! I couldn’t say I was surprised that it worked, but it still felt good to watch the blue laser beam trigger like it was supposed to. Another cool one-off project is in the bag, and I got some great pictures for the website. I hope this little box lives many happy years in its laboratory home.


The current software is so simple, it’s not worth discussing! This is the code I loaded onto the microcontroller.

#define	F_CPU (11059200UL)
#include <avr/io.h>
#include <util/delay.h>

int main (void){	
    DDRB=(1<<PB0); // TTL output
	PORTB=0; // internal pull-down
		while((PINB&(1<<PB2))==0){} // hang while LOW
		PORTB=(1<<PB0); // TTL ON
		PORTB&=~(1<<PB0); // TTL OFF

Here’s the batch script I used to compile and load the code onto the microcontroller. I compiled the code with AVR-GCC and copied it onto the microcontroller with a Bus Pirate. Note also that I’m setting the fuses to respect an external oscillator.

@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex
avrdude -c buspirate -p attiny85 -P com3 -U lfuse:w:0xff:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m

If you have any ideas for how this could device could have been better designed or constructed, let me know!


Bodge note: After a few days I got an email from someone concerned about the current handling capability of the front-end of the circuit. It was noted that a standard 1/4 watt resistor may not be suitable for R1, as a 28V potential would stress it beyond its specs. With 28V applied, R1 (a quarter-watt resistor) would experience P=IE=28mA*28V=784mW of current! It might last (especially if pulsed), but it also might fail with time. The advantage of the R1/D1/R2 system is that the output current will be identical across a wide range of input voltages. The disadvantage is that it’s hard to predict how beefy R1 needs to be. I could have placed five 4.7k resistors in parallel to replace R1 (this would let me handle over 1 watt of power), but I instead simply upped it from 1kOhm to 10kOhm. This further reduced the current that the opto-isolator sees (now only about 0.2 mA) but it seems to work still! So I’m satisfied with this bodge, but a little disappointed I didn’t catch it sooner. Note that the new input resistor (a 10k R1) should only have to dissipate about 80mW, well within its specs.

the bodge is the 10k resistor on the lower right
the bodge is the 10k resistor at the very bottom

Note regarding H11B1 minimum current and AC noise: After pondering it for a while, I considered that a 10K input resistor on 28V would only allow 2.8 mA to pass through. Considering only 3.3V will persist after the zener (a 11.7% current retaining ratio, if that’s valid math), I figured that a best 330uA were passing through the opto-isolator. That seems outside of the specs of the device, because their datasheet graphs always start at 1mA. I decided to run some tests at my home for kicks. I determined that a 10k resistor still works with 5V (500 uA into the device), but checking the output on the oscilloscope I realized that the device operates only partially, and slowly at that low voltage/current. The darlington transistor configuration is very high gain, which is the only reason this works at all, but such low currents are sensitive to parasitic capacitance and infiltrating RF currents. As such, I noticed the chip took a few ms to activate and deactivate. Since this application only uses 5s on and 5s off inputs, it’s fine… but I wouldn’t expect highspeed pulsing of the input to work well. Furthermore, in my breadboard I realized I was getting funny output currents. They were oscillating around 60Hz, which made me suspicious that the device was picking up AC somehow. I realized it was from pin 6 (the exposed darlington base). Normally the LED is so strong is blasts the device fully on or off, but hovering on the edge like this, that pin is picking up signals. Since it’s not connected to anything anyway, I cut the pin off as close to the microchip as I could, and noticed an instant improvement in 60Hz rejection. In conclusion, I wouldn’t try to reliably run an optoisolator on less than 1 mW, but it seems to work!


Realtime Audio Visualization in Python

Python’s “batteries included” nature makes it easy to interact with just about anything… except speakers and a microphone! As of this moment, there still are not standard libraries which which allow cross-platform interfacing with audio devices. There are some pretty convenient third-party modules, but I hope in the future a standard solution will be distributed with python. I appreciate the differences of Linux architectures such as ALSA and OSS, but toss in Windows and MacOS in the mix and it gets to be a huge mess. For Linux, would I even need anything fancy? I can run “cat file.wav > /dev/dsp” from a command prompt to play audio. There are some standard libraries for operating system specific sound (i.e., winsound), but I want something more versatile. The official audio wiki page on the subject lists a small collection of third-party platform-independent libraries. After excluding those which don’t support microphone access (the ultimate goal of all my poking around in this subject), I dove a little deeper into sounddevice and PyAudio. Both of these I installed with pip (i.e., pip install pyaudio)

For a more modern, cleaner, and more complete GUI-based viewer of realtime audio data (and the FFT frequency data), check out my Python Real-time Audio Frequency Monitor project.

I really like the structure and documentation of sounddevice, but I decided to keep developing with PyAudio for now. Sounddevice seemed to take more system resources than PyAudio (in my limited test conditions: Windows 10 with very fast and modern hardware, Python 3), and would audibly “glitch” music as it was being played every time it attached or detached from the microphone stream. I tried streaming, but after about an hour I couldn’t get clean live access to the microphone without glitching audio playback. Furthermore, every few times I ran this script it crashed my python kernel! I very rarely see this happening. iPython complained: “It seems the kernel died unexpectedly. Use ‘Restart kernel’ to continue using this console” and I eventually moved back to PyAudio. For a less “realtime” application, sounddevice might be a great solution. Here’s the minimal case sounddevice script I tested with (that crashed sometimes). If you have a better one to do live high-speed audio capture, let me know!

import sounddevice #pip install sounddevice

for i in range(30): #30 updates in 1 second
    rec = sounddevice.rec(44100/30)

Here’s a simple demo to show how I get realtime microphone audio into numpy arrays using PyAudio. This isn’t really that special. It’s a good starting point though. Note that rather than have the user define a microphone source in the python script (I had a fancy menu system handling this for a while), I allow PyAudio to just look at the operating system’s default input device. This seems like a realistic expectation, and saves time as long as you don’t expect your user to be recording from two different devices at the same time. This script gets some audio from the microphone and shows the values in the console (ten times).

import pyaudio
import numpy as np

CHUNK = 4096 # number of data points to read at a time
RATE = 44100 # time resolution of the recording device (Hz)

p=pyaudio.PyAudio() # start the PyAudio class,channels=1,rate=RATE,input=True,
              frames_per_buffer=CHUNK) #uses default input device

# create a numpy array holding a single read of audio data
for i in range(10): #to it a few times just to see
    data = np.fromstring(,dtype=np.int16)

# close the stream gracefully


I tried to push the limit a little bit and see how much useful data I could get from this console window. It turns out that it’s pretty responsive! Here’s a slight modification of the code, made to turn the console window into an impromptu VU meter.

import pyaudio
import numpy as np

CHUNK = 2**11
RATE = 44100


for i in range(int(10*44100/1024)): #go for a few seconds
    data = np.fromstring(,dtype=np.int16)
    print("%04d %05d %s"%(i,peak,bars))


The results are pretty good! The advantage here is that no libraries are required except PyAudio. For people interested in doing simple math (peak detection, frequency detection, etc.) this is a perfect starting point. Here’s a quick cellphone video:

I’ve made realtime audio visualization (realtime FFT) scripts with Python before, but 80% of that code was creating a GUI. I want to see data in real time while I’m developing this code, but I really don’t want to mess with GUI programming. I then had a crazy idea. Everyone has a web browser, which is a pretty good GUI… with a Python script to analyze audio and save graphs (a lot of them, quickly) and some JavaScript running in a browser to keep refreshing those graphs, I could get an idea of what the audio stream is doing in something kind of like real time. It was intended to be a hack, but I never expected it to work so well! Check this out…

Here’s the python script to listen to the microphone and generate graphs:

import pyaudio
import numpy as np
import pylab
import time

RATE = 44100
CHUNK = int(RATE/20) # RATE / number of updates per second

def soundplot(stream):
    data = np.fromstring(,dtype=np.int16)
    print("took %.02f ms"%((time.time()-t1)*1000))

if __name__=="__main__":
    for i in range(int(20*RATE/CHUNK)): #do this for 10 seconds

Here’s the HTML file with JavaScript to keep reloading the image… 

<script language="javascript">
function RefreshImage(){
document.pic0.src="03.png?a=" + String(Math.random()*99999999);
<body onload="RefreshImage()">
<img name="pic0" src="03.png">

Here’s the result! I couldn’t believe my eyes. It’s not elegant, but it’s kind of functional!

Why stop there? I went ahead and wrote a microphone listening and processing class which makes this stuff easier. My ultimate goal hasn’t been revealed yet, but I’m sure it’ll be clear in a few weeks. Let’s just say there’s a lot of use in me visualizing streams of continuous data. Anyway, this class is the truly terrible attempt at a word pun by merging the words “SWH”, “ear”, and “Hear”, into the official title “SWHear” which seems to be unique on Google. This class is minimal case, but can be easily modified to implement threaded recording (which won’t cause the rest of the functions to hang) as well as mathematical manipulation of data, such as FFT. With the same HTML file as used above, here’s the new python script and some video of the output:

import pyaudio
import time
import pylab
import numpy as np

class SWHear(object):
    The SWHear class is made to provide access to continuously recorded
    (and mathematically processed) microphone data.

    def __init__(self,device=None,startStreaming=True):
        """fire up the SWHear class."""
        print(" -- initializing SWHear")

        self.chunk = 4096 # number of data points to read at a time
        self.rate = 44100 # time resolution of the recording device (Hz)

        # for tape recording (continuous "tape" of recent audio)
        self.tapeLength=2 #seconds

        self.p=pyaudio.PyAudio() # start the PyAudio class
        if startStreaming:

    # pure access to microphone and stream operations
    # keep math, plotting, FFT, etc out of here.

    def stream_read(self):
        """return values for a single chunk"""
        data = np.fromstring(,dtype=np.int16)
        return data

    def stream_start(self):
        """connect to the audio device and start a stream"""
        print(" -- stream started"),channels=1,

    def stream_stop(self):
        """close the stream but keep the PyAudio instance alive."""
        if 'stream' in locals():
        print(" -- stream CLOSED")

    def close(self):
        """gently detach from things."""

    # tape is like a circular magnetic ribbon of tape that's continously
    # recorded and recorded over in a loop. self.tape contains this data.
    # the newest data is always at the end. Don't modify data on the type,
    # but rather do math on it (like FFT) as you read from it.

    def tape_add(self):
        """add a single chunk to the tape."""

    def tape_flush(self):
        """completely fill tape with new data."""
        print(" -- flushing %d s tape with %dx%.2f ms reads"%\
        for i in range(readsInTape):

    def tape_forever(self,plotSec=.25):
            while True:
                if (time.time()-t1)>plotSec:
            print(" ~~ exception (keyboard?)")

    def tape_plot(self,saveAs="03.png"):
        """plot what's in the tape."""
        if saveAs:
            print("plotting saving took %.02f ms"%((time.time()-t1)*1000))
            print() #good for IPython

if __name__=="__main__":

I don’t really intend anyone to actually do this, but it’s a cool alternative to recording a small portion of audio, plotting it in a pop-up matplotlib window, and waiting for the user to close it to record a new fraction. I had a lot more text in here demonstrating real-time FFT, but I’d rather consolidate everything FFT related into a single post. For now, I’m happy pursuing microphone-related python projects with PyAudio.



Controlling Bus Pirate with Python

After using the AVR-ISP mkII for years (actually the cheap eBay knock-offs) to program ATMEL AVR microcontrollers, today I gave the Bus Pirate a shot. Far more than just a microcontroller programmer, this little board is basically a serial interface to basic microcontroller peripherals. In a nutshell, you plug it in via USB and it looks like a serial port which has a command-line interface that lets you do things like turn pins on and off, perform voltage measurements, and it naively supports bidirectional use of common protocols like I2C, SPI, UART, and even HD44780 series LCDs. Note that although you could directly interface with the Bus Pirate using HyperTerminal, I recommend using TeraTerm. It can supply voltages (3.3V and 5V) to power small circuits, and if current draw is too high (indicating something is hooked-up wrong) it automatically turns the supply off. So clever! At <$30, it’s a cool tool to have around. In addition, it’s naively supported as an AVR programmer by AVRDUDE. Although I could write assembly to perform tasks, I almost always write in C for the convenience. For my reference (and that of anyone who may want to do something similar), I’m posting the simplest-case method I use to program AVR microcontrollers with the Bus Pirate on Windows (noting that Linux would be nearly identical). I also wrote a Python script to connect with the Bus Pirate and run simple commands (which turns the power supply on and report the voltage of the VCC line immediately after programming completes).  Yes, there are fancy packages that allow you to interact with Bus Pirate from Python, but the advantage of my method is that it runs from native Python libraries! To get this all up and running for yourself, just install WinAVR (which supplies AVRDUDE and AVR-GCC) and Python 3. I assume this code will work just as well on Python 2, but haven’t tried.

IMG_7092 (1)
the Bus Pirate programming an ATTiny85 microcontroller


To ensure my Bus Pirate is working properly, I start off by running the Bus Pirate’s built-in test routine. For full details read the guide. It just involves connecting two pairs of pins together as shown in the picture here, connecting to the Bus Pirate with the serial terminal, and running the command “~”. It will output all sorts of useful information. Once I know my hardware is up and running, I’m good to continue.


Here’s the code which runs on the microcontroller to twiddle all the pins (saved as main.c). Note that my MCU is an ATTiny85. I’m using standard clock settings (internal RC clock, 8MHz), but if I wanted to modify fuses to do things like use an external clock source or crystal, I’d calculate them with engbedded’s handy dandy fuse calculator (which also shows AVRdude arguments needed to make the change!).

#define	F_CPU (8000000UL)
#include <avr/io.h>
#include <util/delay.h>

int main (void)
    DDRB = 255; 
        PORTB ^= 255;

To compile the code and program the MCU with it, I always have a bash script in the same folder that I can double-click on to delete old compiled files (so we don’t accidentally re-program our MCU with old code), compile main.c, and load it onto the MCU using the Bus Pirate. You may have to change COM3 to reflect the com port of your Bus Pirate. Note that it is required that you disconnect other terminals from the Bus Pirate before doing this, otherwise you’ll get an “access denied” error.

@echo off
del *.elf
del *.hex
avr-gcc -mmcu=attiny85 -Wall -Os -o main.elf main.c
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c buspirate -p attiny85 -P com3 -e -U flash:w:main.hex

Although the programmer briefly supplies my MCU with power from the +5V pin, it’s cut after programming completes. Rather than manually re-opening my terminal program, re-connecting with the bus pirate, re-setting the mode (command “m”) to something random (DIO, command “9”), and re-enableing voltage output (command “W”) just to see my LED blink, I want all that to be automated. Thanks python for making this easy. The last line calls “”. This fancy script even outputs the voltage of the VCC line after it’s turned on!

"""python3 control of buspirate ("""

import serial

BUSPIRATE_PORT = 'com3' #customize this! Find it in device manager.

def send(ser,cmd):
    """send the command and listen to the response."""
    ser.write(str(cmd+'\n').encode('ascii')) # send our command
    for line in ser.readlines(): # while there's a response
        print(line.decode('utf-8').strip()) # show it

ser=serial.Serial(BUSPIRATE_PORT, 115200, timeout=1) # is com free?
assert ser.isOpen() #throw an exception if we aren't connected
send(ser,'#') # reset bus pirate (slow, maybe not needed)
send(ser,'m') # change mode (goal is to get away from HiZ)
send(ser,'9') # mode 9 is DIO
send(ser,'W') # turn power supply to ON. Lowercase w for OFF.
send(ser,'v') # show current voltages
ser.close() # disconnect so we can access it from another app
print("disconnected!") # let the user know we're done.

When “burn.cmd” is run, the code is compiled and loaded, the power supply is turned on (and killed if too much current is drawn!), and the voltage on VCC is reported. The output is:

C:\Users\scott\Documents\important\AVR\2016-07-13 ATTiny85 LEDblink>burn.cmd

Detecting BusPirate...
**  Bus Pirate v3a
**  Firmware v5.10 (r559)  Bootloader v4.4
**  DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
BusPirate: using BINARY mode
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.12s

avrdude: Device signature = 0x1e930b
avrdude: erasing chip
avrdude: reading input file "main.hex"
avrdude: input file main.hex auto detected as Intel Hex
avrdude: writing flash (84 bytes):

Writing | ################################################## | 100% 3.12s

avrdude: 84 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex auto detected as Intel Hex
avrdude: input file main.hex contains 84 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 2.72s

avrdude: verifying ...
avrdude: 84 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.


Bus Pirate v3a
Firmware v5.10 (r559)  Bootloader v4.4
DEVID:0x0447 REVID:0x3046 (24FJ64GA002 B8)
1. HiZ
2. 1-WIRE
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

Power supplies ON
1.(BR)  2.(RD)  3.(OR)  4.(YW)  5.(GN)  6.(BL)  7.(PU)  8.(GR)  9.(WT)  0.(Blk)
GND     3.3V    5.0V    ADC     VPU     AUX     CLK     MOSI    CS      MISO
P       P       P       I       I       I       I       I       I       I
GND     3.17V   5.00V   0.00V   0.00V   L       L       L       H       L

This is a minimal-case scenario, but can be obviously expanded to perform some complicated tasks! For example, all commands could be run from a single python program. Considering the Bus Pirate’s ability to communicate with so many different protocols (I2C, 2-write, etc.), being able to naively control it from Python without having to install special additional libraries will certainly prove to be convenient.

PS: I noted there is a surprising delay when initializing programming the AVR with the bus pirate. The process hangs for about 10 seconds after the bus pirate introduces itself with the welcome message, then seems to resume at full speed writing to the flash of the microchip. After a bit of Googling, I believe the delay is due to the Bus Pirate slowly bit-banging SPI to initialize the programming sequence. The AVR has rich SPI functionality, some of which involves its own programming. Satisfied with this answer for now, I’m not going to try to speed it up. It’s a little annoying, but not too bad that I won’t use this to program my AVRs.


Festivus Pole Video Game

strikeDecember 23 is Festivus! To commemorate the occasion, I have built a traditional Festivus pole with a couple added features. To my knowledge, this is the first electronic Festivus pole on the internet. fullFor those of you unfamiliar, Festivus is a holiday comically celebrated as an alternative to the pressures of commercialism commonly associated with other winter holidays. Originating from the 1997 Seinfeld episode “The Strike”, the traditions of Festivus include demonstrating feats of strength, declaring common occurrences as Festivus miracles, airing of grievances, and of course the fabrication of a Festivus pole. Over the years various Festivus poles (often made of beer cans) have been erected in government buildings alongside the nativity scene and menorah, including this year in my home state Florida (the video is a good laugh). Here, I show a Festivus pole I made made from individually illuminated diet coke cans which performs as a simple video game, controlled by a single button. The illuminated can scrolls up and down, and the goal is to push the button when the top can is lit. If successful, the speed increases, and the game continues! It’s hours of jolly good fun.

After playing at my workbench for a while, I figured out a way I could light-up individual coke cans. I drilled a dozen holes in each can (with a big one in the back), stuck 3 blue LEDs (wired in parallel with a 220-ohm current limiting resistor in series) in the can, and hooked it up to 12V. This was the motivation I needed to continue…

Now for the design. I found a junk box 12V DC wall-wart power supply which I decided to commandeer for this project. Obviously a microcontroller would be the simplest way to implement this “game”, and I chose to keep things as minimal as possible. I used a single 8-pin ATMEL ATTiny85 microcontroller ($1.67) which takes input from 1 push-button and sends data through two daisy-chained 74hc595 shift-registers ($0.57) to control base current of 2n3904 transistors ($.019) to illuminate LEDs which I had on hand (ebay, 1000 3mm blue LEDs, $7.50 free shipping). A LM7805 linear voltage regulator ($0.68) was used to bring the 12V to 5V, palatable for the microcontroller. Note that all prices are for individual units, and that I often buy in bulk from cheap (shady) vendors, so actual cost of construction was less.

festivus pole video game schematic

To build the circuit, I used perf-board and all through-hole components. It’s a little messy, but it gets the job done! Admire the creative resistor hops connecting shift registers and microcontroller pins. A purist would shriek at such construction, but I argue its acceptability is demonstrated in its functionality.

The installation had to be classy. To stabilize the fixture, I used epoxy resin to cement a single coke can to an upside-down Pyrex dish (previously used for etching circuit boards in ferric chloride). I then used clear packaging tape to hold each successive illuminated can in place. All wires were kept on the back side of the installment with electrical tape. Once complete, the circuit board was placed beneath the Pyrex container, and the controller (a single button in a plastic enclosure connected with a telephone cord) was placed beside it.

It’s ready to play! Sit back, relax, and challenge your friends to see who can be the Festivus pole video game master!

A few notes about the code… The microcontroller ran the following C code (AVR-GCC) and is extremely simple. I manually clocked the shift registers (without using the chip’s serial settings) and also manually polled for the button press (didn’t even use interrupts). It’s about as minimal as it gets! What improvements could be made to this Festivus hacking tradition? We will have to wait and see what the Internet comes up with next year…


#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/delay.h>

// PB2 data
// PB1 latch
// PB0 clock
// PB4 LED

// PB3 input button

volatile int speed=400;
volatile char canlit=0;
volatile char levelsWon=0;

char buttonPressed(){
	char state;
	state = (PINB>>PB3)&1;
	if (state==0) {
		return 1;
	else {
		return 0;

void shiftBit(char newval){
	// set data value
	if (newval==0){PORTB&=~(1<<PB2);}
	else {PORTB|=(1<<PB2);}
	// flip clock

void allOff(){
	char i=0;

void allOn(){
	char i=0;

void onlyOne(char pos){
	if (pos>=8) {pos++;}
	char i;
	for (i=0;i<pos;i++){shiftBit(0);}
	//if (pos>8) {shiftBit(0);} // because we skip a shift pin

void updateDisplay(){PORTB|=(1<<PB1);PORTB&=~(1<<PB1);}

void ledON(){PORTB|=(1<<PB4);}
void ledOFF(){PORTB&=~(1<<PB4);}

char giveChance(){
	int count=0;
		if (buttonPressed()){return 1;}
	return 0;

void strobe(){
	char i;

char game(){
			if (giveChance()) {return;}
			if (giveChance()) {return;}

void levelWin(){
	char i;
void levelLose(){
	char i;

void showSelected(){
	char i;

void nextLevel(){
	// we just pushed the button.
	if (canlit==14) {
	else {

int main(void){
	char i;

Programming: note that the code was compiled and programmed onto the AVR from a linux terminal using AvrDude. The shell script I used for that is here:

rm main
rm *.hex
rm *.o
echo "MAKING O"
avr-gcc -w -Os -DF_CPU=1000000UL -mmcu=attiny85 -c -o main.o main.c
avr-gcc -w -mmcu=attiny85 main.o -o main
echo "COPYING"
avr-objcopy -O ihex -R .eeprom main main.hex
avrdude -c usbtiny -p t85 -F -U flash:w:"main.hex":a -U lfuse:w:0x62:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
echo "DONE"


Epoch Timestamp Hashing

I was recently presented with the need to rename a folder of images based on a timestamp. This way, I can keep saving new files in that folder with overlapping filenames (i.e., 01.jpg, 02.jpg, 03.jpg, etc.), and every time I run this script all images are prepended with a timestamp. I still want the files to be sorted alphabetically, which is why an alphabetical timestamp (rather than a random hash) is preferred.

  • At first I considered a long date such as 2014-04-19-01.jpg, but that adds so much text!
    …also, it doesn’t include time of day.
  • If I include time of day, it becomes 2014-04-19-09-16-23-01.jpg
  • If I eliminate dashes to shorten it, it becomes hard to read, but might work 140419091623-01.jpg
  • If I use Unix Epoch time, it becomes 1397912944-01.jpg

The result I came up with uses base conversion and a string table of numbers and letters (in alphabetical order) to create a second-respecting timestamp hash using an arbitrary number of characters. For simplicity, I used 36 characters: 0-9, and a-z. I then wrote two functions to perform arbitrary base conversion, pulling characters from the hash. Although I could have nearly doubled my available characters by including the full ASCII table, respecting capitalization, I decided to keep it simple. The scheme goes like this:

  • Determine the date / time: 19-Apr-2014 13:08:55
  • Create an integer of Unix Epoch time (seconds past Jan 1, 1970):  1397912935
  • Do a base conversion from a character list: n4a4iv
  • My file name now becomes n4a4iv-01.jpg – I can accept this!
    and when I sort the folder alphabetically, they’re in order by the timestamp

I can now represent any modern time, down to the second, with 6 characters. Here’s some example output:

19-Apr-2014 13:08:55 <-> 1397912935 <-> n4a4iv
19-Apr-2014 13:08:56 <-> 1397912936 <-> n4a4iw
19-Apr-2014 13:08:57 <-> 1397912937 <-> n4a4ix
19-Apr-2014 13:08:58 <-> 1397912938 <-> n4a4iy
19-Apr-2014 13:08:59 <-> 1397912939 <-> n4a4iz
19-Apr-2014 13:09:00 <-> 1397912940 <-> n4a4j0
19-Apr-2014 13:09:01 <-> 1397912941 <-> n4a4j1
19-Apr-2014 13:09:02 <-> 1397912942 <-> n4a4j2
19-Apr-2014 13:09:03 <-> 1397912943 <-> n4a4j3
19-Apr-2014 13:09:04 <-> 1397912944 <-> n4a4j4

Interestingly, if I change my hash characters away from the list of 36 alphanumerics and replace it with just 0 and 1, I can encode/decode the date in binary:

19-Apr-2014 13:27:28 <-> 1397914048 <-> 1010011010100100111100111000000
19-Apr-2014 13:27:29 <-> 1397914049 <-> 1010011010100100111100111000001
19-Apr-2014 13:27:30 <-> 1397914050 <-> 1010011010100100111100111000010
19-Apr-2014 13:27:31 <-> 1397914051 <-> 1010011010100100111100111000011
19-Apr-2014 13:27:32 <-> 1397914052 <-> 1010011010100100111100111000100
19-Apr-2014 13:27:33 <-> 1397914053 <-> 1010011010100100111100111000101
19-Apr-2014 13:27:34 <-> 1397914054 <-> 1010011010100100111100111000110
19-Apr-2014 13:27:35 <-> 1397914055 <-> 1010011010100100111100111000111
19-Apr-2014 13:27:36 <-> 1397914056 <-> 1010011010100100111100111001000
19-Apr-2014 13:27:37 <-> 1397914057 <-> 1010011010100100111100111001001

Here’s the code to generate / decode Unix epoch timestamps in Python:

#hashchars='01' #for binary

def epochToHash(n):
  while n>0:
    hash = hashchars[int(n % len(hashchars))] + hash
    n = int(n / len(hashchars))
  return hash

def epochFromHash(s):
  for pos in range(len(s)):
  return epoch

import time
for i in range(10):
  print(time.strftime("%d-%b-%Y %H:%M:%S", time.gmtime(t)),
              "<->", t,"<->",epochToHash(t))


Directly Driving 7-Segment Display with AVR IO Pins

I came across the need for a quick and dirty display to show a 4 digit number from a microcontroller. The right way to do this would be to use a microcontroller in combination with a collection of transistors and current limiting resistors, or even a dedicated 7-segment LED driver IC. The wrong way to do this is to wire LEDs directly to microcontroller IO pins to source and sink current way out of spec of the microcontroller… and that’s exactly what I did! With no current limiting resistors, the AVR is sourcing and sinking current potentially far out of spec for the chip. But, heck, it works! With 2 components (just a microcontroller and a 4 digit, 7-segment LED display) and a piece of ribbon cable, I made something that used to be a nightmare to construct (check out this post from 3 years ago when I accomplished the same thing with a rats nest of wires – it was so much work that I never built one again!) The hacked-together method I show today might not be up to spec for medical grade equipment, but it sure works for my test rig application, and it’s easy and cheap to accomplish… as long as you don’t mind breaking some electrical engineering rules. Consider how important it is to know how to hack projects like this together: Although I needed this device, if it were any harder, more expensive, or less convenient to build, I simply wouldn’t have built it! Sometimes hacking equipment together the wrong way is worth it.

Segments are both current sourced and sunk directly from AVR IO pins. Digits are multiplexed with 1ms illumination duration. I don’t really have a part number for the component because it was a China eBay special. The display was $6.50 for 4 (free shipping). That’s ~$1.65 each. The microcontroller is ~$1.

SCHEMATIC? If you want it, read this.common cathode 7 segment display lcd It’s so simple I don’t feel like making it. Refer to an ATMega48 pin diagram. The LCD is common anode (not common cathode), and here’s the schematic on the right. I got it from eBay (link) for <$2.  The connections are as follows:

  • Segments (-) A…H are directly wired to PD0…PD7
    – I call the decimal point (dp) segment “H”
    – I don’t use current limiting resistors. I’m not making a consumer product. It works fine, especially multiplexed. Yeah I could use transistors and CLRs to drive the segments to have them bright and within current specifications, but I’m not building an airplane or designing a pacemaker, I’m making a test device at minimum cost! Direct LED wiring to my microcontroller is fine for my purposes.
    – I am multiplexing the characters of my display. I could have used a driver IC to simplify my code and eliminate the current / wiring issues described above. A MAX7219 or MAX7221 would have been easy choices for this (note common anode vs. common cathode drivers / displays). It adds an extra $5 to my project cost though, so I didn’t go with a driver. I drove the segments right out of my IO pins.
  • Characters (+) 1…4 are PC0…PC3
  • Obviously I apply +5V and GND to the appropriate AVR pins

Here it all is together in my microcontroller programming set up. I’ll place this device in a little enclosure and an an appropriate BNC connector and either plan on giving it USB power or run it from 3xAA batteries. For now, it works pretty darn well on the breadboard.

Here is my entire programming setup. On the top left is my eBay special USB AVR programmer. On the right is a little adapter board I made to accomodate a 6 pin ISP cable and provide a small breadboard for adding programming jumpers into a bigger breadboard. The breadboard at the bottom houses the microcontroller and the display. No other components! Well, okay, a 0.1uF decoupling capacitor to provide mild debouncing for the TTL input.
Here is my entire programming setup. On the top left is my eBay special USB AVR programmer. On the right is a little adapter board I made to accomodate a 6 pin ISP cable and provide a small breadboard for adding programming jumpers into a bigger breadboard. The breadboard at the bottom houses the microcontroller and the display. No other components! Well, okay, a 0.1uF decoupling capacitor to provide mild debouncing for the TTL input.

Let’s talk about the code. Briefly, I use an infinite loop which continuously displays the value of the volatile long integer “numba”. In the display function, I set all of my segments to (+) then momentarily provide a current sink (-) on the appropriate digit anode for 1ms. I do this for each of the four characters, then repeat. How is the time (the value of “numba”) incremented? Using a hardware timer and its overflow interrupt! It’s all in the ATMega48 datasheet, but virtually every microcontroller has some type of timer you can use to an equivalent effect. See my earlier article “Using Timers and Counters to Clock Seconds” for details. I guess that’s pretty much it! I document my code well enough below that anyone should be able to figure it out. The microcontroller is an ATMega48 (clocked 8MHz with an internal RC clock, close enough for my purposes).

#define F_CPU 8000000UL // 8mhz
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

// for simplicity, define pins as segments
#define A (1<<PD0)
#define B (1<<PD1)
#define C (1<<PD2)
#define D (1<<PD3)
#define E (1<<PD4)
#define F (1<<PD5)
#define G (1<<PD6)
#define H (1<<PD7)

void setDigit(char dig){ // set the digit starting at 0
	PORTC=(1<<dig)|(1<<PC4); // always keep the PC4 pin high

void setChar(char c){
	// given a number, set the appropraite segments
		case 0:	DDRD=A|B|C|D|E|F;	break;
		case 1:	DDRD=B|C;			break;
		case 2:	DDRD=A|B|G|E|D;		break;
		case 3: DDRD=A|B|G|C|D;		break;
		case 4: DDRD=F|G|B|C;		break;
		case 5: DDRD=A|F|G|C|D;		break;
		case 6: DDRD=A|F|G|E|C|D;	break;
		case 7: DDRD=A|B|C;			break;
		case 8: DDRD=A|B|C|D|E|F|G;	break;
		case 9: DDRD=A|F|G|B|C;		break;
		case 31: DDRD=H;			break;
		default: DDRD=0; 			break;

void flashNumber(long num){
	char i;

	for (i=0;i<4;i++){
		if (i==2){DDRD|=H;} // H is the decimal point
		_delay_ms(1); // time to leave the letter illuminated

volatile long numba = 0;
volatile long addBy = 1;

ISR(PCINT1_vect){ // state change on PC4
	if ((PINC&(1<<PC4))==0) {addBy=0;} // pause
	else {numba=0;addBy=1;} // reset to 0 and resume

	TCNT1=65536-1250; // the next overflow in 1/100th of a second
	numba+=addBy;	  // add 1 to the secound counter

int main(void)
	DDRC=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3); // set all characters as outputs
	DDRD=255;PORTD=0; 	// set all segments as outputs, but keep them low

	TCCR1B|=(1<<CS11)|(1<<CS10); // prescaler 64
	TIMSK1|=(1<<TOIE1); //Enable Overflow Interrupt Enable
	TCNT1=65536-1250;   // the next overflow in 1/100th of a second

	// note that PC4 (PCINT12) is an input, held high, and interrupts when grounded
	PCICR |= (1<<PCIE1); // enable interrupts on PCING13..8 -> PCI1 vector
	PCMSK1 |= (1<<PCINT12); // enable PCINT12 state change to be an interrupt
	sei(); // enable global interrupts

	for(;;){flashNumber(numba);} // just show the current number repeatedly forever

I edit my code in Notepad++ by the way. To program the chip, I use a bash script…

avr-gcc -mmcu=atmega48 -Wall -Os -o main.elf main.c -w
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avrdude -c usbtiny -p m48 -F -U flash:w:"main.hex":a -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m

Nothing here is groundbreaking. It’s simple, and convenient as heck. Hopefully someone will be inspired enough by this write-up that, even if they don’t recreate this project, they’ll jump at the opportunity to make something quick and dirty in the future. It’s another example that goes to show that you don’t have to draw schematics, run simulations, do calculations and etch boards to make quick projects. Just hack it together and use it.

Update a two days later… I found a similarly quick and dirty way to package this project in an enclosure. I had on hand some 85x50x21mm project boxes (eBay, 10 for $14.85, free shipping, about $1.50 each) so I used a nibbler to hack out a square to accomodate the display. After a little super glue, ribbon cable, and solder, we’re good to go!

Related reading for the technically inclined: