Arduino Iambic Keyer 2016 – Part 3: Operation

Memory Keyer 2016

Arduino Iambic Keyer - Keyboard and Paddles

Arduino Iambic Keyer – Keyboard and Paddles


This describes the operation of an Arduino sketch and appropriate hardware that serves as an iambic morse code keyer. This version runs on a PJRC Teensy3.2 board and libraries. It will not compile to an Atmel (traditional Arduino) processor without major changes. I chose the Cortex M4 based Teensy because it has built in Real Time Clock, a real DAC, built in USB, and lots of memory. I added a 16×2 liquid crystal display and batteries for stand alone operation.


  1. Characters to be sent are buffered in an asynchronous circular queue so memory buttons or keyboard characters can be “typed ahead”.
  2. PS2 and serial terminal keyboards supported.
  3. Paddle generated morse is interpreted and printed as ASCII text.
  4. Seven 50 character memories. Each is programmable from keyboards or from paddles.
  5. Random code practice modes, letters only, letters and numbers, letters numbers and punctuation.
  6. Sending speed settable 10 to 45 WPM. Limits can be changed by recompiling.
  7. Sidetone frequency settable 100 to 1200 Hz. Limits can be changed by recompiling.
  8. Synthesized sine wave sidetone with leading and trailing edge envelope shaping.
  9. Memories and operating parameters stored in EEPROM, are easily reset to defaults.
  10. Stand alone operation from batteries. Based on tests, a 4400 MAH battery will last at least 36 hours.
  11. A Liquid Crystal Display.

Outside the Box

This keyer has five I/O connectors:

  1. A 3 conductor jack for the paddle or straight key.
  2. A 3 conductor jack for transmitter keying with an optocoupler open collector output on the tip. Line level sidetone audio is connected to the ring.
  3. An external speaker jack connected to a 2.5 watt audio amplifier.
  4. A mini DIN connector for PS2 keyboard. USB keyboards will work with an adapter.
  5. A micro USB port for programming and serial terminal connection. This also powers the unit and charges the battery.

There are eight push button switches, a volume control, and an LED:

  1. A Function button.
  2. Seven push buttons to activate individual memories.
  3. The volume control feeds a Class D amplifier for the speaker. It does not affect the level on the line output connection.
  4. The LED follows the transmit keying signal.

There is an on/off switch that also serves to reboot the processor into setup mode.

Liquid Crystal Displays have a limited space for messages so information has to be presented sequentially. Switching on power displays clock status then “Keyer Ready” is displayed on the LCD and on the serial port. The unit is then ready for normal operation.

Straight Key Operation

On power up, if the unit senses a two conductor plug in the paddle jack, it will go into Straight Key mode and just pass keying through to the transmit circuit, with side tone. Memories and other features are not available as the morse engine is never started.

Normal Iambic Operation

The dual paddle jack is wired dit paddle on tip, dah paddle on ring of the mini stereo connector. The external speaker jack will work with stereo headphones or a speaker. On the transmit jack, there is an open collector optocoupler connected to tip and line level side tone on the ring.

Software will attempt to translate paddle sent morse into ASCII which will display on the LCD and is also sent to the serial port. Decode success depends on how good your fist is. The keyer cannot decode morse received over the air.

Keyboard Operation

The keyer will accept and send characters entered from a PS2 keyboard or from a terminal emulator program such as PuTTY, or even the Arduino IDE serial window. It’s better to use an emulator that supports line at a time transmission as that gives you an opportunity to fix typing mistakes. Opening a terminal window on a USB connected PC also lets you view and log status messages sent from the keyer. PS2 support also works with a USB keyboard and appropriate USB to PS2 adapter.

All characters in the Wikipedia morse code table are supported except the underscore and the dollar sign. From either serial or PS2 keyboards, enter normal text in lower case. Entering text in upper case will suppress the next intercharacter gap, thus running two characters together. This can be used to send prosigns. For example, As (wait) or Sk (end of contact). Message text entered from the paddles will always be treated as all lower case.

Serial or PS2 keyboards use a one at a time command mode, activated by typing a back slash followed by a single character. Keyboard commands are:

  1. \+ or \= increase sending speed one Word Per Minute
  2. \- decrease sending speed one Word Per Minute
  3. \u increase sidetone frequency by 5%
  4. \d decrease sidetone frequency by 5%
  5. \w save current sidetone frequency and WPM to EEPROM memory
  6. \1, \2 … \7 send stored text as though a memory button was pressed.


Seven programmable 50 character memories are available by pressing buttons. The sketch uses a 64 byte circular buffer to queue sendable text from either keyboard or from EEPROM memory, the buffer is asynchronous so memory messages can be stacked with interspersed keyboard text. Memory messages are read as needed from EEPROM so each consumes only a single byte of circular buffer space. Memories can also be queued from the keyboards by entering commands \1 … \7.

Message memory can be programmed from compiled defaults, from either keyboard, or directly from the paddles if your sending is good which is useful in stand alone operation. To program a message into memory, press and hold the Function button, then press and release the desired memory button, then release Function. Enter your text from paddles or keyboard, then exit programing mode by clicking Function again.

Normal Operation Display

Operating parameters can be viewed on the LCD by holding the Function button. Parameters also print to the serial port. The rotating menu display will show:

  • Time and date both GMT and local
  • Sending speed and side tone frequency
  • Battery status
  • The first 16 characters of each programmable message.

Each item will be on the LCD for one second. Releasing Function stops menu rotation but does not erase the LCD which allows more time to read a particular display.

Changing Words Per Minute

Since speed may need to be adjusted according to conditions, there is a provision to change WPM on the fly. Just hold the Function button down and close a paddle. Dits increase speed, dahs decrease. On releasing Function, the changed speed writes to EEPROM.

You can also change speed from the keyboards by entering \+ to increase or \- to decrease. Entering \= will also increase WPM if you forgot to shift. If adjusting by keyboard, you must enter \w to write the new setting to EEPROM.

Changing Side Tone Frequency

This can be done from the keyboards by sending \u to raise frequency or \d to lower frequency. As with WPM, enter the command \w to save the change. Tone frequency can be set in stand alone operation from the Startup Menu described below.

Battery Status

