Articles typically receive this designation when the technology they describe is no longer relevant, code
provided is later deemed to be of poor quality, or the topics discussed are better presented in future
articles. Articles like this are retained for the sake of preservation, but their content should be
critically assessed.
December 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.
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.
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
volatileint speed=400;
volatilechar canlit=0;
volatilechar levelsWon=0;
charbuttonPressed(){
char state;
state = (PINB>>PB3)&1;
if (state==0) {
PORTB|=(1<<PB4);
return1;
}
else {
PORTB&=~(1<<PB4);
return0;
}
}
voidshiftBit(char newval){
// set data value
if (newval==0){PORTB&=~(1<<PB2);}
else {PORTB|=(1<<PB2);}
// flip clock
PORTB|=(1<<PB0);
PORTB&=~(1<<PB0);
}
voidallOff(){
char i=0;
for(i=0;i<16;i++){
shiftBit(0);
}
updateDisplay();
}
voidallOn(){
char i=0;
for(i=0;i<14;i++){
shiftBit(1);
}
updateDisplay();
}
voidonlyOne(char pos){
if (pos>=8) {pos++;}
char i;
allOff();
shiftBit(1);
for (i=0;i<pos;i++){shiftBit(0);}
//if (pos>8) {shiftBit(0);} // because we skip a shift pin
updateDisplay();
}
voidupdateDisplay(){PORTB|=(1<<PB1);PORTB&=~(1<<PB1);}
voidledON(){PORTB|=(1<<PB4);}
voidledOFF(){PORTB&=~(1<<PB4);}
chargiveChance(){
int count=0;
for(count=0;count<speed;count++){
_delay_ms(1);
if (buttonPressed()){return1;}
}
return0;
}
voidstrobe(){
char i;
for(i=0;i<50;i++){
allOn();_delay_ms(50);
allOff();_delay_ms(50);
}
}
chargame(){
for(;;){
for(canlit=1;canlit<15;canlit++){
onlyOne(canlit);
if (giveChance()) {return;}
}
for(canlit=13;canlit>1;canlit--){
onlyOne(canlit);
if (giveChance()) {return;}
}
}
}
voidlevelWin(){
char i;
for(i=0;i<levelsWon;i++){
allOn();
_delay_ms(200);
allOff();
_delay_ms(200);
}
}
voidlevelLose(){
char i;
for(i=0;i<20;i++){
for(canlit=13;canlit>1;canlit--){
onlyOne(canlit);
_delay_ms(10);
}
}
}
voidshowSelected(){
char i;
for(i=0;i<20;i++){
onlyOne(canlit);
_delay_ms(50);
allOff();
_delay_ms(50);
}
}
voidnextLevel(){
// we just pushed the button.
showSelected();
levelsWon++;
if (canlit==14) {
levelWin();
speed-=speed/5;
}
else {
levelLose();
speed=400;
levelsWon=0;
}
}
intmain(void){
DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB4);
char i;
for(;;){
game();
nextLevel();
}
}
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:
Articles typically receive this designation when the technology they describe is no longer relevant, code
provided is later deemed to be of poor quality, or the topics discussed are better presented in future
articles. Articles like this are retained for the sake of preservation, but their content should be
critically assessed.
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:
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:
Articles typically receive this designation when the technology they describe is no longer relevant, code
provided is later deemed to be of poor quality, or the topics discussed are better presented in future
articles. Articles like this are retained for the sake of preservation, but their content should be
critically assessed.
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.[/caption]
SCHEMATIC? If you want it, read this. 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.
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)
voidsetDigit(char dig){ // set the digit starting at 0
PORTC=(1<<dig)|(1<<PC4); // always keep the PC4 pin high
}
voidsetChar(char c){
// given a number, set the appropraite segments
switch(c){
case0: DDRD=A|B|C|D|E|F; break;
case1: DDRD=B|C; break;
case2: DDRD=A|B|G|E|D; break;
case3: DDRD=A|B|G|C|D; break;
case4: DDRD=F|G|B|C; break;
case5: DDRD=A|F|G|C|D; break;
case6: DDRD=A|F|G|E|C|D; break;
case7: DDRD=A|B|C; break;
case8: DDRD=A|B|C|D|E|F|G; break;
case9: DDRD=A|F|G|B|C; break;
case31: DDRD=H; break;
default: DDRD=0; break;
}
}
voidflashNumber(long num){
char i;
for (i=0;i<4;i++){
setChar(num%10);
if (i==2){DDRD|=H;} // H is the decimal point
setDigit(3-i);
num=num/10;
_delay_ms(1); // time to leave the letter illuminated
}
}
volatilelong numba =0;
volatilelong 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
}
ISR(TIMER1_OVF_vect){
TCNT1=65536-1250; // the next overflow in 1/100th of a second
numba+=addBy; // add 1 to the secound counter
}
intmain(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…
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!
Articles typically receive this designation when the technology they describe is no longer relevant, code
provided is later deemed to be of poor quality, or the topics discussed are better presented in future
articles. Articles like this are retained for the sake of preservation, but their content should be
critically assessed.
How long does a particular bit of Morse code take to transmit at a certain speed? This is a simple question, but when sitting down trying to design schemes for 10-minute-window QRSS, it doesn’t always have a quick and simple answer. Yeah, you could sit down and draw the pattern on paper and add-up the dots and dashes, but why do on paper what you can do in code? The following speaks for itself. I made the top line say my call sign in Morse code (AJ4VD), and the program does the rest. I now see that it takes 570 seconds to transmit AJ4VD at QRSS 10 speed (ten second dots), giving me 30 seconds of free time to kill.
Output of the following script, displaying info about “AJ4VD” (my call sign).
Here’s the Python code I whipped-up to generate the results:
xmit=" .- .--- ....- ...- -.. "#callsigndot,dash,space,seq="_-","_---","_",""for c in xmit:
if c==" ": seq+=space
elif c==".": seq+=dot
elif c=="-": seq+=dash
print"QRSS sequence:n",seq,"n"for sec in [1,3,5,10,20,30,60]:
tot=len(seq)*sec
print"QRSS %02d: %d sec (%.01f min)"%(sec,tot,tot/60.0)
__How ready am I to implement this in the microchip? __Pretty darn close. I’ve got a surprisingly stable software-based time keeping solution running continuously executing a “tick()” function thanks to hardware interrupts. It was made easy thanks to Frank Zhao’s AVR Timer Calculator. I could get it more exact by using a /1 prescaler instead of a /64, but this well within the range of acceptability so I’m calling it quits!
Output frequency is 1.0000210 Hz. That’ll drift 2.59 sec/day. I’m cool with that.
Today I rigineered my frequency counter to output frequency to a computer via a USB interface. You might remember that I did this exact same thing two years ago, but unfortunately I fell victim to accidental closed source. When I rigged it the first time, I stupidly tried to get fancy and add USB interface with V-USB requiring special drivers and special software code to retrieve the data. The advantage was that the microcontroller spoke directly to the PC USB port via 2 pins requiring no extra hardware. The stinky part is that I’ve since lost the software I wrote necessary to decode the data. Reading my old post, I see I wrote_ “Although it’s hard for me, I really don’t think I can release this [microchip code] right now. I’m working on an idiot’s guide to USB connectivity with ATMEL microcontrollers, and it would cause quite a stir to post that code too early.”_ Obviously I never got around to finishing it, and I’ve since lost the code. Crap! I have this fancy USB “enabled” frequency counter, but no ability to use it. NOTE TO SELF: NEVER POST PROJECTS ONLINE WITHOUT INCLUDING THE CODE! I guess I have to crack this open again and see if I can reprogram it…
My original intention was just to reprogram the IC and add serial USART support, then use a little FTDI adapter module to serve as a USB serial port. That will be supported by every OS on the planet out of the box. Upon closer inspection, I realized I previously used an ATMega48 which has trouble being programmed by AVRDUDE, so I whipped up a new perf-board based around an ATMega8. I copied the wires exactly (which was stupid, because I didn’t have it written down which did what, and they were in random order), and started attacking the problem in software.
The way the microcontroller reads frequency is via the display itself. There are multiplexed digits, so some close watching should reveal the frequency. I noticed that there were fewer connections to the microcontroller than expected - a total of 12. How could that be possible? 8 seven-segment displays should be at least 7+8=15 wires. What the heck? I had to take apart the display to remind myself how it worked. It used a pair of ULN2006A darlington transistor arrays to do the multiplexing (as expected), but I also noticed it was using a CD4511BE BCD-to-7-segment driver to drive the digits. I guess that makes sense. That way 4 wires can drive 7 segments. 8+4=12 wires, which matches up. Now I feel stupid for not realizing it in the first place. Time to screw things back together.
Here’s the board I made. 3 wires go to the FTDI USB module (GND, VCC 5V drawn from USB, and RX data), black wires go to the display, and the headers are to aid programming. I added an 11.0592MHz crystal to allow maximum serial transfer speed (230,400 baud), but stupidly forgot to enable it in code. It’s all boxed up now, running at 8MHz and 38,400 baud with the internal RC clock. Oh well, no loss I guess.
I wasted literally all day on this. It was so stupid. The whole time I was kicking myself for not posting the code online. I couldn’t figure out which wires were for the digit selection, and which were for the BCD control. I had to tease it apart by putting random numbers on the screen (by sticking my finger in the frequency input hole) and looking at the data flowing out on the oscilloscope to figure out what was what. I wish I still had my DIY logic analyzer. I guess this project was what I built it for in the first place! A few hours of frustrating brute force programming and adult beverages later, I had all the lines figured out and was sending data to the computer.
With everything back together, I put the frequency counter back in my workstation and I’m ready to begin my frequency measurement experiments. Now it’s 9PM and I don’t have the energy to start a whole line of experiments. Gotta save it for another day. At least I got the counter working again!
__Here’s the code that goes on the microcontroller __(it sends the value on the screen as well as a crude checksum, which is just the sum of all the digits)
#define F_CPU 8000000UL
#include<avr/io.h>#include<util/delay.h>#include<avr/interrupt.h>#define USART_BAUDRATE 38400
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
voidUSART_Init(void){
UBRRL = BAUD_PRESCALE;
UBRRH = (BAUD_PRESCALE >>8);
UCSRB = (1<<TXEN);
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // 9N1
}
voidUSART_Transmit( unsignedchar data ){
while ( !( UCSRA & (1<<UDRE)) );
UDR = data;
}
voidsendNum(int byte){
if (byte==0){
USART_Transmit(48);
}
while (byte){
USART_Transmit(byte%10+48);
byte-=byte%10;
byte/=10;
}
}
voidsendBin(int byte){
char i;
for (i=0;i<8;i++){
USART_Transmit(48+((byte>>i)&1));
}
}
volatilechar digits[]={0,0,0,0,0,0,0,0};
volatilechar freq=123;
chargetDigit(){
char digit=0;
if (PINC&0b00000100) {digit+=1;}
if (PINC&0b00001000) {digit+=8;}
if (PINC&0b00010000) {digit+=4;}
if (PINC&0b00100000) {digit+=2;}
if (digit==15) {digit=0;} // blank
return digit;
}
voidupdateNumbers(){
while ((PINB&0b00000001)==0){} digits[7]=getDigit();
while ((PINB&0b00001000)==0){} digits[6]=getDigit();
while ((PINB&0b00010000)==0){} digits[5]=getDigit();
while ((PINB&0b00000010)==0){} digits[4]=getDigit();
while ((PINB&0b00000100)==0){} digits[3]=getDigit();
while ((PINB&0b00100000)==0){} digits[2]=getDigit();
while ((PINC&0b00000001)==0){} digits[1]=getDigit();
while ((PINC&0b00000010)==0){} digits[0]=getDigit();
}
intmain(void){
USART_Init();
char checksum;
char i=0;
char digit=0;
for(;;){
updateNumbers();
checksum=0;
for (i=0;i<8;i++){
checksum+=digits[i];
sendNum(digits[i]);
}
USART_Transmit(',');
sendNum(checksum);
USART_Transmit('n');
_delay_ms(100);
}
}
__Here’s the Python code to listen to the serial port, though you could use any program __(note that the checksum is just shown and not verified):
This is super preliminary, but I’ve gone ahead and tested heating/cooling an oscillator (a microcontroller clocked with an external crystal and outputting its signal with CKOUT). By measuring temperature and frequency at the same time, I can start to plot their relationship…