Pro Mini Logger Project for the Classroom [ EDU v2: 2019 ]

“Instrumentation is a central facet of student, amateur and professional participation in science. STEM education, recruitment of scientists and experimental research are thus all hampered by lack of access to appropriate scientific hardware. Access restrictions occur because of: 1) lack of capital to purchase or maintain high-cost equipment, and/or 2) the nature of proprietary ‘black box’ instrumentation, which cannot be fully inspected, understood or customised…
…In addition to reducing opportunities for people to engage with science, this lack of access to appropriate hardware restricts scientist’s creativity in experimental designs.”

From: Journal of Open Hardware
Expanding Equitable Access to Experimental Research and STEM Education

by Supporting Open Source Hardware Development


Last year’s intense deployment schedule focused on getting more sensors into the field, which left little time for development of new approaches to the logger itself.  Now that everything is settling into the school term routine, it’s time to update the “classroom edition” of the Cave Pearl Logger with feedback from three years in the trenches: 

The 2016 build achieved it’s goal reducing construction time, but it was low on important skills like soldering. Limited lab time meant that something had to give if we want students to “pay the iron price” for their data, so we’ve added a pre-made enclosure box. Though it’s not as robust as the PVC housings, it provides more room inside the housing. Past student projects have required things like 555’s, ADS1115 modules, display screens, etc. and the proto-board will make it easier to integrate those additional components.

PARTS & MATERIALS

TransparentSinglePixl
Bill of Materials: $16.75
Plano 3440-10 Waterproof Stowaway Box
Much cheaper at Amazon as “add-on” items, so you need to reach $25, before you can order for $3. Fortunately they sell lots of other useful things like silicone wire, double sided tape, conformal coating, or even the Pro Mini clones $4.96 at Walmart and there are a selection of larger size boxes in the stowaway series.
$3.50
4Pin 24AWG IP65 Black Waterproof Cable Connector OD 4mm
Better quality version is available at Adafruit for $2.50 each, wBL-RED-Wht-Yel colors used here for the I2C bus.
$1.00
M12 IP68 Nylon Cable Gland
Adjustable for 3mm-6mm diameter. You need two for the build. Make sure they include O-rings.
$1.00
3/4″ Schedule 40 PVC Cap
Diameter will depend on the size of your sensor breakout board. Get ones with FLAT ends.
$1.00
White 170 Tie-Points Prototype Breadboard $0.50
Pro Mini Style clone 3.3v 8mHz
Get the ones with A6 & A7 broken out at the back edge of the board.
$2.20
Nano V1.O Screw Terminal Expansion Board
Note: To save time, you can spend an extra $1 for pre-assembled boards by Deek Robot, Keyes, & Gravitech.  Have a few small flat head screw drivers handy.  
$1.05
DS3231 IIC RTC with 4K AT24C32 EEprom (zs-042)
Some ship with CR2032 batteries already installed.  These will pop if you don’t disable the charging circuit!  
$1.25
CR2032 lithium battery  $0.40
4 poles/4 Pin 2.54mm 0.1” PCB Universal Screw Terminal Block Connector
These things look “open” when they are “closed”, and you need a very small screw driver to open them.
$0.40
SPI Mini SD card Module for Arduino AVR
Buy the ones with four ‘separate’ pull-up resistors so that you can remove them.
$0.50
Sandisk or Nokia Micro SD card 256mb-512mb 
 Test used cards before putting them in service. Older Nokia cards have low write currents in the 50mA range. This is less than half the typical write currents you see on larger size cards.
$2.00
3×1.5V AAA Battery Batteries Holder w Wire Leads
The Pro Mini regulator will handle battery packs holding from 3 to 8 AA or AAA batteries. If you are using alkaline AAA batteries, changing this to a 4x battery holder doubles the run time.
$0.40
Common Cathode Bright RGB LED 5mm 
( & 4k7 limit resistor) 
$0.05
5 lb Double Sided Tape10MΩ resistors & 3MΩ resistors, 22awg silicone wireheader pins, etc… $0.50
Donation to Arduino.cc
If you don’t use a ‘real’ Pro Mini from Sparkfun to build your logger, you should at least consider sending a buck or two back to the mothership to keep the open source hardware movement going…so more cool stuff like this can happen!
$1.00
Comment:   You might need one of these to get started:                            (not included in the total above)
3.3V 5V FT232 Module
  ***Be sure to set the UART module jumpers to 3.3v before using it!*** and you will also need a USB 2.0 A Male to Mini B cable.
$2.75
Micro SD TF Flash Memory Card Reader
Get several, as these things get lost easily. My preferred at the moment is the SanDisk MobileMate SD+ SDDR-103 which can usually be found on the ‘bay for ~$5.
$1.00

Connection Diagram:

This logger uses the same three components described in the paper from 2018, but we now connect those core modules via a screw-terminal expansion shield, rather than soldering them directly to the pins:
 
COMPONENT PREPARATION

Watch through the videos as a complete set first so you know where you are going, and then use the images below the videos to remind you of the key steps when you do the assembly; It usually goes much faster working from a photo where you can see all the connections at once. The times listed are estimates for people with some soldering experience. If you’ve never built a circuit before, then taking 3-4x that long is completely normal. Don’t worry about it – you will be surprised how much faster you get with a little practice!

Screw Terminal board:  (~40min)  or ( 5min with pre-assembled board)

Don’t forget to measure the values of the resistors before soldering that voltage divider. You will need those values to calculate the battery voltage based on the ADC readings from pin A6.

These screw terminal boards are designed for an Arduino Nano, but if you orient the board to the Tx/Rx pins, the labels on digital side of the shield will be correctly aligned with the Pro Mini:

The most common beginner errors at this stage are crooked headers & not heating the pad/pins long enough for solder to flow properly.  This is often because students are trying to use an iron tip that has “gone dry” so the heat is not transferring properly to the pins. You must protect soldering iron tips with fresh solder every time you put it in the stand to prevent oxidation. Tip Tinner can sometimes restore those burnt tips.   {Click images for larger versions}

Common soldering errors – which are easily fixed by re-heating with more solder & flux.

Divider runs between GND & RAW Vin, with output to A6 pin.

Always apply conformal coating in a well ventilated space, such as a fume hood.

It is better to err on the side of using a little too much heat, because partial connections to the screw terminals will cause you no end of debugging grief later: Cold solder joins can “sort of” work “sometimes”, but cause mysterious voltage drops over those points because they can act like randomly variable resistors in your circuit.  Note: This voltage divider uses meg-Ω size resistors and takes >1 second to charge the capacitor when the unit is first powered on – so you can’t take the first battery reading until that much time has passed.

The Pro Mini Board:   (~40 min)

~5-10% of the cheap Pro Mini clones from eBay are flaky, and it is quite annoying to discover one of those that after you have assembled a logger. So test your board with the blink sketch before you remove pin13 LED resistor.  These limit resistors move around from one manufacturer to the next, so you might have to go hunting for them on your particular board.  You also need to remove the RESET switch from the board, or that button will be compressed when you put the SD card adapter in place:

Test w blink sketch!

You can skip the reset pins at this stage, or you can pull those pins out of the plastic rails later with pliers, or simply cut them off.

SCL & SDA jumpers to the 2 extra pins on the digital side.

Connect A6-7 & GND to analog side pins with the leg of a scrap resistor.

(Note: Credit goes to Brian Davis for the idea of using “extra header pins” when patching to the unused to screw terminals.)    

The SD Card Adapter:   (~15 min)

This SD card adapter comes with small surface mount pull-up resistors on the MOSI, MISO & SCK (clock) lines (removed from the dashed red line area photo 2 below).  The Arduino SDfat library uses SPI mode 0 communication, which sets the SCK line low when the logger is sleeping. This would cause a constant drain (~0.33mA) through the 10k SCK pullup on the module if we did not remove it.  I prefer to pull MOSI & MISO high using the internal pull-ups on the Atmel328P processor, so those physical resistors on the breakout board can also be removed. Leave the top-most resistor of the four in place to pull up the unused DAT1 & DAT2 lines.  This keeps those unused pins on the SD card from floating, which can draw excess current.

Only remove the bottom three pullup resistors. keep the top one
The SPI connections:
RED:           3.3v regulated
Grey:          Cable select (to D10)
Orange:     MOSI   (to D11)
Brown:      SClocK (to D13)
Purple:      MISO   (to D12)
BLACK:     Ground

Attach SD adapter & Pro mini to the Screw Terminal Board:  (~20 min)

Label the Vcc & GND connections with a colored marker, then insert the Pro Mini into the headers on the screw-terminal shield. Be careful not to bend the pins – especially the “extension” pins at the back of the board. It’s easy to connect the board in the wrong orientation at this step. The voltage divider on the bottom of the screw terminal shield aligns with the ANALOG side of the Promini board. 

Label the Vcc & GND connections.

Then affix the SD adapter board to the top of the Pro Mini with a slight overhang, so that the jumper wires align with the screw terminals below. Trim the wires about 1cm past the edge of the board to provide enough stripped wire for the terminal connection.

The limit resistor for the common cathode RGB can range from 4k7 to > 30kΩ

LED on pins D4-D6, & GND. see: multiplexing wD9 GND

Add layers until the tape extends beyond the pins.

The RTC Module:  (~15min)

The simplest modification to these DS3231 RTC boards is to remove the charging circuit resistor and power LED limit resistor from the circuit board (the red squares in the first picture).  A non-rechargeable CR2032 coin cell battery will supply the RTC with power for many years of operation.  Note: The 32K pin is not connected, and does not get a jumper wire. The four screw terminals go on the same side as the battery holder.

rtc1

Add an extra layer of foam tape over the smaller 4K eeprom chip, so that the thickness matches the top surface of the DS3231 chip.  The RTC board already has 4.7kΩ pull-ups on the SDA (data) and SCL (clock) lines so you will not need to add them to the bus.  This module also has a 4.7k pull-up on the SQW alarm line.  (Adding the screw terminals to the small cascade port on the RTC module is another creative idea from Brian D.)

The Plano Stowaway housing: (~10 min)

In these photos, I’ve tapped some threads into the housing for the cable gland, but that is entirely optional. Glands much larger than PG7 (12mm) will not fit in the available space in that corner. 

ASSEMBLING THE LOGGER PLATFORM:  (~30 min)

Using double sided tape to hold the parts inside the housing (rather than traditional stand-offs) makes this stage of the build remarkably quick.  Adding male Dupont pins allows you to join internal and external wires via the breadboard.  Be sure to use wires that are long enough to reach the mini breadboard. 

You can “reactivate” spent desiccant packs with a few zaps in the microwave – if they have indicator beads.

Connecting external sensors to the housing:

It’s worth mentioning that you don’t have to use the breadboard for those external sensors. In fact the connections would be more robust if you brought those external sensor wires directly over to the screw terminals on the RTC or the Pro Mini. Put protective masking tape over sensor ports that need to remain open before potting those external sensor boards in epoxy!

Your Logger is ready!    (~2 to 2.5 hours)

Now you can test your new logger to confirm all the connections are working:

1. Test the LED – Edit & upload the default blink sketch, changing the pin numbers each time to match your RGB LED connections.

2. Scan the I2C bus – with the scanner from the Arduino playgound. The eeprom on the RTC module is at address 0x56 or 57 and the DS3231 should show up at address 0x68. If you don’t see those two devices when you run the scan, there is something wrong with your RTC or the way it’s connected.