Software constantly monitors battery voltage and the PowerBoost charger status signals. These can be seen in the operating display. Voltage is shown in hundredths with no decimal point. A fully charged battery will show about 4.20 volts, if the battery drops below 3.40 volts “LOW BATT” will show on the battery status and the LCD back light will flash. If voltage drops below the boost regulator LB threshold, about 3.25 volts the status display will show “DEAD BATT”.

Startup Mode

Arduino sketches have a separate startup() section for initializing things. It is executed once when the processor resets, just before entering the main event loop(). This keyer takes advantage of separate startup to recall and optionally change important system parameters. A normal power on sequence copies the following items from EEPROM to RAM:

  • Words Per Minute
  • Side Tone frequency
  • LCD Back light brightness
  • GMT – Local time offset

Memory messages are also stored in EEPROM but are not read into RAM. Startup then reads the Real Time Clock into the system clock.

Startup then checks to see if Code Practice mode (see below) is requested, if so, Code Practice begins as soon as the memory button is released.

Startup Menu

If Startup sees the Function button held down, it enters Startup Menu mode. Eight parameters rotate on the LCD, seven of these can be entered and changed.

  1. Sending speed Words Per Minute
  2. Side Tone frequency
  3. LCD Back light brightness
  4. System clock time (GMT)
  5. System date (also GMT)
  6. GMT – Local offset in hours
  7. Reset all stored parameters to defaults
  8. Display battery voltage and charge status

For Startup Menu purposes, three of the memory buttons are redefined. M5 is Enter, M6 is Up, M7 is Down. Click the Enter (M5) button while a menu item is on the display to activate change mode for that item. For the first three menu items and for GMT offset, Up (M6) and Down (M7) act directly on the displayed number.

Once entered, Time and Date can be set by repeatedly pressing the Enter button until the cursor is beneath the digit needing change. Once there Up and Down operate as expected. The RTC will be updated when the Time or Date menu is exited.

After a change, exit the menu item by pressing and holding Enter (M5) for longer than 2 seconds. Menu rotation will continue where it left off.

Entering menu 7 will reset all EEPROM stored parameters including the seven memory messages to defaults specified in the file “canned.h”. You can change these defaults by editing that file with the Arduino IDE and recompiling. Canned.h appears as one of the tabs at the top of the Arduino editor window.

The last Startup Menu display shows the current battery voltage and charge status. This information is also sent to the serial connection, at the menu rate of rotation, about five times per minute. A terminal emulator program like PuTTY or Minicom on the PC, can log these battery messages in a text file, you can later load the text into a spread sheet and with some amount of fussing create a charge or discharge curve for the battery. To get a discharge curve though you have to disable charging through the USB connection by cutting the red wire in the USB cable.

Startup Menu mode is exited by clicking the Function button again. Changed parameters will write to EEPROM and normal operation starts.

Synchronize the Real Time Clock

Internal system time is maintained by software in the PJRC libraries. System time is initialized at bootup from the crystal controlled, battery backed Real Time Clock inside the processor chip. You can hack set the RTC from the Startup Menu, but there is a way to synchronize the RTC with a PC clock over a USB serial connection. If the PC is itself synchronized with an Internet NTP server, the result will be within 1 or 2 seconds of WWV.

Accurate clock synchronization requires the Arduino sketch be ready to accept and process a time update at the exact moment the PC sends it. Connect the keyer to the PC with a USB cable, power up the keyer while holding the Function button down, then while the LCD displays “Enter Setup Mode”, paste the following Linux command into a shell;

date +T%s\n > /dev/ttyACM0

Release the Function button and the RTC synchronizes. There is a processing sketch included with the PJRC Time library that can be used to synchronize the clock from a Windows computer.

Code Practice Mode

Holding one of the first three memory buttons down on boot up puts the keyer in Code Practice Mode. Characters generated are based on tables in the Wikipedia article on Morse Code.

  • M1 Send letters only
  • M2 Send letters and numbers
  • M3 Send letters, numbers, and punctuation

Characters are sent in groups of five. If a serial terminal window is open it will display the sequential group number as well as the ASCII characters themselves.

Practice Mode Commands

In practice mode, the first four memory buttons adjust the delay between characters in increments of two element (dot width) times. M1 adjusts by zero, M2 by two, M3 by four, M4 by six elements giving a listener additional time to decode the sounds. Each step slows the average WPM by about 10 percent.

Pressing the M5 button pauses practice and the display back light will begin blinking. Pressing M5 again resumes but will likely have mutilated any character that was in progress. M6 increases sending speed and M7 lowers sending speed, one WPM per click. The changed speed is only effective until the keyer is reset, it is NOT written to EEPROM.

Display Mode

Normal Operating Displays are also available in Code Practice mode by pressing Function. The display will not start until the current five letter code group is completed.

Battery Status

If the battery voltage drops below 3.40 volts, the display back light will begin flashing.


Many thanks to Richard Chapman KC4IFB whose September 2009 QEX article provided the inspiration and base code for this sketch. His iambic keyer code feels exactly like my original WB4VVF Accukeyer. Also see Rarons Blog for a discussion of the tree method for decoding and encoding morse characters. It was very helpful in building efficient translation tables. The circular queue was implemented with help from examples at Paul Stoffregen encouraged me to try the Teensy3.2 on the PJRC forum.


Revision History

February 25, 2016       MemoryKeyerTeensy3.2_V1.0    Initial sketch
March 9, 2016             MemoryKeyerTeensy3.2_V1.1.0  Rework battery alarm logic, bug fixes.
March 16, 2016           MemoryKeyerTeensy3.2 V1.1.1   Workaround fix LCD does not have backslash in its font.



Still More Fun With Direct Digital Synthesis: TeensyLC with DAC

I posted a link to my previous page on setting up PWM Direct Digital Synthesized sine waves on PJRC’s Teensy 2.0, a 32u4 Arduino. Paul Stoffregen (the PJ in PJRC) commented that I should try porting my DDS demo sketch to a TeensyLC. “You won’t need PWM” he said. “Use the Digital Analog Converter” he said. I was a bit hesitant because TeensyLC has an ARM processor running at 48 Mhz. Quite a bit more power than the Atmel 16 Mhz chips and more I/O capability, so worth a look.  PJRC supplies an Arduino IDE add on called Teensyduino which configures support for PJRC boards so simply doing an analogWrite to pin A12 (took me a while to actually find A12) starts the DAC instead of starting PWM. Teensyduino has an included library IntervalTimer which sets a repetitive timer running and attaches that to an Interrupt Service Routine which you supply.  So an LC port should be simple as the dirty work of configuring the timer is taken care of.

Arduino PWM based DDS uses a fixed sample rate of 31 or 62 Khz and the interrupt generated sine wave has to fit into that constraint. That means low frequency audio tones are relatively smooth as there are lots of sample periods to go around even with the 256 step tables. High audio frequencies on the other hand, suffer distortion as the shorter period audio wave can’t fit in enough sample periods.

In the TeensyLC, the DAC always gets a fixed number of bits so you change the interrupt frequency to change the frequency of the generated audio tone. For instance, using the 256 step table, to generate a 1000 Hz tone requires 1000 * 256 interrupts per second. That’s about one every four microseconds, which even with the 48 Mhz processor clock, is going to use a LOT of CPU time. The shortest period I could set with IntervalTimer was 5 microseconds, my experiments with the demo program showed a maximum audio frequency of 650 Hz with the 256 step table, the 128 table limited at 1300 Hz, and the 64 step table maxed out at 2600 Hz.

Another down side to the DAC method stems from the fact that the audio frequency granularity is determined by the 1 microsecond granularity of the IntervalTimer function multiplied by the number of steps in the sine table.  The demo program shows this while sweeping. Low audio frequencies sweep smoothly but the higher frequencies have very noticeable jumps. Higher sine table sizes show this effect much more.

But the output wave form is much better than PWM. The following photos were shot using the Quarter Wave symmetry version of the demo sketch. Full table version traces were identical. All these were taken at a set audio frequency of 440 Hz. The filter was a single 10K resistor in series with the output pin, and a 0.01 ufd capacitor to ground. You can see the wave period changing a bit with the different table sizes. That is due to the granularity issue.

TeensyLC DAC Bottom - Raw, Top - Filtered 256 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
256 Step Table, Quarter Wave


TeensyLC DAC Bottom - Raw, Top - Filtered 128 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
128 Step Table, Quarter Wave


TeensyLC DAC Bottom - Raw, Top - Filtered 64 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
64 Step Table, Quarter Wave


TeensyLC DAC Bottom - Raw, Top - Filtered 32 Step Table, Quarter Wave

TeensyLC DAC Bottom – Raw, Top – Filtered
32 Step Table, Quarter Wave Symmetry


TeensyLC DAC Bottom - Raw, Top - Filtered 16 Step Table, Quarter Wave Symmetry

TeensyLC DAC Bottom – Raw, Top – Filtered
16 Step Table, Quarter Wave Symmetry

I will probably use the TeensyLC in my next version of morse keyer.  I have to find a 16×2 LCD that will work at 3.3 volts, figure out how to interface a 5 volt PS2 keyboard, and how to charge and connect a 5 volt battery pack. The LC (and the 32u4) have USB serial built in which will make interfacing a terminal window on a logging computer a lot easier.

I found a useful web page showing how you implement quarter wave sine symmetry DDS on an FPGA and I took this opportunity to streamline the quarter wave ISR. You have to be familiar with bit banging to understand it now.

The demo sketches, full table and quarter table versions, and the Libre spreadsheet I used to develop the quarter wave half step offset tables are included in the archive at:

More Fun With Direct Digital Synthesis: 32u4 and Fast PWM

32u4 Port

My 2015 winter project will be an expanded version of the Morse Code keyer I built last year. I now have a PJRC Teensy 2.0 controller board (from Sparkfun) to use. The Atmel 32u4 based Teensy 2.0 is even smaller than the Pro Minis I have been using. It is attractive because it has USB built in for program loading and serial transmission. And there’s lots of I/O pins available which will make an LCD easy to connect. I note that everybody making a 32u4 “Arduino” is defining a different pinout from the chip. The Adafruit Feather is quite ambitious, has it’s own IDE addon and can be bought with Bluetooth or WiFi  included.

This breadboard photo shows the Teensy 2.0 at top left, Sparkfun Pro Mini at center, Sparkfun RedBoard top right, and a MicroCenter Pro Mini clone at bottom right.



PJRC has ported many of the standard Arduino libraries to their 32u4 Teensy form factor and these are included in your Arduino IDE when you download and install the Teensyduino addon. But my keyer sketch uses Direct Digital Synthesis to form a nice sine wave side tone which requires direct setup of a Pulse Width Modulation timer inside the AVR chip. My implementation is based on code from Jeff Whitlatch, KO7M.  I used timer 2 in last winters UNO based keyer as that’s the timer that does tone() in the Arduino UNO and I completely superseded that function. Reading the data sheet on 32u4 shows that it doesn’t even *have* a timer 2. It has timer 0 (8 bit), timers 1 and 3 (16 bit), and timer 4 (10 bit). Digging into the Teensy Arduino libraries shows that PJRC is using timer 3 for tone() so I needed a port that just changed the timer used. Comparing the 32u4 data sheet with the Mega328 data sheet showed that the only difference besides the timer number would be in the Waveform Generation Mode bits. 32u4 has four WGM bits, Mega328 has 3. I used a mode setting that turns the 16 bit 32u4 timer 3 into an 8 bit timer and Success! The port was working in my test program.

Fast PWM

Phase Correct PWM in an AVR processor uses the timer in a manner that has it count from 0 to 255 then count back down to zero for each interrupt cycle. The PWM signal goes high on the way up and low on the way down. For an 8 bit counter, that’s 510 counts per cycle (read the data sheet to find out why it skips two) so with no clock scaling the sample rate is 16 MHz/510 or 31.4 KHz. In Fast PWM mode the timer counts from 0 to 255 then rolls over back to zero. A PWM wave on the output pin goes high on the way up and low on overflow. This results in some jitter on the PWM pulses but the sample rate is twice as fast, 16 MHz/256 or 62.5 KHz. I decided to try Fast PWM in the test program. It required only a change in the math that calculates the sample rate, and a slightly different set of WGM bits.

The following images show comparisons of the 31.4 KHz (Phase Correct) and the 62.5 KHz (Fast) rate tone waveforms from the test program. The PWM signal is filtered by a single 10k resistor and a 0.01 ufd capacitor to ground at the scope connection.

Comparison of Phase Correct PWM with Fast PWM

Comparison of Phase Correct PWM with Fast PWM at 100 Hz


Comparison of Phase Correct PWM with Fast PWM at 1000 Hz

Comparison of Phase Correct PWM with Fast PWM at 1000 Hz