3. Test the EEprom on the RTC module – We’ve updated BroHogan’s original code from the playground to this tester script. You may have to change the I2C address at the start of the code based on the numbers shown during your I2C bus scan.

4. Set the RTC time, and check that the time was set – There are dozens of good Arduino libraries you could use to control the DS3231, and there is a script over at TronixLabs.com that lets you set the clock without a library. The trick with Tronix’s “manual” method is to change the parameters in setDS3231time(second, minute, hour, dayOfWeek, dayOfMonth, month, year);  to about 1-2 minutes before the actual time, and then wait to upload that code till about 10-15 seconds before your computers clock reaches that time (to compensate for the compiler delay). Open the serial window immediately after the upload finishes, and when you see the time being displayed, upload the examples>blink sketch to remove the clock setting program from memory – otherwise it will keep resetting the RTC every time the Arduino re-starts.  [ Note: hour  in 24-hour time, & year with two digits eg: setDS3231time(30,42,21,4,26,11,14);  ]

5. Check the SD card is working with Cardinfo – Changing chipSelect = 4; to chipSelect = 10;
Note that this logger requires the SD card to be formatted as fat16, so most 4GB or larger High Density cards will not work. Most loggers only generate 5 Kb of data per year anyway.

6. Check the sleep current – With an SD card inserted in the logger, upload this Pro Mini datalogger starter script with no changes (note: that code requires you to install three libraries as well). Then connect an ammeter between the positive battery connection and the Vin screw terminal (you will need an extra wire to do this) and run the logger from the AAA or AA battery pack.  After the initialization sequence has finished, the reading on the screen (in milliamps) is your loggers sleep current.

AAA cells usually provide about 1000 milliamp-hours of power to their rated 0.8v, but we are only using half of that from alkaline batteries with a regulator input cutoff around 3.6v.  So dividing 500 by your loggers sleep current gives you a rough estimate of your loggers operating life (in hours).  For a more accurate estimate, you can use one of the Battery Life Calculators on the web with 250ms @5mA for your sample time.  Changing the power supply to 4xAAA cells lets you bring alkalines down to 0.9v/cell, extracting almost the entire 1000 mAh. Lithium AAAs deliver almost their entire capacity above 1.2v/cell so 3xAAA lithiums yield almost 1000 mAh capacity even with the 3.6v input cut-off.

Thermal response of 3x AAA’s (mV left axis) vs Temp (°C right axis) in the standard voltage-regulated classroom build running the starter code from GithubThe 90mv drops caused by SD card “controller housekeeping events” at 20°C  increase to ~220mV as temps near -15°C. These periodic high drain (100-200mA) events would likely trigger the low-voltage shutdown before anything else in the loggers normal duty cycle. (Note: Battery readings taken AFTER SD save, Sample interval: 1 min, sleep current for this test unit: 0.22mA )

Its worth noting that the starter program we’ve provided captures an ambient temperature record from the RTC in 0.25°C increments (example right).  New sensor readings can be added to the log file by inserting:
file.print(YourSensorVariableName);
followed by a separator file.print(“,”);
in the main loop before you close the datafile on the SD card. Then change the text in the dataCollumnLabels[] declaration to add headers to match your new data. This starter script automatically generates required data files on the SD card at startup, and tracks the rail voltage for those adventurous enough to run without a regulator. SD memory is electrically more complex than the Pro Mini processor, with some using a 32 bit arm core.

Once you have your logger running, you might want to review our tutorial on adding sensors to your data logger. And after that you’ll find a few more advanced I2C sensor guides on this site as well (…and the list is constantly growing) We’ve also developed methods to add 5110 LCD & OLED screens to the Cave Pearl Loggers using the fewest system resources. These screens are easily accommodated on the proto-board in this build.

For people wanting to take their skills farther, you can explore the gritty details of how we optimize these loggers for multi-year deployments in the 2018 Sensors article (free to download). The research loggers are a more challenging build, that fits inside an underwater housing made from PVC pipe

Addendum: Power Management (Optional)

On the standard build described above, the Pro-Mini’s MIC5205 power regulator should deliver  sleep currents below 0.25 mA (Pro Mini ~0.05 mA + sleeping SDcard ~0.05-0.09 mA + RTC ~0.09 mA). That should reach several months operation on 3 AAA cells before the batteries reach the regulators 3.4v input cut-off.  I usually have regulated loggers go into shutdown mode at ~3.6v to reduce the chance of leaks, because alkaline batteries often spill their guts when they reach 1v/cell.

There are a couple of relatively simple modifications to the basic logger that more than double the operational time – but they both come with important implications you should understand fully before adding them to your project. The RTC mod is relatively safe, but running a datalogger from a raw battery supply is not for the faint of heart. 

1) Cutting the VCC leg on the DS3231 chip forces the RTC to run from the coin-cell. >Set Bit 6 of CONTROL_REG 0x0E to enable wake alarms from the backup battery!

2) Remove the regulator: few LDO’s have reverse current protection & most regs leach 30-90 uA if the voltage on output line is  higher than on their input

2) Then connect the positive wire from a 2X LITHIUM AA battery pack directly to the Vcc rail on the Pro Mini

The DS3231 RTC was designed to handle power supply failures by switching over to the backup coin-cell battery, and it enters a special 3uA “timekeeping mode” to use less power in that situation. However the chip is still fully capable of generating alarms (provided you set the Battery-Backed Square-Wave Enable bit of CONTROL_REG 0x0E to 1) , and of responding to the I2C bus at 400 mHz. So if you cut the main power leg on the RTC you reduce the loggers sleep current by almost 0.1mA (~40%). The trade-off is that your loggers operation is now entirely dependent on the 200mAh CR2032 coincell to keep the clock delivering wake-up alarms when you are also asking it to deal with pulsed loads in the 80 uA range every time you communicate over the I2C bus. Another quid pro quo here is that coin-cell holders occasionally lose contact very briefly under vibration, so if you cut the Vcc input leg – add  a  0.1 μF capacitor (ceramic 104) across the coin-cell holder pins. That will give you about 80 ms coverage, which should be longer than the holder will lose contact. Otherwise a hard bump can reset the RTC back to its Jan 01 2000 default.  The wake-up alarms usually continue after that kind of reset, however fixing an entire years worth of time series data based on your field notes is a pain in the backside.  Real world installations often involve this kind of rough handling, so I prefer a more advanced RTC modification that keeps two power lines feeding the RTC.  But for more “gentle” deployments, simply cutting the chip leg & adding a cap should be OK. Write the installation date on the coin cell with a black marker. I do this to all of my batteries now…

For loads in the 0.1mA range, the MIC5205 is about 50% efficient. So the other modification is to remove the voltage regulator and run the entire system from 2x LITHIUM AA batteries.  Lithium batteries (like the Energizer L91) have two characteristics that make them well suited to this approach: 1) they have an extremely flat discharge curve, yielding >75% of their power before the voltage falls below 1.5v/cell and 2) a pair of brand new lithium cells gives a combined voltage just a wee bit over 3.6 volts. If you look at any of the SD card manufacturers’ specifications, they all specify a voltage range of 2.7v to 3.6v.  At 8 MHz the ATmega328P processor on the ProMini supports voltage levels between 2.7 V and 5.5 V. Both of these ranges overlap beautifully with the lithium cell’s discharge curve.

Here I’ve done both modifications to the basic build, and brought the sleep current (with no sensors) from an unmodified starting point of 228μA, down to 80μA. Most of that remaining power is due to the sleeping SD card, since the Pro Mini only draws about 5μA in deep sleep mode. Using only 1/2 of the 3000 mAh capacity of a typical AA Lithium pack would keep a logger that sleeps at 0.1mA alive for more than a year, and my rough estimate is that the RTC mod will get you at least twice that much time from a new Cr2032 cell – with a typical 5-15 minute sampling interval.      [NOTE: I’m using an EEVblog uCurrent here to display the μA sleep current on a DVM as milivolts. It’s an exceedingly useful tool that lets you read sleep currents into the nano-amp range without adding the burden voltage you’d see from putting your meter directly into the circuit ]

The other cool thing about this modification is that the processor on the Pro Mini can take a reading of it’s rail voltage by comparing it to the 1.1v internal band-gap reference. So all you need is a little bit of code, and you can keep track of your rail=battery level without a voltage divider.  Unlike alkaline batteries, lithium cells have very little voltage droop with brief loads below 100mA, but it’s still a good idea to protect your SD card from potentially data corrupting 5-10 ms low voltage spikes with a beefy capacitor. Adding a 47uF (or larger) on the microSD rails should keep those transients away, and once the system reg. has been removed running a jumper between Vcc & Raw recruits the orphan (10uF tantalum) capacitor from the input side of the (now removed) regulator.  Always check the supply voltage before the data saving begins and perform a low voltage shutdown when the lithium pack reaches 2875mv. (ie: at least 150mv above the SD’s 2.7v safe writing minimum). Generate a new data file every couple of weeks so only the last one is vulnerable during the write process. 

Thermal response of 2x LITHIUM AA’s supplying power to an unregulated build running the same code from GithubThe key observation is that the initial 50mv supply voltage variation recorded at 22°C increases  ~100mV at temps near -15°C. For Lithium chemistry batteries with flat discharge curves, the voltage-drop under load is often a better indicator of the remaining battery capacity than the cell voltage. (Readings taken AFTER SD CARD SAVE, Sampling every 1 min, overall sleep current 0.17mA   Note: the 200mv baseline drop on the cells is slightly exaggerated here because low temps increase the bandgap slightly) 

Of course everything has a price, and removing the regulator means you’ve not only lost your reverse voltage protection – you also need to think about how all the components in your system will respond to a decreasing supply voltage over time. Ratiometric analog circuits using the rail as Aref handle this well, but even if you want to use the 1.1v bandgap ref – you already know what the rail voltage is, so you can easily throw a compensation factor into the calculation.  The real problem is that when 2.7 – 3.6v is listed on the spec sheet for a digital sensor – that’s no guarantee the readings will be consistent when the supply voltage changes.  You could have very different error percentages at the high & low end and ambient temperature fluctuations could push your batteries through significant voltage changes every single day (lithium cells are more resistant to this than alkaline).  Testing is the only way to find out if your sensors can handle the variation, and if you don’t have time for that it might be worth keeping that voltage regulator on board despite the reduced lifespan. For field units, I usually replace the MIC5205 with a more efficient MCP1700 regulator because I want all the data consistency I can get.  Another thing to keep in mind when you are hoping for a really low-power build is leakage currents through leftover flux – it’s always worth the time to get your parts squeaky-clean during construction.

Tutorial: Adding the SSD1306 OLED Screen to an Arduino Logger (without a library)

An SSD1306 OLED screen mounted on a climate station build.

This is the third installment in a series on adding output screens to Cave Pearl Data loggers. It builds on the Nokia 5110 LCD tutorial and the post describing how I store fonts in the Arduino’s internal EEprom to save program memory – so you might want to have a look at those two posts before diving in here.