Comparison of Phase Correct PWM with Fast PWM at 5000 Hz

Comparison of Phase Correct PWM with Fast PWM at 5000 Hz


Comparison of Phase Correct PWM with Fast PWM at 10000 Hz

Comparison of Phase Correct PWM with Fast PWM at 10000 Hz


There is a clear improvement at the higher sample rate in the amount of “fuzz” on the waveform. The fuzz is at the sample rate and is the result of the 0.01 ufd capacitor integrating the PWM square wave. At twice the rate, the capacitor has half the time to charge or discharge. You can see at 5 KHz, the Fast PWM signal is much closer to a sine wave than Phase Correct. At 10 KHz, both are falling apart. A better output filter that cuts off the sample frequency would help but for morse keyer side tone from a tiny speaker, the average amateur radio operators ear won’t know the difference. I may try a switched capacitor filter some time in the future just to see. Watch this space.

Revision History

2015/12/08   The photos above are all from the 32u4 port. The program uses quarter wave symmetry to reduce the table size by a factor of 4. Two sketches, one running on UNO or other Mega328 controllers, the other for the PJRC 32u4 Teensy are at:

I also back ported the changes to an earlier sketch that did not take advantage of symmetry. Scope traces were identical to the 32u4 port. Since the complete 360 degree cycle is specified, the code may be modified to generate arbitrary non-sinusoidal waveforms by manipulating the tables. Download at:

Each of these zip archives has a copy of the spreadsheet I used to construct the sine tables.



Worlds Smallest Iambic Keyer Paddles

I’ve done a couple of homemade dual lever paddles but recently I wanted to demonstrate my Tiny85 Arduino based keyer project at a local Maker Faire, so wanted something I could put in my pocket. In a few minutes, I made this. It’s a standard 3.5mm (1/8 inch) stereo plug. You can’t get any more portable than that.



Unscrewing the plastic shell reveals the secret sauce.



This is the dash paddle side. Just a tiny bit of thin copper soldered to the plug terminal. For those readers needing details, the copper came from the band around a Basil Hayden’s whiskey bottle.  We recycle!



Here is the dot side.



A  bottom view, you can see the two copper strips and how the sleeve (ground) contact was bent to form the common contact. A little careful tweaking left a thick sheet of paper’s worth of space between each copper strip and the common contact.



And the top side.



I was surprised to find it actually works. Could be useful on a QRP mountain top expedition. Have a look at this YouTube video.

Arduino Display for Liquid Flow Sensors


This project was done for a Friend Of a Friend. He needs to monitor water flow rate and quantity for his solar heating projects. He is mainly interested in this two inch sensor but also sent along a small plastic hose bib type similar to the Adafruit 828. Both of these sensors are turbine types, water flow spins a plastic wheel which magnetically triggers a pulse output proportional to the speed at which the wheel is turning. There’s lots of these sensors made for irrigation and industrial processes. The display is sometimes called a “Totalizer”.

This photo shows the 228PV sensor connected to the prototype display. I am spinning the turbine with air from a heat gun.

Flow Sensor Prototype with Large Flow Sensor

Flow Sensor Prototype with Large Flow Sensor


The electrical interface on the small flow meter has 3 wires, power, ground, and pulse output – relatively simple to connect to the microcontroller. But the large device has only 2 wires. It signals a pulse by shunting power to ground through a low resistance. The display must sense a pulse by looking for an increase in supply current. I designed an interface circuit that works with either unit by changing an option jumper. I constructed the interface circuit on a small piece of project board from Radio Shack (RIP). The positive supply feeds through a resistor which produces enough voltage drop when the large sensor is pulsing to trigger a digital low at the Arduino. The series resistor value is low enough that the power feed is still adequate for the small plastic sensor, so the option jumper just selects where to pick off the pulse signal. A series resistor and zener diode make sure the voltage ratings of the Arduino input pin are not exceeded. It’s a bad thing to overvolt an Arduino pin, please Don’t Ask Me How I Know This.



In this photo you can see the interface board soldered down near the front of the Altoids tin. I use “L” shaped bits cut from a paper clip, soldered to the board ground, and to the ground plane.  The same technique anchors the Arduino board.



Physical Construction

At first I worked up the circuit on a solderless bread board using code from the Adafruit web site. When satisfied with the results, I went ahead with building the Altoids tin prototype. The Arduino variant I used is a Sparkfun Pro Mini 5 Volt. It takes up little space and has a 5 volt regulator with enough capacity to run the 16×2 LCD.  An LED and two push buttons protrude through the lid, these are regular 6mm square PCB buttons. I solder one side directly to the lid, the other side of the switch is supported by a bit of PCB material and a piece of paper clip wire.

This photo shows the LED and the Reset button. Note the bit of PC board on the high side of the switch has a groove filed across so the grounded paper clip is isolated from the signal connection.



This photo shows the Function switch. It’s hard to see, but there is a 0.05 ufd surface mount capacitor soldered between the signal side and ground. That capacitor is part of my debounce strategy.



The Liquid Crystal Display itself mounts on four 2-56 screws. The screw heads are soldered directly to the lid. I attached a 10k Pot for contrast adjustment to the back of the LCD and it’s legs are used as tie points for 5v and ground wiring to the rest of the display.


If I have to build another one of these, I might glue the Arduino board to the back of the LCD which will greatly reduce the wiring between lid and box.


There is a power jack for 9 or 12 volt DC input, and a 3 conductor phone jack to connect the turbine sensor. These are epoxyed to the box.  Connection to the sensor plug is as follows:
Ground to the plug sleeve
Positive lead to the plug tip
If the sensor is a 3 wire type, the pulse lead connects to the plug ring



The opposite side of the box has a simple on/off slide switch mounted.



Software Considerations

Almost all of the turbine type flow sensors I looked at have two calibration factors specified: a “K” factor and an “offset”.  During calibration the manufacturer measures the pulse rate outputs for a number of precise flow rates. These are plotted but since the turbine has some friction, the graph will not be linear especially at the low end and a linear regression is done to get a best fit straight line.  The “K” factor represents the slope of the fitted line and has a dimension of pulses per unit volume moved. Offset represents the small amount of liquid flow required to start the turbine moving. You can assume that if any pulses are arriving at all, at least the offset volume of liquid is moving.  The 228PV manual specifies:
Frequency = (Gallons per Minute / K ) – Offset
We are measuring pulse frequency so turning the equation around:
Gallons per minute = (Frequency + Offset) * K

In general, this formula applies to any measurement unit. It would be possible to convert a gallons display to liters by just scaling the K and offset factors by the constant liters/gallon.  The Adafruit example sketch uses this method but measures pulse period in 1 millisecond increments which creates large gaps in the data if the pulse rate is over 100 Hz. At 200 Hz the pulse period will be 5 milliseconds, so a 1 millisecond period change is a 20 percent jump!

The following photo shows the display running Adafruit code:



Adafruit states their sketch is just an example to verify their sensors functionality but I felt higher accuracy at large flow rates was essential. An internet search turned up several sketches using a direct interrupt to count pulses. The sensor pulse train is applied to pin 2 or 3, fires on the rising edge of a pulse and calls an Interrupt Service Routine like:

void pulseCounter()
// Increment the pulse counter

Can’t get much simpler than that.  Run this for exactly one second and you have counted pulses per second. Apply to the above formula and get volume units transfered in that second. Accumulate that many units each second to find total volume transferred. So the code to actually calculate rate and volume is easy. I exorcised most of the Adafruit code and added my own formulas. I also added a line in the ISR to blink the LED along with the incoming pulses.


Display and Operation

But this display needs to operate with multiple types of flow sensors. So I had to code an arrangement to set and permanently store K and Offset for whatever sensor was plugged in. That turned out to be the most complicated part of the sketch. I use the Function button to do this, taking advantage of the Arduino setup section which is only executed on a reboot. Holding Function down while resetting the processor starts set mode.



Releasing the Function button displays the stored K factor with a cursor flashing over the first character, the sign.



The Function button has three uses in set mode, depending on how long it is held.
A quick click increments the digit under the cursor
A press between 2 and 4 seconds advances the cursor to the next digit
A press greater than 4 seconds completes the setting and moves either to the offset setting or writes the data

To make this a little easier, I added code to blink the LED if the button is held between 2 and 4 seconds, and turn on the LED solid if held more than 4 seconds. I hope this is no more annoying than setting a cheap digital watch.

Note that K factors are always positive but occasionally a negative offset is specified.



This photo is the normal running display entered after exiting set mode, or on a processor reset.  The first line records units moved per second, where units is in whatever the given K factor uses. Both the Adafruit sensors have factors specified in Liters/Second. The 228PV I’m working with uses units of Gallons per minute.  The water meter on my house here measures in cubic feet. You have to consult the sensor data sheet.

Resetting the processor zeros the cumulative quantity moved.



Finally, holding the Function button down during normal operating mode will cycle the following four displays:

The stored K factor



The stored Offset



Accumulated time since last reset. Note this is subject to the accuracy of the 16 Mhz clock in the Arduino.



A software version number.


Update October 25, 2015

I’ve constructed a second unit. This one is built in a nice looking Extruded Aluminum box from Adafruit.  I thought the better enclosure would make construction easier. I was wrong. Because it can’t be opened you can’t reach in and solder anything, and you lose the convenience of soldering anything needing a ground directly to the tin box. That means wires have to be attached to every terminal, brought to a common point and spliced. I did try soldering the Pro Mini to the back of the LCD and that works but the contrast pot had to be wired out so the assembly didn’t save much wiring. This photo shows the completed display with K factor set to 1.0 and a 2000 Hz crystal controlled signal applied to the sense input:



The left side has a power switch and also an SPDT switch for 2-wire/3-wire operation that replaces the option block in the prototype.



Sense in and power jacks are mounted on the right panel



Have to open the left side to connect an FTDI Friend



Calibration and the K Factor

Most of these flow sensors will have specified somewhere in the data sheet, a K factor and offset. What the manufacturer does is plot flow in output pulses per second (frequency) against flow volume through the sensor at a number of flow rates. Then they do a linear regression on the data to get a best fit straight line. An example is Fig 1 in
K factor is the slope of the line, usually given in pulses per unit volume, for example pulses per gallon. Offset accounts for the plot not being non-linear at the low end. Because of friction, it takes some small amount of fluid velocity to get the turbine to start spinning. You can assume that if the turbine is pulsing at all, at least the offset quantity is moving. Less than the offset volume is undefined. In the sketch, interrupt code blinks the LED when pulses are coming in.
There does not seem to be a standard for how K factor is presented. Sensors output a pulse stream at a frequency proportional to the flow volume as calibrated, this can be measured. With some sensors, you multiply the pulse frequency by the K factor to obtain a volume rate. Others however, require you to divide the pulse frequency by K.
In the sketch, I added a way to switch between these two methods by using the first character of the K factor. If this character is a “*”, the incoming pulse rate will be multiplied by the K factor, If the first character is “/” pulse rate will be divided by K. You may see a formula in the sensor data sheet like Freq = (Flowrate * K) – offset. Since we measure Frequency and need to display Flowrate, the formula is rearranged to Flowrate = (Freq + offset) / K and the K factor needs to be set to type “/”. Other sensors present Freq = (Flowrate / K) – offset. Rearranging that formula gives Flowrate = (Freq – offset) * K and you would set the K type to multiply, “*”. If the sensor documentation is not clear, just try it out. If the multiply/divide indicator is wrong, you will probably get totally unreasonable flows displayed. If so try changing the type indicator.


Here is a table from the FMC MNIT001 meter manual:


Note how K factors are presented in Pulses per Unit Volume. So for these meters, set the K factor type to “/”.
Another table, this one from Badger documentation:


Badger presents the flow frequency formula as:


So with these Badger sensors the rearranged equation to find flow rate is GPM = (Freq + Offset) * K and you would chose the multiply type option.

More information on the sketch’s K factor changes is in the file HERE_ARE_THE_DIRECTIONS.pdf included in the V1.10 dropbox download below.

Sketch and Revision History

The code can be downloaded from my DropBox account. I am carrying forward the original Adafruit license.
Version 1.oo Oct 08 2015 Initial release

Version 1.01 Oct 17 2015 Correct schematic error

Version 1.10 Oct 25 2015 Change method of applying K factor

The Shed Project

This post is not really woodworking more like carpentry. Sheds are legal in this town as long as they are not on a permanent foundation and are at least 3 feet from a utility easement.