While the Nokia 5110’s are a cheap, low-power option with great visibility in full sun, they reacted badly to pressure directly on the LCD surface.  Since this project deploys loggers in an underwater environment I went looking for something more robust and the SSD1306 OLED’s caught my attention. (@ ~$3.50 on eBay) These little screens are showing up in hacked toyscompasses, GPSanalog meters, ECG’s, and theres even a tiny oscilloscope project at Hackaday. But those applications typically use the u8g2 library which is fantastic for graphic output, but also quite memory intensive; what I need is a bare bones solution that uses the fewest system resources on a unit that’s already near memory limits. Though these 0.96 inch displays are quite small, 128×64 pixels lets you render several lines of readable text.

While the I2C variants of this screen are easy to use, the SPI version lets me re-purpose unused analog lines to drive this display without interfering with the sensor or SD card bus because it can be driven via shift-out on any pins that are available. Powering the screen from A0 brings the screen down to zero current while the logger is sleeping, and also lets me get rid of the Reset & Cable Select lines. The only thing to watch out for is that you bring all the control lines low when you cut power so that reverse bias doesn’t end up “back powering” the screen controller.

Connecting the OLED:                                {Click any image to see larger versions.}

The data sheet for the SSD1306 controller specifies that the reset input needs to be LOW, during initialization, after which the pin should be HIGH for normal operation. To achieve this low -> high  transition, I tie the Reset line to the middle of an RC bridge made from a 104 (0.1uF) capacitor and a 10k resistor. When you add the 25k inside the 328p used to pull A0 high, you get a 63.2% time constant of about 3.5ms.

Begin by tinning the pins, and bending them 90 degrees for alignment with the RC bridge which also connects to the CS pin.  Once that delayed rise circuit is soldered in place, also jumper the incoming GND line over to Cable Select. You would not do this if the display was on the normal hardware SPI bus, because it would exclude other devices on the SPI bus. But since we are using a separate set of wires for the display we can get away with this trick.

The connections for the SSD1306 OLED display are the same as the ones for the Nokia 5110: (D0=clock, DC=command, D1=data in)  Note that I’m not using the 3.3v rail from the pro-mini,  and YOU MUST BE USING A 3.3V ARDUINO FOR THIS WIRING TO WORK UNLESS YOUR OLED BOARD IS 5V TOLLERANT.  Some of the breakouts  from eBay are OK at 5v, and some are not – check THIS before you buy if you are using a 5V Arduino.  (Note that  most breakouts sold by Adafruit include regs & level shifters to handle both voltages.)

When all the incoming lines have been added to the board, thread them through the housing and verify that the screen is still working. The analog A0-A5 lines on an Arduino can be re-purposed as digital I/O so I usually break them out with a 6-pin Deans Micro Plug (incl. GND & Vcc)  In this case the screens Vcc line is being re-routed to pin-powering from A0 so the pro-mini’s rail voltage is not used.  Cut away or heat-shrink over the unused Vcc pass-through on the screen side of the connector (which is still visible & exposed in the photo on the right) as you don’t want it accidentally contacting something later on inside the housing.

After the operation test, cork the pass-through hole with a bead of plumbers epoxy putty  about the size of your fingertip. Wrap that putty so that it is on both sides of the wires before smoothing it down on the housing.  (The sensor cap shown below has four housing penetrations sealed by this method)  On the top of the sensor cap, wrap a grape-sized lump of well worked putty around the wires on the back of the screen. Then carefully press the screen down into the PVC well so that the putty compresses into a support pillar that holds the screen as near level as possible. The putty hardens in about 10 minutes and then you can pour the first layer of potting epoxy. Here I’ve used Loctite HYSOL E-60NC, with a 50ml applicator & MA6.3-21s mixing nozzles. The air space for the reflective back light forced me to use clear epoxy with the 5110 LCD screens, but since these OLED’s emit their own light, you can bring that black epoxy right to the edge of the display – covering the board & any ugly soldering… 🙂  Check the epoxy over the next couple of hours and pop any bubbles that rise to the surface with a pin. 

Always TEST before potting!

Let that initial layer of epoxy cure for 24 hours, then drill a 7/32″ hole at a safe distance away from the screens edge. Mount an RGB indicator led inside the housing and seal it in place with plumbers putty. At this point you can simply add a second layer of clear epoxy to protect the screen, but in our experiments with the Nokia LCDs, seawater caused a serious fogging problem.  So I recommend a top surface of more chemically resistant material for that kind of application. Here I’ve used a 1/4″ thick plexiglass disk (~$0.35 each on eBay)
First apply a thin layer of clear epoxy over the screens surface so that it self-levels to thickness of about 1-2mm. Then hold the edge of the acrylic disk and carefully tilt it over the epoxy film with an even contact edge that moves across the disk slowly enough to let the air escape.  Don’t make that first layer of clear epoxy too thick or it will over-top the edge when the plexi settles into place and this will form blobs on the surface. Once the acrylic is in place, you can slowly add drops of epoxy on the side to bring the level up to match the edge.  Give the clear epoxy another 24 hours to cure.

The display draws more current as you increase the number of pixels turned on.  As a point of reference: the screen output shown above (generated from the code on Github ) draws 3.4 mA.  And I haven’t seen any nasty current surges that might exceed the pin limit when the display is first powered up.

The shore hardness of the plexiglass is not much higher than cured epoxy, but the optical clarity is considerably better. The photos in this post don’t capture it well, but this mounting method really shows off the razor-sharp output you get from an OLED, and it’s readable from just about any angle.  For surface loggers a 1/8″ disk should provide sufficient protection, but for the underwater units I will use 1/4″ thickness to resist the compression at depth. I won’t be able to test those underwater versions in the real world for a few months, but if the acrylic fails I will change to  a stiffer glass overlay.

A few might wonder why I added an indicator LED when the logger now has full display capability. There are plenty of situations where brief LED pips communicate the progression of duty cycle events that are too fast and too numerous for screen output. I also use the LED as a noise generator when I want to squeeze higher resolution from the ADC through oversampling.  These days I add an NTC thermistor to every build to capture ambient temperature.