I bought this house in February 1999. There was a 10×12 foot shed in the back yard which was even at that time clearly deteriorating. Fast forwarding to 2015 and it had become a house for homeless rodents. The door had disintegrated and part of the floor had rotted away. I do need the storage space so I am rebuilding the underlying structure and will be replacing some of the rotted T1-11 siding on the front.

This is the patient. Note there is no transom or sill under the doorway. The front of the shed faces West and is just set on the dirt following the grade of the lot. It definitely tilts towards the back where there is a drainage swale. My measurements estimate the front is four inches higher than the rear. I believe this was a major factor in the floor deteriorating as rain falling on the door will run into the shed. I will think about raising the rear to make the structure level.



Most of the trim is untreated pine, and the bottom front has been in contact with soil.



Part of the floor has been removed here and the camera is inside looking at the area underneath the door. Some timber and Great Stuff there in an attempt to keep the rabbits out. The floor is 5/8 plywood and was nailed down with ten penny spikes about every 15 inches. Not fun to get up but I want to put it back down if possible after the framing is repaired.



Transom area from the outside. This would be looking east.



On the south side the floor has been taken up to see what structure is underneath. The shed proper is made of a set of prefabricated barn shaped 2×4 trusses. They are supported by four 4×4 timbers running east to west on a two foot spacing. I discovered that these 4x4s are in turn supported by three 4x4s running north-south set into the dirt.



Four two foot spaced 4×4 across a ten foot shed leaves a foot extra on each side



The plywood flooring has rotted in the area around the door. It has been replaced in pieces at least once.



The first phase was to shore up and replace the sill under the front. Here the front of the shed has been jacked up about four inches. I obtained several two foot long 12×3″ treated cutoffs from a forest preserve project a few miles from here. Getting them home on a bicycle was interesting. My original plan was to use the cutoffs as pads underneath the 4×4 sub structure. In this photo there is a pad under each of the four members at the front.  I have a number of treated 2×6 timbers removed from a deck and I decided to put one 2×6 on top of each of the lateral 4x4s. This will raise the entire structure an inch and a half, getting it above the dirt. I hope.



This bumper jack is raising the southwest corner. Big jack, must have been from a Buick. It will pull a fence post no problem.

I’m cutting the 2 foot pads in half which gives a piece about 11×12″ and you can see the pad in the corner.



I have one hydraulic floor jack, and a half dozen scissors jacks accumulated in anticipation of this project.  The procedure is to dig a hole, slide the jack under a support beam and turn the cranks evenly. The floor jack worked the easiest, and the bumper jack not too difficult with the load but the scissor jacks were hard to turn their screw while the jack is in a hole. A big crescent wrench helped.

I’m also putting a pair of support pads under each side because I noticed the shed has sagged a bit in the middle.



This photo shows the north side of the shed. Another scissors jack is helping raise the center of the structure and the front is now elevated. Pads have been placed at the front corner (left of photo) and at two spaces under the side 4×4″.  You can see a 2×6 has been slid over the front lateral and also over the lateral in the center. The barn shaped trusses are on 24 inch centers.



The horizontal part of the bottom front truss 2×4 that formerly formed the bottom of the door frame was gone. Rather than replace it with another 2×4, I laminated a pair of 2x6s with a bit of half inch plywood to make a beam the same thickness. The vertical studs that formed the door frame are rotted at the bottom, they will be replaced when I find a suitable door.



This is the southwest front corner after raising and placing the treated lumber pad, and installing a new beam across the front. I have screwed a short piece of 2×4 to the rotted door frame to hold it together temporarily.



This is the north side of the door frame with a good 2×4 added.



At this point the front had been repaired enough that I could begin at the back of the shed. The remainder of the floor was removed, the jacks moved to the back. I decided to add another three inches under the rearmost beam to make the structure more level. This is the final arrangement at the north east corner. Three 2×6 under the side beams and two of the 3 inch pads to help take the load.  I put a long lag bolt all the way through the 2×6 to tie the structure together.



This is the opposite rear corner.



The two middle 4x4s had to be double padded as well.



Since I had added 3×12 pads at two points along each side, raising the rear an additional three inches required adding some additional wood to take up the space at those points.  One inch ripped from a 4×4 above the pad at the left in this photo and one inch plus a 2×6 at the right.  The center lateral beam just needed one more 2×6 to make it come out even. The center was bolted down as well.



Now the structural repair was complete and I could start putting the plywood floor back down. It’s splintered a bit from digging out the nails but in a shed, I don’t care, I spackled the splinters.  I’m screwing everything together so it can be taken up easily at some future time.   I put down a layer of rosin paper. Don’t know if that’s necessary but I had some so I used it.

This photo is the north side corner at the rear.



This photo is the south corner at the rear. I also squirted Great Stuff in all the spaces around where the trusses were cut out.




To Do as of 8/7: Finish re-laying the floor and plan to patch the damaged part. Find an exterior door! Get a sheet of T1-11. Get a sheet of 5/8 ply to patch the floor. Get 1×4 cedar to frame the door. Figure out how to get those home. Add soffit vent screens and a screened vent at the rear near peak.

Update: Week of August 10-14

The flooring is all back in place except a 2′ x 6′ piece behind the door which was too badly rotted to reuse.



Added four soffit vents and a 14 inch square gable vent at the top rear. Made a nice cedar frame for the gable vent.
I rented a pickup truck from Menards ($19 for 75 minutes, made it with 15 minutes to spare) and hauled the following things home:

Sheet of 5/8 exterior plywood
Sheet of T1-11 siding
Three 8 foot 1x6s
Three 7 foot 2x4s

And while I had the truck, a used exterior door from the Habitat Resale store.
So now I have no excuse for not finishing the project.
I am not very confident with the door, have to make a frame to fit it. After some drawing and math involving ugly fractions I had a plan for the frame.

The old frame is 4 1/2 inches thick. Probably made to account for a 2×4 stud wall and a half inch of wall board on either side.  I only have the stud wall to account for so have downsized the proposed frame to 3 1/2 inches wide. I bought three 2x6s to form the frame so I moved my table saw to the summer workshop (driveway) and ripped them down. Two of the waste strips were then ripped to 3/8″ thickness, one to half inch. These will form the stop moldings .  Here is the ripping work station. I use my plug in router table as an outfeed support. It plugs into channels on either side of the saw table.



I blocked up the door on a couple of saw horses and clamped the stop molding and frame members to the sides to get an idea of what to do next. It looked good but how to align the hinges?



The door formerly had hinges with four screw holes. Could not find hinges that matched the hole pattern though so I moved the hinges up a half inch so there was solid wood for new screws.  I decided to cut the hinges into the frame member first. I aligned them to the board edge and knifed in the hinge outline. Used a one inch chisel to further deepen the hinge outline and a small gouge to round the corners. Then wasted most of the pocket with a trim router, followed by a pass with my good old Stanley 71 router plane to clean up the edges. Hinges fit well. Now to fasten the other hinge leaves to the door.

I set the frame with hinges attached on the door. With a 3/4″ board under each one it looked like the alignment on the door was as good as it could be. Piloted the screws with a Vix bit.



This shows one of the hinges hanging over the door edge ready to be piloted and screwed down. After running four screws in each hinge on the door side, I removed the clamps and, Moment of Truth, found the frame pivoted all the way with no binding whatsoever. Success!



The final bit of engineering was to bridge the top of the frame. After studying the existing frame, I decided to capture this horizontal board in shallow Dados. I laid them out in pencil, cut the sides down a quarter inch with a back saw then hogged out most of the waste with a chisel. Cleaned the bottom of the dado with the Stanley 71 router plane. This is the Christopher Schwarz/ Roy Underhill method and was probably faster than setting up a jig for the little Dewalt router.

This photo shows the dado with header board inserted, glued and screwed.



Finally I screwed a temporary header across the bottom of the frame, punched out the hinge pins and removed the door. Two temporary diagonal braces were screwed on so the frame can be safely moved.  Both the door and the frame are on the back yard deck now with a coat of paint drying. I think it will work, will find out Monday when the install is done.

 Update August 18

Howard Peterson, from the Dupage Woodworkers Club came over to help with the door. Howard is active with Habitat for Humanity and has much experience building houses. In four hours we had the door installed and the missing piece of flooring replaced.

After tearing out the old frame and the 2x4s that supported it, a framing square showed the opening was far from square, and the floor was not level. Howard ripped tapered shims from 2x4s to correct the out of square condition. Look closely at the vertical edges in the next photo, you can see the tapered bits. I would never have though of doing this, thanks Howard!



After considerable fussing, the door fit well, and we cut a new piece to replace the open floor behind the door. The inside of the shed is now secure and usable.



Update August 23

Next step was to replace the rotted and ant infested sections of T1-11 siding on the front. I figured I could do this with a single sheet of siding if only the bad parts were re done so ran a horizontal chalk line two feet up from the bottom and sliced off the old material with a circular saw. New sections were cut and fitted. I decided to run the new lower piece down almost to the footing to fill the open gap there and in doing so, almost ran out of the new sheet. The lower right piece was short but it turned out the pattern didn’t line up anyway so I made a five inch filler piece and it’s hardly visible.

All the new sections are fastened with screws and I put aluminum drip edge strips in the horizontal seams to keep rain out of the joint.



And here is the repaired front side with one coat of oil stain.  Later another coat of stain was done on the entire shed. Had to caulk a number of carpenter bee holes in the left hand soffit.



The final step was to replace the edge and door trim on the front. I had to rent the Menards truck again to bring home the half dozen cedar boards I figured would be needed.  I’m using six inch cedar trim around the door rather than brick molding plus four inch that was on the old door.

Cedar was cut and fitted for door stop moldings at this time.  This was complicated by the fact that there was a 3/4 inch warp in the front wall which cause the top left corner of the door frame to stick out farther than the right side. I couldn’t use the stop moldings I had previously made, had to make tapered stop strips out of cedar to account for the bulge.  It was a chance to use my latest secret weapon, a crude scrub plane I made out of a decrepit wooden jack plane. The blade has been ground to a radius of 8 inches so the plane takes a deep narrow cut. It hogged off the extra wood down to the line in about five minutes and I shot the edge with a long jointer plane.



My scrub plane takes out these thick rough shavings. Doesn’t take many passes to remove a half inch of cedar.



All the trim and stop is in place in this picture.  I installed an aluminum threshold piece which will help shed water out the front instead of running back into the shed floor.



A major benefit of using deck screws instead of nails is you can take the project apart for painting. I painted the trim a lighter color to match the house, would have gone crazy cutting in two coats of paint around all that cedar. Here is all that carefully fitted wood painted and drying on saw horses.



Update August 25

And this is the completed, painted restoration. Just need to add some weather stripping around the door and caulk a few gaps under the eves.



I’ve been fussing inside the shed all day. It’s an interesting problem, how to best make use of a 10×12 foot space. Formerly, stuff was just piled on the floor, so usually had to crawl over some things to get to what I needed. I’m now hanging as much as I can from the back and front walls and stashing spare wood scraps in the rafters so the floor space is clear.



Final Update September 4

Thinking more about efficient utilization of the interior space, I realized that adding shelving would help. The cheapest 18 inch commercial product I found was at Meijers, $25 for a four shelf unit 4 feet high. The home centers had similar units starting at $45. I decided I could build something better.  There were 2x4s nailed across the inside of the shed on both sides with a single nail in each stud, I believe these originally  supported the frames while the T1-11 siding and roof was nailed on. So I tore those 2x4s down, ripped them lengthwise to make 2 by 2s and converted them into shelves on each side of the shed. Also I had 3/8 plywood available that my neighbor surplused after a sump pump failure which I cut in around the studs. Would not have been able to do that with commercial metal shelving.


The final touch was to build a ramp leading up to the now higher threshold. I had 2×6 treated boards left over from rebuilding a planter years ago. It took a bit of fussing to get the ramp stable but I can easily wheel the lawn mower in there now which will clear space in the garage.


The structure is considered finished now, though there will always be changes to my storage strategy. I hope it lasts another 20 years.

Rebuilding Uncle Ray’s House Number


Sixteen years and change ago, we moved to our current location in Naperville, Illinois. As a house warming gift, Uncle Ray Lauderbach gave us an illuminated house number sign. He had made many of these for his neighbors in New Jersey. The design consisted of a wooden box about 5″ x 12″, and 3″ deep. It’s assembled using box (finger) joints.  There is a groove around the front where the number template, cut from thin black foam and glued to a sheet of textured plastic sits, along with a sheet of thin plastic as a front face plate. The back of the box is a sheet cut from a plastic mirror tile. Ray installed three 12 volt incandescent bulbs connected in series, these were powered by a 20 VAC wall wart, the undervoltage provided a dim but long lived illumination.

I screwed the box to the front of our garage.

I’ve painted the box four times and caulked the face plate but could not keep moisture out of the interior. In 2015 I could see the corners crumbling and it was clear that reconstruction was necessary. I removed it from the garage and disassembled. It’s a credit to Uncle Rays box jointing skills that I had to jack the ends apart with a reversed clamp to extract the number stencil sandwich from it’s groove. I cleaned everything and prepared to make a new wooden box.

Raw Material

Home Depot has these half inch thick Cedar fence pickets 6 inches wide and four feet long. I made a bird house out of them a few years ago and its held up well. There were three pickets lounging in my lumber stash, so this was a logical starting point. Also in this photo you can see the number sandwich and the mirrored backing plate with the electrics.

Bare Home Depot Cedar Fence Picket

Bare Home Depot Cedar Fence Picket


I decided to use the “Eleven Grooved Box” technique with mitered corners reinforced with splines. So I ripped the picket to 3 inches, and cross cut to about 38 inches. This was clamped in my planing board, planed smooth on one side, and readied to cut a quarter inch groove the whole length.

3 x 36 Inch Strip Ready to Plane

3 x 36 Inch Strip Ready to Plane


I have a beautiful, genuinely old plow plane and used it to cut the groove. I’m sure the plow plane was quicker than setting up the router table, digging out the router, finding a bit, and creating a ton of sawdust. Note to self: Cedar shavings smell good and make good mulch.

Plowing Quarter Inch Groove

Plowing Quarter Inch Groove


This is a close up of the finished groove in what will be the front edge of the new box. The whole 38 inches has been grooved at this point.

Finished Groove 1/4 Wide 1/4 Deep

Finished Groove 1/4 Wide 1/4 Deep


A test showed that the number sandwich fit well in the quarter inch groove. Also in this picture you can see one corner of the old light box.

Test Fit

Test Fit


Box Componants

The next step in making an Eleven Grooved Box (actually this one only needs nine grooves) is to slice the stock into 45 degree mitered side pieces. This is done using a big Stanley miter box. I used the plastic front face plate to gauge the dimensions of the pieces, leaving about an eighth of an inch extra for caulking.

Slicing the 36 Inch Strip

Slicing the 38 Inch Strip


With all four sides cut and checked for equal length top to bottom and side to side, I could do a dry fit using a strap clamp with the number sandwich inserted. It worked perfectly.

First Dry Fit

First Dry Fit


Next to cut grooves in each of the eight miter faces to receive the eighth inch splines I had cut from the remaining piece of the Cedar picket. I have a jig for this, developed to hold a Stanley 45 plow plane in just the right orientation.

Plowing 1/8 Inch Grooves for Splines

Plowing 1/8 Inch Grooves for Splines


All four box sides have been grooved in this photo. The jig mentioned above allows a clean cut which means a tight fit for the splines that will be glued in.

Four Completed Box Sides Grooved for Splines

Four Completed Box Sides Grooved for Splines


Box Assembly

The number sandwich has to be inserted in the front groove as the box is glued together. I made this a two step operation by gluing up the top, bottom, and one end only first, then inserting the plastic number sandwich, then finally gluing the last end in place. This photo was taken while the first stage was setting. The second end is in place to keep the box in shape, it has no glue applied yet.

First Stage Glue Up

First Stage Glue Up


I applied silicone sealant to the front edge only of the groove, inserted the plastic face plate, pressed it in place against the sealant, then slid in the number stencil with it’s textured plastic backing. This seals the front tightly but will allow the number itself to breathe a little bit.

Then glue was applied to the final box side piece along with it’s two splines, sealant applied as before, the final end inserted and clamped.  The photo below was taken the rear surface planed flush and the box primed. You can see how the splines fit tightly and reinforce each corner. There is only a single joint line exposed to the weather.

Rear Surface Planed Flush

Rear Surface Planed Flush


At this point I fitted the rear mirror with it’s electrics to the box and tested under power. It did not light. I checked and every one of the three light bulbs were open. Apparently they did not survive the box disassembly. These were bayonet base 12 volt bulbs from Radio Shack. Radio Shack no longer exists in this area, so I decided rather than try to find replacements, to construct something with white LEDs.

On the table saw I ripped a strip from an old prototype printed circuit board. It has a single long row of tenth inch spacing holes. Note to self: wear safety glasses and use a carbide tipped blade you don’t care about. Fiberglass is very abrasive.

I have a handful of white LEDs harvested from a string I got during a post Christmas sale, and dug up a 12 volt wall wart (actually measured closer to 18 volts). I soldered eight LEDs to the PC strip, wiring them in pairs with a 1500 ohm resistor between each pair which allows about 10 milliamps. Each pair is wired to common power points in the center. I splayed alternate LEDs out a bit to spread the light more evenly.

New Light Strip

New Light Strip


I removed the old bulb sockets from the mirror but left the three supporting copper brackets.  With a bit of bending I was able to solder the new LED strip to the copper strips for good support. The LEDs point towards the mirror, not towards the front. I felt this would spread the light more evenly.

New Strip Soldered to Old Brackets

New Strip Soldered to Old Brackets


A dry fit in the box showed good even illumination. There is a slight shadow across the center due to the PC board strip but hardly noticeable.

First Test Light

First Test Light



Back in the garage, I reattached the strip of flashing across the top rear that mounted the old box. Then I attached a strip of extruded aluminum behind the flashing. This will tilt the box forward slightly and help rain to run off. I cut a small piece of flashing and attached to the bottom of the box to make sure that edge is held tightly against the wall.

Finished Box With New Mounting

Finished Box With New Mounting


Here is the front view of the rebuilt box after a couple coats of paint.  Note to self: paint doesn’t stick to silicone sealant fingerprints.

Front Of Finished Box

Front Of Finished Box


So now it’s show time. Screw the creation back on the garage face. Since I used the original rear plate and mounting bracket, I only had to drill one new pilot hole. The power wire was routed inside across the header plate to the nearest outlet and stapled down. Power is on continuously, you can’t see the illumination in the daylight but because of Uncle Ray’s black background the numbers are very readable.

Mounted on Garage

Mounted on Garage


Finally the real test, how does it work at night? It’s a little bit brighter than the original setup but still not so bright it is distracting.

Night View

Night View


Thanks Uncle Ray!