The Code Example on Github uses a cascading method to break text strings up for single character rendering with : oledWriteString–>oledWriteCharacter–>oledWriteData  and I’ve co-opted that with a new split-character method to print larger numbers to the screen in a two-pass method.  The shift-out code for those functions is basically the same as that used for the Nokia 5110. I went over all that in some detail in the earlier posts so I wont re-fry those beans here. The key thing to keep in mind is that this new screen driving script uses EEPROM.read which assumes you’ve already loaded the font definition(s) into your Arduinos internal eeprom with this helper utility.  That utility loads a ‘reduced’ font set to leave 500 bytes of space for file header data in the EEprom as well. (so the 5×7 font is caps only, and large characters are #’s only).  If you don’t need that level of memory optimization in your build, you can switch back to simply storing the screen fonts in program memory;  just transfer the PROGMEM based string->character->data functions (and the font arrays) over from in the NOKIA 5110 code example.

The housekeeping functions that take care of  initializing the screen, clearing the memory, and setting the XY position are more complex for the OLED than those for the PCD8544 Nokia because the SSD1306 controller has more operating parameters.  But the overall approach transferred easily between the two controllers and I suspect this method could be re-used with most of the larger SPI OLED screens on the market (like the SH1106) provided they stay below the pin current limit on A0.

Time to go shopping!  🙂

 

Addendum 20181019:

A helpful commenter has informed me that it’s possible to try a similar approach with I2C screens because you can bit-bang I2C devices over any two spare wires.  Now that we’ve pulled off this isolation trick with SPI, I’ll look into bang’n as a way to shut down high current I2C sensors when they are not in use.  I’d want those off the regular I2C bus because it necessarily has a few “always on” devices that might not respond well to a lump of dead wood hanging off the same wires.

Starting Points & Ideas for your Arduino STEM Curriculum

Arduino Starter Kits can be assembled from $10 to $100 per seat depending on the complexity of your course. We generally order parts about a month beforehand and then spend a day pulling it all together into “ready to go” lab kits at the start of term.

Over the last decade the open source Arduino platform has been embraced by STEM educators, and there are a growing number of pay-per-use resources available with pre-made lesson plans, etc. (eg: becauselearning.com While most welcome viable business models in the sector, it struggles against the problem of ever shrinking education budgets. Where the rubber meets the road you are faced with the stark reality that many teachers now have to pay for teaching materials with their own money:

“Classroom teachers spent an average of $468 out of pocket on classroom supplies and equipment in the last year — amounting to nearly 1 percent of an average teacher’s salary in the United States. Nearly eight in 10 teachers — 77 percent — spent “at least” $200, with some as high as $5,000, according to the latest results of an annual survey.”


With that in mind, I’ve started this list of links to STEM learning resources, curriculum, and activities for Arduino.  Unlike more formalized lists of this type, the focus here will be on creative IDEAS and resources that teachers can access for FREE ( eg: WeTeachNYC’s Gr9 lesson plans , textbooks online, etc.)

This page will grow over time as I find more material:


Arduino project IDEAS:

Any teacher worth their salt already knows how to make lesson plans, so the tough part is finding a theme that really motivates your students.  If you are looking for science project ideas, it wouldn’t hurt to browse through a few commercial data logger websites sites to see how people use loggers in the real world. Then search through the Arduino sensors forum and see if someone has already posted helpful information about the application your students find interesting.  Though the Cave Pearl Project is focused on environmental monitoring, you should’nt overlook the other cool things that people do with Arduinos for more information on integrating sensors (eg: building instruments like the TC1 slinky seismometer) Browsing through the Arduino project hub gives you some sense of the range.  A good number of artists create interactive pieces by adding motion, sensing, LEDs & sound. Wear-able projects are also pretty groovy.  Others create simple robots with their Arduinos, and there are plenty of body/wheel/motor kits to get you rolling. Drones get all the media attention, but I think underwater ROV’s are also interesting.

There are lots of great maker resources to search through if can appreciate their sense of humor (though you might want to avoid clock projects 🙂  Intructables is heaving with Arduino projects which you can find simply by searching for “Arduino” + “subject”.  If you find an Arduino book that sounds interesting, there is a good chance that there are sample projects on the web from the book that you can review.  GPS tracking opens up interesting possibilities and the folks over at the RIFFLE project have been pulling that location data out of digital camera photos, with their data logger hanging from a kite.  So really, the sky is the limit . . . or maybe not even that . . . commander Sparkles.


Most ” Discovering Arduino ” resources follow a pattern something like this:

Introduction of the Arduino board. (hardware)
Introduction of the Arduino programming environment and the structure of a script. (software)
Introduction of the breadboard. (hardware)
Blinking the internal LED at pin 13. (software)
Connecting a LED to Arduino using a breadboard. (hardware)
Using a digital output pin to blink the LED. Using multiple digital output pins & leds (software)
Pulse-width modulation for fading LEDs. (software)
Connecting a button to the Arduino, with de-bouncing cap/resistor combination. (hardware)
Programming  to support the button input , if/then/else conditional behavior. (software)
Introducing the serial monitor for text output of events (software)
Connecting analog sensors to the Arduino with voltage dividers. (hardware)
Capturing sensor readings with the ADC and storing them in a variable. (software)
Using the serial plotter for live display of sensor output (software)
Advanced programming concepts (e.g., for/while loops, counters, switch/case). (software)
Connecting digital bus sensors with pull-up resistors (usually I2C or OneWire ) (hardware)
Including code libraries to so you can read data from those digital sensors (software)

As you can see, learning the Arduino platform is like climbing a ladder, where each step you take toward understanding the electronics is matched by one learning how to write code.

Where To begin:
The instructables beginners guide is a good place to start, as is Udemy’s free Learn the Basics Arduino Tutorial. Actually instructables has been busy building a range of free beginners classes on subjects from the internet of things to 3D printingetc.  There are plenty of other “Getting started” videos available with  another free video course offered at the Programming Electronics Academy (also see their other Youtube videos). Many of these courses require some kind of registration, and given the nature of their business you can expect a fair amount of self promotion messages to be peppered throughout. And finally, don’t overlook the official Arduino example tutorials that come built into the IDE. There are some great learning examples in there like the Tone Pitch follower with tutorials by Massimo Banzi himself.

Special Mention:
Be sure to check out Jeremy Blum’s Arduino Tutorials which are essentially a complete course on the Arduino;  all the more impressive because he did the entire thing as a one-man-band while he was still a student.  In my opinion,  the best quality videos available for Arduino are the ones created by Jeff Feddersen & Tom Igoe for the ITP program at NYU, though there’s a lot to wade through, and some of those tutorials might be pitched at too high a level for beginners. Paul McWhorter also has an extensive tutorial series on youtube.

And don’t forget to search for the many new videos that people have posted. Youtube has grown into a universal self-teaching tool and we’ve entered the game with clips from our fieldwork, and build tutorials.

Arduino in a Nutshell is a free e-book resource worth looking into, as is the Programming Guide from instesre.org. And though I’m not sure if they are still a going concern, the old Earthshine Starter kit manual PDF can still be found floating around the internet. If e-books like that are your thing, and you are willing to shell out a few bucks, there are sometimes good Humblebundle deals, though those are often in weird combinations of topics, and the individual books also available the Make website.

Sparkfun is also a great place to look for teacher resources.

It’s a lot to wade through, but the Adafruit tutorial list  is another one of the best resources out there. Just be aware that they have developed their own library “system”, so sometimes their tutorials are tailored to that.

Tronixstuff has a large number of  specific hardware tutorials when you are ready to go further with your Arduino projects, and there are a host of cool Arduino projects to dig through at instructables site. I really believe that you can improve engagement and understanding by providing hands-on experience with real data, but there are plenty of other practical things you can do with the same basic setup.

If you google around, you can find curriculum documents, individual lesson plans, and other resources all over the place, like for example this conductivity lab over at teachengineering.org or this beginners set from Arduino 101.  The challenge is that most of the sites were developed for a different curriculum than yours, so first figure out what you want to tackle, then go sifting through the tutorial sites for material that matches your learning outcomes. Otherwise you will just get buried in the shear volume of it all.

If you want to abstract away the entire IDE interface for younger students, there are a few visual programming tools out there for the Arduino like Visuino, or MIT’s Scratch, for which there are plenty of tutorials on youtube.

Going further:
There is also a long set of more detailed videos at Makecourse.com. Though it’s a bit dry, All About Circuits has a complete textbook online [see: Vol. I – Direct Current (DC) ] And if you really want to dig deep, several universities like Stanford, MIT & Berkeley have made full electronics courses available, though that goes well beyond the Arduino landscape. There is a good walk through the sub-components that make up an UNO at Rheingold Heavy’s build an Arduino From Scratch series.  And I’d be remiss if I didn’t mention the Mini-notebook series that that Forest Mims wrote back in the 70’s.


Using Social Media to find resources:
Like Pinterest, Reddit has grown into one of the most useful social media sites for leveraging other peoples knowledge to help you find useful resources.  I’ve compiled a short list of places that might be good starting points.  You can also find material with the right hashtags on twitter such as #DIYscience.  But social media like Twitter/Facebook/etc can easily waste as much of your time as it saves, so finding good material is directly related to how particular you are about following people who actually contribute resources to the community (as opposed to those who are merely talking about it)

A few Teacher & Maker sub-reddits:

Teaching & Education
/r/ScienceTeachers/ – Chemistry, Biology, Physics, Astronomy, and General Science for K-12
r/matheducation
r/education -news articles about America’s education system, from Pre-K through PhD
r/teaching

Electronics:
/r/arduino – Arduino and compatibles. Lots of projects posted, discussion leans more towards programming with dabbling in circuit design

/r/electronics – About electronic circuit design and occasionally embedded systems
/r/raspberry_pi – Discussion about the Raspberry Pi & /r/raspberrypi
/r/embedded – Similar to /r/arduino and /r/raspberrypi but not platform specific
/r/3Dprinting – 3D printers

Others that instructors may find interesting:
/r/diy – The granddaddy of them all. Largely focused on home improvement but has content from just about everything.
/r/crafts – Sewing, knitting, scrapbooking, kids crafts, etc. and /r/craftit – Smaller version of /r/crafts
/r/somethingimade – Largely arts & crafts related, occasional woodworking or self made website posted
/r/maker – For people who make things. Doesn’t seem to be very active.
/r/woodworking – 50/50 between using power tools and hand tools. Wide variety of projects posted from simple to “they must be professionals”
/r/metalworking – Stuff you can do with metal
/r/welding – Welders, machinists and all other enthusiasts of joining two things together
/r/outstruments – Musical instrument making
/r/lego – Lego is made of ABS plastic and you can use a tiny dab of ABS plumbing solvent (nasty stuff!) to weld it together into a custom bullet-proof housing for your Arduino project. Great for internal scaffolding too.  also see /r/AFOL – Custom designed LEGO creations.


YouTubers on Science & Technology:

Like the other flavors of social media, YouTube can give a boost to your STEM lessons, provided you don’t go down that rabbit hole until after you already have clear lesson outcomes in mind.  It’s hard to pick a favorite, but Ben Krasnow @ Applied Science might take the title because he does incredible things without the over-the-top wow-yuck factor that the media seems to feel is the only way to make science interesting.  When Ben wants an electron microscope – he builds one.  Super Conductor? ditto. Plasma tube? easy-peasy.

Life, the universe, & everything:
Veritasium – An element of truth – videos about science, education, and anything else
Kurzgesagt – In a Nutshell – finding a new way to end the human race with every video
SciShow – delves into popular scientific subjects with lots of flash for younger audiences
Physics Girl – Physics videos for every atom and eve
Vsauce – Michael Stevens combines discussions of science and philosophy
BrainCraft – Vanessa Hill explains why we humans act the way that we do
ASAPscience  -explains topics in science with their trademark kinetic typography and drawings
minutephysics -physicist Henry Reich explains physics concepts simply  in a few minutes
It’s Okay To Be Smart

People who put things together:
Kevin Darrah
Julian Ilett – the Bob Ross of makers
Electronic Basics by GreatScott
Adam Savage’s Tested

People who take things apart:
bigclivedotcom – random take apart videos from expensive toys to cheap junk from China

People who explain how things work:
Engineerguy
Real Engineering
Practical Engineering
3Blue1Brown:  Brilliant animated introductions to complex math subjects

The Do-ers:
Smarter Every Day-engineer Destin Sandlin films himself doing his own experiments
Mark Rober
Cody’sLab
The Slow Mo Guys
Mike Boyd

The Story Tellers:
Curious Droid (Paul Shillito)
LindyBeige
Knowing Better
The Good Stuff
TedX Talks

The incomparable Colinfurze.  Close tie for the #1 spot because Colin is kind of like Ben Krasnow’s unhinged alter-ego from some parallel dimension where humans have very short lifespans.  Like ArduinovsEvil , and the site-which-must-not-be-named, this highly inappropriate material is best viewed at 1am when you’ve already killed off any high-function brain cells with a 10-hour exam marking marathon. (ie: Don’t show Colin’s videos to impressionable young minds unless you want to be fired, and never show content from AvE, and IFLS without serious vetting)


Other inspiring links:

What’s the Maker Movement and Why Should I Care?

The Maker Movement in K-12 Education: A Guide to Emerging Research

Progressive Education and The Maker Movement

TED Talk – Massimo Banzi (the primary founder of Arduino) – How Arduino is Open-Sourcing Imagination

Hans Rosling as an advocate for a “fact-based worldview” with his amazing bubble charts.

Using Arduino’s Internal EEprom to Store Data & Screen Fonts

This tutorial is the second in a series on adding displays to expand the capability of the Arduino data loggers described in our SENSORS paper earlier this year. As more of those DIY units go into the field, it’s become important that serial #s & calibration constants are embedded inside the files produced by each logger.  One can always hard-code that information, but with multiple sensors and screens for live output, space is getting tight:

This prompted me to look at the ATmega328p’s internal EEprom as a potential solution. The EEprom can only store one byte per location, so saving numbers larger than 255 requires you to slice them up and store them in consecutive memory locations. That takes two locations for a the “high byte” and a “low byte” of an int, and four memory locations for longs & floats. That’s a little clunky but it mirrors the way you read & write high-bit registers on I2C sensors, so there are lots of code examples out there to follow.  Piece by piece approaches also require memory pointers for retrieval and re-assembly of your variables.

A more elegant method is to roll them into a single ‘struct’  and store that with a generic function, but even with read_block & write_block I’d still be tweaking the code for each logger, since they often have dramatically different sensor combinations.  I wanted a more generic “cut & paste” method that would handle file headers and variable boiler plate info ( contact emails, etc.  ) without me having to update a bunch of pointers.  The real clincher was realizing that the equation constants generated by my thermistor calibration procedure had too many significant figures to store in an Arduino float variable anyway.

A char array provided the simplest way to achieve the flexibility I was after, and I wrapped that up into a little “EEprom loader” utility:             (Note: Github link at the end of this post)

#include <EEPROM.h>
#define PADLENGTH 1024
char eepromString [PADLENGTH+1];    //+1 to leave room for null terminator

void setup(){
strcpy(eepromString," ");
strcat(eepromString, "\r\n");      // a carriage return in Excel
strcat(eepromString,"#198, The Cave Pearl Project");
strcat(eepromString, "\r\n");
strcat(eepromString,"Etime=(raw*iSec)/(86400)+\"1/1/1970\"");
// NOTE: \ is an escape which lets you put "special" characters into the string 
strcat(eepromString, "\r\n");
strcat(eepromString,"Tres=(SeriesOhms)/((((65536*3)-1)/Raw16bitRead)-1)");
strcat(eepromString, "\r\n");
strcat(eepromString,"1M/100k@A7(16bitP32@1.1v),A=,-0.0003613129530,B=,0.0003479768279,C =,-0.0000001938681482");
strcat(eepromString, "\r\n");                 
// following this pattern, simply add more lines as needed (up to max 1024 characters)

// This fills the remaining unused portion of eepromString with blank spaces:
int len = strlen(eepromString);  // strlen does not count the null terminator
memset(&eepromString[len],' ',PADLENGTH-len);

// Now write the entire array into the EEprom, one byte at a time:
for (int i = 0; i < 1024; i++){ 
EEPROM.update(i, eepromString[i]); 
}
}

void loop() {
// nuthin here...
}
 

This is just a bare-bones example I whipped up, and it’s worth noting that strcat will overflow if you try to add more characters than eepromString can hold.  You can check your count at sites like lettercount.com  or try using snprintf() as an alternative without that problem. Since this is a ‘run-once’ utility, I haven’t bothered to optimize it further.  Bracketing calibration numbers with a comma on each side makes them directly usable when the CSV data file is loaded into Excel later because they end up inside their own cell.  It’s a good idea not to avoid putting EEPROM.write codes inside the main loop, or could accidentally burn through the limited write cycles of your internal EEprom. EEPROM.update is the safer than EEPROM.write, because it first checks the content of each memory location, and only updates it if the new information to be stored is different.

With the data stored in the EEprom, it only takes a few lines to transfer that information to the SD card when a new file gets created:

char charbuffer[0]=" ";  //a one character buffer
file.open(FileName, O_WRITE | O_APPEND);
for (int j = 0; j < 1024; j++) {
 charbuffer[0] = EEPROM.read(j);
 file.write(charbuffer[0]);
 }
file.close(); 

The spaces used to pad out the array so that it fills all 1024 bytes of the EEprom do create an extra blank line in the file, but that’s a pretty harmless trade-off for this level of code simplicity.

What else can we store in the EEprom?

In the post covering how to drive a Nokia5110 LCD using shiftout, I went into some detail on the way the fonts for that screen were created and displayed. Three simple cascading functions (originally from Julian Ilett) let you send any string of ASCII characters to the screen.

void LcdWriteString(char *characters)
{
while(*characters) LcdWriteCharacter(*characters++);
} 
void LcdWriteCharacter(char character)
{
for(int i=0; i<5; i++){
LcdWriteData(pgm_read_byte(&ASCII[character - 0x20][i])); 
}
LcdWriteData(0x00);            //one row of spacer pixels between characters
} 
void LcdWriteData(byte dat)
{
digitalWrite(DCmodeSelect, HIGH);    // High for data 
digitalWrite(ChipEnable, LOW);  
shiftOut(DataIN, SerialCLK, MSBFIRST, dat);  // transmit serial data 
digitalWrite(ChipEnable, HIGH);
} 

I modified that code that slightly with reduced font-set arrays stored in PROGMEM and introduced a method for displaying larger numbers on screen by printing the upper and lower parts of each number in two separate passes.  PROGMEM requires pgm_read_byte to get the data out of the 2-D arrays for printing.

Now, with a little bit of juggling, a “loader” script can store that font data in the 328P’s internal EEprom by converting the two dimensional font array into a linear series of memory locations:

const byte ASCII[][5] PROGMEM =  
{
{0x00, 0x00, 0x00, 0x00, 0x00} // 20 
,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &
,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 '
,{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (
,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 )
,{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *
,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +
,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,
,{0x08, 0x08, 0x08, 0x08, 0x08} // 0x2d (dec 45) (-) in row 13 of source array
,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .
//...etc, a complete font is in the array, but I only store a 46 character "caps only"
// subset in the eeprom ranging from (-) at array row 13 to capital (Z) =array row 59
// this takes 235 bytes of EEprom memory storage (addresses 0-234)
} 

// move that sub-set of the font (13 to 59) from PROGMEM into the 328's internal EEprom
currentIntEEpromAddress=0;   // each letter is constructed from 5 byte-collumns of data
for(int i=13; i<59; i++){    // so each i value forces a 5-byte jump in EEprom address
for(int j=0; j<5; j++){      // while j value counts through each individual column
charbuffer=pgm_read_byte(&ASCII[i][j]);  // i&j used separately in the array
currentIntEEpromAddress=(((i-13)*5)+j);  // i&j combined for the EEprom address
EEPROM.update(currentIntEEpromAddress,charbuffer); //update to save unnecessary writes
}

Once the font has been transferred into the internal EEprom by the loader program, I only need to make two small changes to the original display functions so they pull that font from the EEprom. Note the calculation trick (character-0x2d) which uses the ASCII code for each character to calculate where the first of the five bytes is located for that character:

void LcdWriteCharacter(char character)
{
for(int j=0; j<5; j++){
LcdWriteData(EEPROM.read(((character -0x2d)*5)+j)); 
//we subtract 0x2d because the zeroth position in EE memory is (-) = ASCII(0x2d)
}
LcdWriteData(0x00);            
} 
// (character - 0x2d)*5 jumps 5 bytes at a time through the EEprom address space
// Add a fixed offset for other fonts stored at higher locations in the memory: 
// eg: LcdWriteData(EEPROM.read(235+((character -0x2d)*5)+j)); 
// the big#fonts are 11 byte-columns wide, so calc = (Offset+((character -0x2d)*11)+j)

This adds some delay, but because the Nokia 5110 is already dead-dog slow it’s not even noticeable.  A similar mod gets applied to the split print functions for the big number font, and moving both to the EEprom still leaves a very serviceable 500 characters for file header info.  The trick to stacking different kinds of information in the EEprom is figuring out what the resulting address offsets are so each reading function starts at the correct memory address. You skip over the memory locations holding the font data when transferring that file header text.

With fonts stored in EEprom, the remaining Nokia 5110 functions compile to just a little over 400 bytes of program storage and 10 bytes of dynamic (excluding EEPROM.h, which gets called by some of my other libraries even if the screen is not present)  That’s with three duplicate copies of each LCD function because I’ve used a set for the standard size font, and two more for printing the large numbers in upper & lower rows.  With a bit more optimization I could get that down to about 200 bytes, which I suspect is probably the smallest memory footprint achievable for adding live data output to my loggers.

I’ve posted a ‘EEprom loader utility’ which demonstrates the dual Font/Text approach at our Project’s GitHub repository  so people can modify it to suit their own projects. On loggers with a number of DS18b20 sensors, I’ll use a similar approach to store the sensor bus addresses, which I usually store in two dimensional arrays very similar to those shown here for screen fonts.

Using the Nokia 5110 LCD with an Arduino Data Logger

Here I’ve added a the 5110 LCD to a logger recording data from a BME280 & Tipping Bucket Rain gauge. If the BME  survives in our field environment, this will become a standard configuration for our climate stations. I’m not holding my breath though, as we’ve tested half a dozen RH sensors so far and none of them have gone the distance in high humidity environments that occasionally go condensing.

This year I want to tackle some projects that need live data out, so I’ve been sifting through the many display options available for Arduino. Unlike flashier projects, my goal was to find one that I could add to existing logger builds without sacrificing too much of the multi-year lifespan I had worked so hard to achieve. The low power winner by a fair margin was the Nokia 5110 Liquid-crystal Display  which you can pick up for around $2 from the usual sources. With the back-light off these displays pull between 100-400 μA, depending on the number of pixels turned on.

This screen uses a PCD8544 controller and the SPI protocol.  It will tolerate 5V, but it works best at 3.3V, which is perfect when you are driving it from an 8mhz ProMini. Each pixel on the display is represented by a single bit in the PCD8544’s RAM. Each byte in RAM correlates to a vertical column of 8 pixels. The X coordinate works on a per-pixel basis, and accepts values between 0 and 83. The Y coordinate accepts values of 0 – 5 which on this 48 pixel high screen, corresponds to 6 “rows of bytes” in the controller’s RAM. So bitmaps can only be displayed on a per row (& column) basis. The display is quite sluggish compared to competitors like the 0.96 I2C monochrome OLED and you have to handle any processing overhead on the Arduino.

Most hookup guides assume that you can spare six control lines to run the display, which is not the case when your logger already has three indicator LEDs, I2c devices, one wire sensors and a couple of voltage dividers on the go.  However if you are willing to add a few resistors and occasionally toggle the power, you can bring that down to three wires and a power pin.

So many libraries, so little optimization…

This screen’s been around for a very long time, so there’s are a huge number of easy to use, highly functional libraries for Arduino. But they tend to focus on things like speed or endless font options which are not important for most data logging applications. And these libs assume your project can afford to lose up to ⅓ of the available program & variable memory just driving the display. Most also require the hardware SPI lines, but our project needs those for SD cards, which are finicky enough without some pokey LCD gumming up the works: the 5110 maxes out at 4mbps, and this slows the bus significantly .

Those fat libs were non-starters for our project, and I had almost given up on this display when I found Ilett’s Ardutorial offering a bare-bones method more suitable for our resource limited data loggers. If you haven’t discovered Julians YouTube channel yet then you are in for a treat because if Andreas Spiess is the maker worlds answer to Werner Herzog, then Julian is surely their equivalent to Bob Ross.  I don’t know if he’s growing “Happy little trees” with his DIY hydroponics, but I can say that the gentle timbre of his “Gooood morning all” reduces stress faster than a warm cup of Tea.  And his “Arduino sandwiches” are brilliant examples of minimalist build technique.

Driving the Nokia 5110 with shiftout

Everything I’m presenting here builds on his tutorials, so grab a mug and give ’em a watch:

Tutorial #1 – Connecting and Initial Programming
Tutorial #2 – Getting Text on the Display
Tutorial #3 – Live Numerical Data

This software SPI method (originally from arduino.cc?) requires no library at all, and shiftout commands work with any combination of digital pins; saving those hardware SPI lines for more important jobs.

Initial setup is explained in video #1 using two functions

void LcdInit(void)
{
digitalWrite(RST, LOW);            // not needed with pin powering!
digitalWrite(RST, HIGH);           // see below for details
LcdWriteCmd(0x21);                 // extended commands 
LcdWriteCmd(0xB8);                 // set Vop(contrast) // you may need to tweak
LcdWriteCmd(0x04);                 // set temp coefficient 
LcdWriteCmd(0x14);                 // bias mode 1:40 // you may need to tweak this
LcdWriteCmd(0x20);                 // basic commands 
LcdWriteCmd(0x0C);                 // normal video
for(int i=0; i<504; i++) LcdWriteData(0x00);  // clear the sceen
} 
void LcdWriteCmd(byte cmd)
{
digitalWrite(DCmodeSelect, LOW);    // low for commands, high for data 
digitalWrite(ChipEnable, LOW);      // not need with pin-power
shiftOut(DataIN, SerialCLK, MSBFIRST, cmd);  // transmit serial data 
digitalWrite(ChipEnable, HIGH);     // not need with pin-power
} 

After that you need is a function to position the cursor and a font stored in a byte array (in this example called ASCII[][5])

void LcdXY(int x, int y)
{
LcdWriteCmd(0x80 | x);              // Column
LcdWriteCmd(0x40 | y);              // Row  
} 

Then three short cascading functions let you send a string of ascii characters to the display:

void LcdWriteString(char *characters)
{
while(*characters) LcdWriteCharacter(*characters++);
} 
void LcdWriteCharacter(char character)
{
for(int i=0; i<5; i++){
LcdWriteData(pgm_read_byte(&ASCII[character - 0x20][i])); 
}
LcdWriteData(0x00);            //one row of spacer pixels between characters
} 
void LcdWriteData(byte dat)
{
digitalWrite(DCmodeSelect, HIGH);    // High for data 
digitalWrite(ChipEnable, LOW);  
shiftOut(DataIN, SerialCLK, MSBFIRST, dat);  // transmit serial data 
digitalWrite(ChipEnable, HIGH);
} 

Julians original implementation included a 500 byte 5×7 font.h file (which you can find at several locations) and  I’ve rolled that font array into some code based on his work and posted it to the Cave Pearl Project’s repo .  You will find lots of other examples based on the shiftout method on Github, but for some reason many people insist in retooling that tiny bit of code into, you guessed it, even more libraries

You’ll also find plenty of other drop-in font definitions with Google, but for small 5×7’s, it doesn’t take that long to roll your own by clicking the boxes in an online font creator. and then copying the byte pattern into a bin-hex converter. This also gives you the option of creating custom icons by using a non-standard bitmap for some of the less frequently used ascii characters. Keep in mind that you don’t need to store the entire alphabet if you are only sending a few letters to the screen (like ‘T+P’ or ‘RH%’, etc …) extracting only the letters you need to a reduced font array could save a lot of memory.

So your reduced font array could look something like this:

const byte ASCII[][5] =
{
{0x7f, 0x09, 0x19, 0x29, 0x46}  // 52 R
,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H
,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T
,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +
,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P 
};  

If you do that you’ll need to send text to the screen character-by-character because the ASCII based [character – 0x20] calculation won’t work any more.

I tweaked Julians code in a couple of important ways. First, I added PROGMEM to move the font(s) into the program memory space. Second, I added a method to print large numbers to the screen by repeating the same WriteString->WriteCharacter->WriteData pattern two times: once for the “upper half” of the numbers, and then again for the “lower half” of the numbers after re-positioning the cursor to the next line.

To make this limited large-number font I first composed a black & white bitmap for each number with a graphic editor, and then loaded that .bmp file into the LCD assistant program as described in this instructables tutorial.  I started with a bitmap that was 11 pixels wide, by 16 pixels high (though you can use any arbitrary size you want – just remember to leave the blank spacer row at the bottom) and for this two-pass ‘sliced-letters’ method I set vertical & little endian encoding in LCD assistant. I then put the top 11 bytes in the Big11x16numberTops[] array & the lower 11 bytes for each number in the Big11x16numberBottoms[] array.

It takes two passes to print each large number to the screen:

LcdXY (0,2);              //top half of the double-size numbers
LcdWriteBigStringTops(dtostrf(voltage,5,2,string));  
LcdXY (0,3);              //bottom half of the numbers 
LcdWriteBigStringBottoms(dtostrf(voltage,5,2,string));

And some slightly modified functions that refer to the corresponding number-font array:

void LcdWriteBigStringTops(char *characters)
{
while(*characters) LcdWriteBigCharacterTops(*characters++); 
} 
void LcdLcdWriteBigCharacterTops(char character)
{
for(int i=0; i<11; i++){
if((character - 0x2d)>=0){
LcdWriteData(pgm_read_byte(&Big11x16numberTops[character - 0x2d][i]));
}
}
LcdWriteData(0x00);  //one row of spacer pixels inserted between characters  
} 

Those number printing functions could be eliminated with better use of pointers, but I liked having the readability afforded by a few extra lines of code.

Reducing the number of control lines

The stuff I posted on Github assumes you are using a standard 6-pin arrangement shown in most Nokia 5110 hookup guides you will find on the web. But once I had that wrangled, I realized that it would be possible to reduce the number pins needed to drive the display.  You will have to tweak that default example by commenting out the RS & CS commands if you implement the pin-power changes I’m suggesting here… 

I use Deans micro-plugs  for multi-wire applications like this. The unused pin here is the normal Vcc, with the A0 pin-power supply indicated with a dash on the red line.

The shiftout method can be used with any pins you want, and most of my builds have A0-A3 available. With those dedicated wires the PCD8544’s chip select (CS) line can be connected to GND telling the screen that it’s always the selected device. This would be bad if it was connected to the hardware SPI lines shared with the SD card, but since we are using re-purposed anlaog lines, there is no conflict. One minor drawback is that since we are now using all the analog lines (I use A6 & A7 too) we can’t read a floating pin for RandomSeed().

Getting rid of the RESET line is a little trickier. The data sheet says that the RS line must be low while power stabilizes and should then be pulled high within 100ms of power on. Several people create an auto-reset situation by connecting the screens reset to the Arduino’s reset line. Others make the low-high transition with an RC network across the supply for a delayed rising signal. This can even be driven by the DC line (which is low in command mode and high in data mode) 

But I had something else in mind, since I wanted to power the entire display from a digital pin because the power draw with the display off is still about 70uA. This accumulates into a significant amount of wasted power over a multi-year deployment.

Reducing Back-light Current

OR … a photocell divider embedded in that clear epoxy would let you enable the backlight dynamically – with the appropriate mosfet for the connection type.

If you use the back-light in the default configuration, the screen can potentially draw up to 80mA (4 white LEDs at 20mA each). The back-light pin is usually connected to a transistor, so you can PWM all 4 LEDs at once for variable lighting control, but the peak currents are still too high for direct pin-powering unless you add some kind of series resistor.  A 10k pot gives you a simpler method to adjust the screen brightness, but I found that a 3k3 series resistor brought the total display current down to ~1mA with decent readability ( & blue LEDs are brighter than white).  Adding an in-line slide switch provides a way to completely disable the back-light for long deployments.  With the entire display safely below Arduino’s pin-current limit, you can then power it by writing a driver pin high or low in output mode.

#define n5110PowerPin  A0          // power the 5110 screen from pin A0 (RED)
#define n5110modeSelect A1         // 6.1.9 D/C: mode select (BLUE)
#define n5110SData A2              // 6.1.7 SDIN: serial data line (WHITE) 
#define n5110SCLK A3 ;             // 6.1.8 SCLK: serial clock line (YELLOW)
// lines not needed any more: 
// #define n5110RST  Now -> 4.7k to power A0
// #define n5110ChipEnable  Now -> GND

This gives you a way to perform a hard reset any time you want provided you tie the screens RS line to that switched power with a 4k7 pullup resistor, and re-run the initialization sequence after restoring power.

Boards with pin vias on both sides make it easier to add the RST & CE connections. The orange wires shown here thread through the housing to a slide switch which disables the backlight connection for surface deployments. This example connects power to the backlight, but with other screens you might have to connect BACKLIGHT to GND.

Enabling the screen now looks like this in setup:

pinMode(n5110PowerPin, OUTPUT);
digitalWrite(n5110PowerPin, HIGH);
pinMode(n5110modeSelect, OUTPUT);
pinMode(n5110SData, OUTPUT);
pinMode(n5110SCLK, OUTPUT); 
LcdInit(); // shiftout takes control of Mode, Data & SCLK lines at this point

To turn off the screen you pull all the control lines low:

digitalWrite(n5110PowerPin, LOW);        
digitalWrite(n5110modeSelect, LOW);                
digitalWrite(n5110SData, LOW);                
digitalWrite(n5110SCLK, LOW);                         

All four control lines must be brought low when you de-power the display or you will get a 13mA leak current through the controller after vcc goes low. Only the power pin needs to be driven high to start the screen later in the main loop, but don’t forget to run the init each time you power up.

My tests so far have shown reliable operation of pin-powered 5110’s through more than 8000 ‘long-sleep’ power cycles. In applications where I want to display data on the screen on for long periods of time,  I still depower the screen during the new sensor readings. This lets me know when the logger is capturing data and forces a periodic re-synch with the bus. I don’t know how long these displays would run continuously without that step, but I’m sure the coms would eventually go AWOL without some kind of regular reset.

Potting the Nokia 5110 display

Contraction of the epoxy created pressure burns on the LCD when I did a single large pour to pot the screen.

No screen is much use on our project unless it can withstand some bumping around in the real world, and ideally we want one that is dive-able. For several years my go-to solution has been to pot surface mounted LED’s and sensors in Loctite E30CL. I like this epoxy because the slow cure usually sets clear because bubbles have time to rise to the surface without a vacuum treatment. My first attempts looked great the night of the pour, but I got a nasty surprise the following morning. You see I usually mount sensors in small ½-1 inch wells, but the 5110 required a ring more than 2” in diameter. The contraction of the epoxy in this 10mm deep well caused pressure marks on the edges of the screen, and a significant brown spot in the center of the display where the text became inverted.

Successive small pours worked better. Here the back-light reflects off of the edges of the epoxy that seeped under the screen before it finished setting. The display in this photo has a 3k3 series resistor in the backlight circuit.

The next attempt was much more successful, as I built up the epoxy a few mm at a time like the layers of an onion. As each layer hardened, it protected the screen from the contraction of the subsequent layers above.  The trick was to bring the first pour to the base of the pcb, and the second pour to “just barely” cover the surface of the screen. The epoxy penetrates about 1/3 of the way into the display housing but this does not interfere with readability as those edges are invisible under natural lighting conditions. That epoxy is actually under the LCD, in the air gap between the transparent glass LCD sandwich and the white reflector plastic which holds the thin LCD in place between the metal rim and the PCB.  I’ll try future pours at different angles to see if that lets the space under the LCD fill completely. Looking at the epoxy penetration, it’s clear that the black edges in pour #1 were places where the LCD was compressed on both sides, and the brown discoloration was from pressure on top with no support below. 

Seawater caused severe fogging of the potting epoxy after only three days in service. Originally a concession to my aging eyes, the large fonts really saved our bacon when this reaction occurred.

The results for the second batch looked good and the screens worked beautifully with full marine submersion for about two days. Then some kind of chemical reaction with the sea-water started fogging the epoxy, and by day three I was glad I’d created the large number fonts because the 5×7’s were completely unreadable.   Once we were back home, a bit of elbow grease & 800 grit removed the foggy surface rind, and a layer of conformal coating restored clarity. I think my next builds will add the coating to the epoxy surface at the start.

I also noted some screen discoloration from pressure at about 3m depth, indicating that even a thick layer of epoxy bows too much for a deeper deployment. I’ve ordered some 1/4“ plexiglass disks to provide a surface with a bit more chemical resistance, and will post an update on how that works after the next fieldwork trip. I’m hoping that provides a bit more pressure protection too, but the shore hardness of the epoxy is 85, and PMMA (plexiglass) is only a few steps above that at 90. I might try polycarbonate as well.

Other Fun stuff:

There is so much more to explore with this screen, including live graphing libraries, and display controls so I expect it will keep me amused for a while since I can add it to any of the current logger builds. Several are out in the wild now for long term tests, and I’m currently working on a script to move those fonts (and a few other things) into the 328p’s internal eeprom. If all goes well I’ll release that ultra low memory footprint version of the code shortly. 

Cheers for now.

Addendum 2018-08-24

After several builds using the this LCD screen I finally got around to storing those font arrays in the Arduino’s internal EEprom. Works a treat, and frees a good chunk of PROGMEM space with very little change to the core functions. With fonts in EEprom, the remaining Nokia 5110 functions compile to a little over 400 bytes of program storage and 10 bytes of dynamic. (not counting EEprom.h) And that’s with three copies of the output functions because of the simple 2-pass method I’m using to display the large numbers.  A small price to pay for live data output on our loggers!

Addendum 2018-10-17

Because of that pressure problem with the 5110 I decided to try out the 0.96″ OLED screens which sell for about $3 on eBay.  When the first batch arrived I was pleasantly surprised by how well they stood up to pressure on their surface. Then I found the SPI version of the SSD1306 OLED can be driven by essentially the same code as the PCD8544 (with the exception of the init & XY functions which are specific to each controller).

Adding the SSD1306 OLED Screen to an Arduino Logger (without a library)

I’m connecting the OLED with the same analog line connections used for the Nokia, but I’ve added a delayed-high RC bridge because the OLED is pickier about the reset input than the Nokias. In hindsight a similar method is probably a good idea for the Nokia screens as well, though you might need to experiment a bit with the resistor/cap values to get the timing right.

Measuring Temperature by Comparing the Arduino System Clock to an RTC

I was pretty pleased about coming up with a new dithering method that lets you over-sample thermistors to better than 0.002°C with an Arduino.  I was bragging about this to a programmer friend recently, and suggested that achieving this with nothing more than a resistor on a pin might annoy engineers who’ve used more complicated circuits for essentially the same job.  His response to this surprised me:

“Actually, the ones you’re really going to piss off are the coders. It seems to me that your pin-toggle technique only works because the rail stabilization on those chips is bad. In my business, that’s known as ‘Coding to a Fault’.  You see, I spend my days trying to keep large systems on their feet, and these are a patchwork of woolly legacy code and new functions tied together by utilities passing data back and forth. Errors creep in, and that’s expected, because those translators necessarily have to change the format of the data. Often the coder who did the tweening knows about these issues, and documents them, but their manager won’t authorize time for a proper fix once the function is stable because it’s judged to be a harmless, non-lethal error, and the budget’s too tight.  Ten years later, it lands on my plate because some diligent person finally decided to take that issue off the bug-list, usually because it was getting on their nerves that the person before them had done such shoddy work. Of course by then the error’s been present in the system so long that other working groups have unwittingly written code that relied on the artifact.  So fixing the original problem causes a heap of trouble five steps down the line.  Those situations are the bane of my life…”

This 8 MHz 3.3V clone works well with the two-clock method. I think of these as simply a cheap breakout board for the 328P.

He had more to say on the matter, but I missed the rest because I was backing away from his increasingly animated gesticulations, which were punctuated by some weird facial ticks.  I paused for a moment at the front door, thinking I should at least thank him for the coffee, when “…in fact, I should probably take you out of the technological gene pool right now, before you spread this madness…” convinced me otherwise.  I finally understood why the engineers were so critical about this project, since the way I build our loggers ignores several of rules that they’ve dedicated their career to.  If I had any professional decency, I’d seek absolution by dumping all that eBay crap in the bin, and abstain from any future component purchases that lead me away from the righteous ±1% path.

A divine revelation from Rantwijk’s site.

But I have to confess – the devil is still finding work for these idle hands.  Especially after reading Joris van Rantwijk’s analysis of Arduino clock frequency, when I realized the resonators on cheap Pro Mini clones probably had so much thermal variation, that you could base a temperature sensing method on that alone. The key insight here is that the $1 DS3231SN boards I’m getting from eBay are the genuine article with ±2ppm stability. By using both of those components in the same device, I had a high accuracy angel on one shoulder and a high resolution daemon on the other.

DS3231’s can be set to output a 1Hz pulse on SQW simply by zeroing the  control register:

Wire.beginTransmission(104); //DS3231 RTC address
Wire.write(0x0e);            //control register
Wire.write(0);               //zeroing all bits outputs 1 Hz on SQW
Wire.endTransmission(); 

To build the temperature sensor, all I had to do was compare that thermally stable 1-Hz pulse to the corresponding number of system clock ticks from the rubbish oscillator on the Pro Mini clone. A dive into the programming forum at Arduino.cc led me once again to Nick Gammon’s site, where his page on Timers and Counters  provided several ways to measure the frequency of pulsed inputs.  This isn’t the first time I’ve spent a few days learning from Nick’s examples, and I own him a huge debt of gratitude for his insightful work.

I was already familiar with the hardware interrupts on D2 & D3, but the 328P’s input capture unit on D8 does the job with a special circuit that saves the timer values in another register. You then read back that frozen value, and it doesn’t matter how long after the interrupt executes, or what you do in that interrupt, the captured time is still the same. This lets you measure duration to a temporal resolution approaching two ticks of your system clock. (see reply #12 on Nick’s page)

Will the regulators temp-coefficient affect the oscillator?

Oscillators are sensitive to input voltage as well as temperature, but Rantwijk also looked into that, determining that the clock frequency on his 16 MHz Pro Mini varied by about +2.5 Hz / mV input.  The MIC5205 LDO on the Mini & most of the 3.3V clones quotes an output Temperature Coefficient [∆VO/∆T] of 40 ppm/°C. If I restrict my sensing range from 0-40°C, then my regulator’s voltage output would be expected to vary by about  0.00004*(3.3 output Voltage/°C) = 5.28 mV over that 40° range.  Multiplying Rantwijk’s observed 2.5 Hz/mV *5.28 mV suggests that thermal effects on the regulator would cause less than 14 Hz of variation. Given that he was seeing a variation of several thousand Hz in the ceramic oscillator over a similar temp. range, regulator based thermal errors can be considered negligible.

What about freq. variation due to your decreasing battery voltage?

I had to go digging to figure out what kind of effect a decreasing battery voltage would have. The 5205’s data sheet lists a line regulation [ ∆VO/VO ] of 0.05%.  Since my rail is at 3.3v, that suggests a rail variation of about 165 mV over inputs between 3.65-12V.  With Rantwijk’s 2.5 Hz / mV benchmark, that would cause about 400 Hz of frequency variation over the entire input range the 5205 will support. That’s about 10% of the expected clock frequency delta. I should see less than 1/3 of that error since the batteries I’m using will only swing from 3.65-6v,  but three percent is significant so I’m going to need some way to compensate for main battery discharge.  My freezer testing also sees a 0.5V drop on alkaline supply batteries when they get cold, but provided I use the same chemistry during my calibration & deployment runs, voltage “droop” from ambient temperature should be included in the calibration.

Will it Blend?

This graph was created by counting the number of system clock tick during a 1Hz pulse from a DS3231 RTC. The count was captured with Nick Gammon’s Input Capture Method (see reply #12) on pin D8. The red line is the temperature in °C from an si7051 reference [±0.13 °C] (left axis, Celcius), and the orange line is the corresponding change in the count (right axis, freq.(-798000)).

This test used a Pro Mini clone, and the clock count varied by 4056 ticks over 44.54°C. That’s similar to Rantwijk’s result, and provides an average resolution of 0.011°C.  I was expecting a nasty response curve, with the least amount of change near 20°C since most components are optimized for room temperature operation. But the fit was surprisingly linear:

The key to getting a clean run is to change the temperature as slowly as possible so your reference sensor doesn’t get out of sync with the oscillator on the main board. To achieve this I built a dry calibration box out of two heavy ceramic pots, with about 3kg of rice between the two pots.  Each pot then has its own lid. I drove this box through a 40° range by putting it in the refrigerator, and then setting it on top of the house radiators. I excluded the “rapidly changing” portions of the data from the final calibration set. I also noticed that some boards seem to have a 6 hour “settling time” before the startup hysteresis goes away and temp/frequency relationship stabilized. Even then you still see some non-linearity creeping into the Temp. vs. Freq. graph above 40°C, which forces you to a 3rd-order polynomial to include those higher temperatures.

Dealing with oscillator frequency drift

Decreasing rail voltage isn’t the only thing that could give me grief because virtually all oscillators suffer from age related problems.  According to Frequency Stability and Accuracy in the Real World:

“Drift often proceeds in one direction and may be predictable based on past performance, at least for a few days. In some oscillators drift may be more random and can change direction. Long-term drift will affect the accuracy of the oscillator’s frequency unless it is corrected for.”

This is a real issue for our loggers which are now being deployed beyond the two-year mark.  And since we are under water, or in a cave, I can’t discipline to some NTP server, or GPS signal.  Whatever method I use has to rely on the existing parts.  By deduction, the temperature sensor inside the DS3231SN must have a reasonable amount of long term stability, since that record is the basis for the corrections that let Maxim claim ±2ppm.  And though the temp. record from the DS3231 has only quarter-degree resolution and an datasheet spec of only ±3°C, I’ve been surprised many times by how well it compares to sensors with respectable accuracy:

Most of the time you will see a small offset between the RTC and the reference sensor, and you can correct that to three nines with a linear from the calibration dataset.  (a typical example: y = 1.0022x + 0.0646, R² = 0.9996) Another thing I’ve noticed is that the RTC’s temp. register starts to diverge from my reference sensors above 50°C. So the DS3231 should probably only be used to discipline temp. accuracy across the same  0°C to 40°C range specified for the ±2ppm rating.

After the initial calibrations are done, you can correct drift in the frequency-delta temperatures by comparing them to the RTC’s temperature register. The only fly in the ointment is that the RTC record is so crude that direct adjustments based on it have the potential to put ugly stair-step transitions all over the place.

Drift correction with an Leaky integrator

Drift correction is necessarily a long game, so I’m not really worried about individual readings; just the overall trend. Tracking this requires more readings than you would use in a typical moving-average.  In addition, the 328 doesn’t have much computational horsepower, and it’s easy for numbers extending past the third decimal place to over-run the memory.  One solution to those problems is the leaky integrator:

//I pre-load filter variables in setup for 25°C, but that is not necessary
uint32_t rtcfiltSum = 800000;    // the previous reading "memory" variable (32*25000)
uint32_t rtcFiltered= 25000;     // equivalent to a temp of 25C
int filterShift = 5;             // equivalent of dividing new readings by 32
float tempFloat; uint16_t newValue;

//bit shifting only works with positive integer values (so no negative temps!)
//so you have to convert the decimal-float temperature readings
tempFloat=TEMP_degC*1000;  //preserves three decimal places from the RTC temp. reading
newValue=(uint32_t)tempFloat;
// this is the filter itself - save rtcFiltered in the log file for drift correction
rtcfiltSum += (newValue - (rtcfiltSum >> filterShift)); 
rtcFiltered =(rtcfiltSum >> filterShift);

That is an hefty amount of filtering, so the value in rtcFiltered will lag behind the current temp reading by several hours. However using a shift of 5 means that each new data from the RTC’s temp register only adds 1/32 of that to the final filtered value.  Even if the RTC takes one of it’s gigantic 0.25°C steps, the filtered value changes by only 0.25/32 =  0.0078°C. This transmogrifies the crunchy RTC record into one with a resolution comparable the data we are deriving from the frequency delta.  Then the de-trending can be done without harming the small details in the high resolution record. I could probably change that to shift=4 for faster response as only 1/2 of the resulting 0.0156 steps would typically show up in the record on average.

So the method is basically:

1) Create an IIR low-pass version of RTC’s temperature register.

2) Use the same leaky integrator on the frequency based temperature, which is calculated from the calibration data’s fit equation.

3) Compare those two heavily filtered numbers to create a rolling adjustment factor that you apply to the frequency based temperature data. Because you are only trying to compare long term behavior, you want these to be ridiculously heavy filters (ie shift 5 or 6) which you would never use in normal sensor filtering applications.

A typical 15 minute sampling interval only generates 96 readings per day, so this leaky integrator approach would take 8 hours to adapt to large changes in the offset. So it won’t do a thing to help you with short term hysteresis in environments that see large daily temperature fluctuations.  However, it would gracefully handle the line regulation problem, and it will respond to aging offsets that change direction half way through a long deployment.  Many sensors suffer from drift issues like this, and its easy to see how this correction method could be applied to those situations if you could define a temperature relationship.

Of course this begs the question of why Maxim didn’t make that temperature record available at a higher resolution in the first place; especially when you see all those unused bits in the register:

I suspect the design engineers had higher resolution output in the original plans, but it was pulled when some bean counter pointed out that doing so would cannibalize existing sensor sales – especially the highly profitable DS18b20s. If that is the case, it certainly wouldn’t be the first time a company disabled capabilities in a design to protect other product lines.

When things go squirrelly

I’ve been talking about the resonator/clock as though it was an isolated system, but this method is really a test of all the components on the board, and sometimes those combinations  produce some pretty weird behavior.  For example: The Rocket Scream Mini Ultra has long been one of my favorite Arduino compatible boards, and I’ve use it in many different logger builds because of it’s efficient MCP1700 regulator. But it doesn’t seem to work with this two-clock method because of a spectacular discontinuity at around 23°C:

Any response curve that produces non-unique solutions like that will make it impossible to do a simple regression curve-fit. The 800ST ceramic resonator on the Mini Ultra I used for this test looks quite different from the metal-can style one on the cheaper clone board, and it’s larger size has me wondering if there was some kind of compensation circuitry that was suffering from really bad hysteresis. Of course, there is always the chance I made calculation error somewhere…but if so I still haven’t found it, and the same code was running on both boards. The fact that the temp-frequency graph showed an inverse relationship also has me scratching my head.

Where to go from here…

Every board/RTC combination will have to be calibrated, which is a bit of a pain if you’re not doing week long burn tests like we do.  But the thing that really amuses me about this approach is that the potential resolution is inversely proportional to the quality of the components you are using. Rantwijk found a temp-co of less than +0.97 Hz / °C on the Duemilanove so the method has access to 100x more resolution on a Pro Mini. If you’ve got a Genuino with a quartz  oscillator, it’s probably not worth your time to even try.

One problem with driving the dry-box down to sub-zero temps is that the freezer’s compressor cycle will muck up the data if you don’t have enough thermal mass. If you live in a suitable climate, outdoor temps give you better results, with the added benefit that your spouse won’t gripe that they can’t find the chicken to make dinner behind “all that crap” you’ve stuffed into the ACSF.  (Arctic Conditions Simulation Facility)

Unless . . . uhhhh . . . doesn’t the 328P’s internal clock use an RC circuit with even more variation than the external ceramic resonators?  If memory serves,  Atmel suggests calibration to wrangle that puppy down from the ±10% factory defaults to ±1% over the -40 to 85 °C operating range. (see AVR4013: picoPower Basics)  For an 8 MHz system, that works out to a delta of more than 600 ticks per degree.  If you used Nick’s code to count with the 328’s internal oscillator, you could reach ±0.001°C with this two-clock method.  That’s approaching what you’d get from an RTD, and all you need is a $1 DS3231SN module from eBay.  Since you’d be dealing with parts inside the 328, you likely won’t have the kind of board to board variation I ran into with the Mini Ultra.

To read ambient temps, you would have to take the count right after waking from about 10 minutes of sleep, so the chip was not reacting to it’s own internal heating.  And I suspect reconciling the accuracy of those readings could involve more calibration-penance than any self-respecting maker should ever have to pay.  But it is just sitting therewaiting to be done by someone willing to set some fusesand that voice whispering in your ear right now is just good honest intellectual curiosity. No sin in that. Right?

After these shenanigans, I propose we update that old saying:
“A man with one watch knows what time it is.  A man with two watches is never sure.”
with the postscript: “But at least he can measure the temperature to ±0.01°C, provided one of those clocks is a 99¢ piece of junk from eBay.” 🙂

 

Addendum: 2018-03-19:
Just found an interesting document from the fluke archive describing the drift on an RTD sensor described as 90-day accuracy: 8520A/PRT precision temperature system (see graph on page 1)  Whats interesting is that those curves seem to have a period of accelerated drift, and then flatten out again.

Exposure to high temperatures affects all resistors (which RTDs & thermistors are). Prolonged exposure to temperatures over ~100°C  will cause a higher drift rate compared to lower temperatures.  Our loggers are usually out on deployment for at least a year… I’d be kidding myself to think I could constrain drift to anything near this RTD’s performance with the RTC oscillator.

Addendum: 2019-02-07:
Just found another interesting “no parts” method to measure ambient temperature with an Arduino over at AvrFreaks:

“An alternative low pin/parts count method could be to use the temperature dependence of the output impedance at the AREF pin. If you have the typical external capacitor there, the time it takes get the reference stable when switching from high (VCC) to low Ref (internal 2,5 V) should depend on temperature.”

I run into Aref cap settle times frequently – often on the order of 10ms. Timing that would be a simple matter of reading the rail against the bandgap untill you get the same number after changing from high to low.  Easy Peasy!

The 2017 Cave Pearl Project ‘Year in Review’

Run times for Cave Pearl loggers without RTC pin power (0.25 mA) and with RTC pin powering (0.1mA). Dashed lines are projections to the point where the unit would have performed an automatic low-voltage shut down.

It’s been an intense year for the Cave Pearl Project, with several major advances. Almost all of the the units in the field sleep at 0.1mA or less with the RTC pin-power modification, so we can finally push the deployment cycle out to a two year rotation. Somehow I doubt that Trish will be able to wait that long for her data, but at least now we have the option of just leaving things in place if we need to when the fieldwork doesn’t go according to plan.

I also started experimenting with SD card shut-down this year, and early records from those prototypes are in, suggesting that they will run for at least four years. However I’m not going to call this technique ready for prime time until we see at least twenty units deliver more than a year of saved data.  Accelerated bench tests can only tell you so much about how a unit performs in the real world.

Extended lifespans mean that we can leave loggers with other people so they can do exploratory deployments in locations we can’t get to. Natalie Gibb from Under the Jungle sent us a brilliant video from one of those deployments:

We couldn’t have produced anything that polished with our hokey little point & shoot cameras!

I didn’t have much time to update the site in 2017, but even with only six new tutorials the traffic continues to grow, and we are approaching 100,000 unique IP’s. I still consider this whole endeavor as an experiment, since we had no idea how much traffic a nerdy rant about DIY data loggers would get when we fired it up in 2014. I think we’ve passed some kind of threshold this year, because traffic analyzers are now hitting the site regularly, and the comments are being spammed with a heap of “monetize your blog” garbage. Are there really people out there willing to annoy that many people for a $2.50 average CPM? (Ok…rhetorical question…)

I mentioned in the 2016 review that European countries were occasionally passing the US in the daily stats. At the time I thought that this was just an artifact of some mention in a forum thread, but through 2017 it started happening more frequently and now the US traffic is really starting to fall off. This struck me as odd, given all chin wagging you hear about STEM education initiatives in the burbs.

So I did a some checking with Google Trends and it’s not my imagination; something happened in 2017 that reduced the number of searches for Arduino in the U.S. while those same searches are rising in the rest of the world. Sadly, I don’t think you have to look very far to understand what’s happening when the president states that dismantling “the DEP” is one of his goals, and then appoints a director that sued the agency several times to carry out that plan. The relationship between the executive branch and the research community is so deeply dysfunctional right now that the Center for Disease Control has been ordered not to use terms like “evidence-based” or “science-based” in official documents.  Is it possible that folks on the street are getting the message that science has somehow become un-American?

I’ve no doubt more will be written about this epic estrangement, and in keeping with the freaky zeitgeist we’re introducing the Cave Pearl Projects first annual “Ugliest Deployment of the Year” contest.  A worst-in-show collection of from coastal outflows, mangrove swamps and hydrogen sulfide pits:

Sponges growing on a flow logger after 27 month deployment in a hydrogen sulfide cave. This unit smelled so bad that it attracted all the feral cats from the neighborhood when we brought it home for cleaning.

Bio fouling on an estuary unit after only 6 months. It was deployed as a floater, and I was quite surprised that it was still buoyant enough to function. A swarm of stinging sea lice made this retrieval particularly memorable.

Pressure unit after 6 month stint in a cave feeding a coastal lagoon. While this units’s not that ugly per se, that outflow fed directly into a swimming area that sees hundreds of tourists per day expecting the joys of “crystal clear spring water”… Nuf said?

Honorable Mention: This was actually reef logger from 2015, but I’ve included it here because this was the deployment that really defined the “fugly enough to be cute” benchmark that future deployments will have to measure up to.

To qualify, these dogs had to run through the entire deployment because without primary data to support your hypothesis – you’ve got nothing. (no matter what they look like on the outside…)  You can’t just wave your hand and create alternative data because in research that’s called lying.  Somehow, this not-so-subtle distinction has become blurred in the media, where science itself now seems to be under attack.  It’s remarkable that someone with a “natural instinct for science“, and an obvious facility with numbers could fail to appreciate how valuable the insights from research can be.

I’m genuinely concerned that if the the U.S. continues to turn inward, choosing a path towards declining health and social outcomes, it will become less appealing to the kind of entrepreneurs that built the country in the first place. The winners-take-all legislation rolling out of Washington these days threatens to eliminate the things that make risk-taking innovation possible.  An important nugget that policy wonks always seem to forget was eloquently summarized in Jennifer Romolini’s Career Advice article:

“You’ll Suck at Everything the First Time You Do It.
You will probably suck the second and third time too.
Don’t get defensive about this; don’t decide that you should never do the thing again…”

This was my first attempt to build a data logger, and yeah, it was pretty crude. I was lucky to get 24 hours on 6xAA batteries and it was held together with hot glue. My current builds are probably going to pass four years at 100-200 ft depth.   If I gave up when it still looked like this piece of junk on my kitchen table, I’d have no idea that was even possible.  Even today I get criticism from engineers who say the project is pointless because it’s not ‘state of the art’. But they don’t know where we started, so they also have no idea how far it will go. The same holds true for your project, whatever that might be.

But without a functioning a social support system, only people with rich parents ever get a second chance. It’s no surprise that bankers could care less about this, since they don’t have to produce anything new to make their money. But these days it seems that silicon valley is also willing to focus on corporate profits rather than innovation, even if that means looking the other way while legislators dismantle systems those propeller-heads needed when they were just starting out.  If people thought WannaCry was bad in 2017, just wait till they see what AT&T and Comcast does with the net neutrality rollback. (And they called the bill the “Internet Freedom Act”…nope…that’s not Orwellian at all… )

America will not succeed in the 21st century simply by making stuff cheaper with learning systems that remove human beings from the process.  If that does happen, who’s going to have enough money to buy the consumer goods that keep the economy rolling? But they could reclaim that edge by re-imagining how technologies interact with people and the environment. Of course, no one from old money will support policies that might upset the profitable status quo, so the last thing they want is an educated population changing things with a bunch of new ideas.

Unfortunately, the ‘new’ money created by the internet revolution is now acting like the old.  With few exceptions, the major tech players are willfully dropping the ball, spinning up proprietary bank crypto-currencies when they could be using tools like blockchain to build efficient resource allocation systems for new energy sectors that use considerably less water and create far more jobs. It’s time for the de facto stewards of the internet to accept responsibility for their creations, which are becoming the real arbiters of trust, fairness and justice in our society.  A good start along that path would be to make the voting system more secure from external threats, and from internal ones.

If the tech sector consolidates into a corporate platform oligopoly, scientists / inventors get lured away by countries 1/10th the size, congress bends the knee to carbon energy’s hired guns and big PhRMA’s lobbyists, then the US will essentially be handing the future to China.  But it does not have to be this way.  America seems primed for a democratic political awakening, and I hope that process encourages people to think about the role science, innovation and invention originally played in ‘Making America Great’, and then vote for leaders who help those things to flourish in the future: