Arduino datalogger shield using the VDIP1 USB module
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
Current Status: Complete
Date: 15th August 2015
License: Creative Commons Attribution 3.0 Unported License
This project was the authors first Arduino project. It utilizes a FTDI VDIP1 module to provide an interface to a USB memory stick and a custom shield that incorporates analogue input circuitry, a real time clock and a thermometer. The design can measure voltages from 0V to 22V or by using the author's low cost current monitor, measure a current in the range of 0-5A or 0-30A.
A Maxim DS1338 is used to provide a real time clock and a CR2032 lithium cell provides battery backup.
The design provides some protection on the analogue inputs against an un-powered module connected to active supplies. The first application has been to use the circuit on a solar power monitor, which monitors solar panel outputs (upto 21V) and the terminal voltage of a deep-cyle lead acid battery. Using a neat trick of the Atmega 328, this design calibrates its ADC using the internal VREF, thus reducing the scaling and conversion errors.
The trickiest part of the design was getting the VDIP1 module to work reliably. The author experienced a few issues and there was a lot of contradictory information on the internet. The issues and eventual fixes are discussed later on. The results are saved as daily CSV (text) files on the USB memory stick.
Schematic and PCB layout of the custom shield are provided, along with an example program. A simple sketch to program the real time clock module is also provided on github, https://github.com/istedman/ArduinodataloggerUSB
Double click the image below to expand it
Hardware implementation notes
A CR2032 coin cell is used to provide backup power to the real time clock when the unit is not connected to its main battery power supply. To save power, as my
module is battery powered, I made a few modifications. The Arduino itself is an Androino_2009, single sided Dnuemilanove clone. I removed the USB device and the linear regulator to save power. As I run the system from a 12V SLA battery, I fitted a ready made LM2577 buck converter module from Ebay to create the +5V supply from the battery input. Power consumption in idle is now 10-15mA, previously with the linear regulator, it was 25-30mA. The current increases to ~100mA with the
The VDIP1 is switched, off to save power, transistors T1 (N-channel) and T2 (P-channel) MOSFETs switch the +5V supply to the VDIP. The PROG and RESET pins of the VDIP1 are pulled up to configure UART mode.
The analogue input range is configurable. It can be a 0-5V range or by fitting R10-R13, as required, a potential divider can be created to accept a wider range. I use this to sample the up to 22V input from a solar cell. BAV199 dual diode packs provide over and under voltage protection.
Finishing the hardware design, an LM73 temperature sensor is provided, interfaced via the I2C bus.
Software implementation notes
The current software version is 0.2, available here, https://github.com/istedman/ArduinodataloggerUSB.
The datalogger.h file in the archive allows you to customize some settings and set the debug level from verbose to minimal. Scaling factors for the ADC ranges are defined here as well as the 0.01V/A DC offset of the current monitor.
The analogue inputs are passed through a simple moving average filter to remove noise. The ADC range is calibrated on startup using the inbuilt VREF of the device, using the really clever trick detailed here, https://www.instructables.com/id/Secret-Arduino-Voltmeter/I should re-calibrate every day to account for temperature, have not done this yet.
To save RAM, string constants are stored in PROGMEM, this includes the text printed to the serial port on power up which details the time and date of the build and the sample interval.
You can set the sampling time, via the SampleInterval variable in the main program. You have to enter it as the number of miliseconds as the compiler would not evaluate a time in seconds to milliseconds at build time, one of many confusing quirks in development. A simple time_of_day() function, with a crude almanac is used to
ensure that the device only samples data in daylight hours. The datalogger.h file has the simple sunrise/sunset times within it for easy editing. My implementation uses the times for London, England.
The VDIP module is interfaced using a software serial port on pins 4 & 5 at 9600 BPS. This was the trickiest part of the software to get working reliably. One of the peculiarities of the VDIP1 is that when you open a file, you have to specify how many bytes you are going to write and you must write exactly that number! If you write too few bytes, the write operation will not complete and the VDIP1 will wait forever. Too many and it gets truncated. Some 'fun' came from the fact that a sample line of data looks like this:
There can be variation in the length of that record. The length of the date can change, 25/12/15 requires another byte and the length of the timestamp can be shorter.
In the software I define a variable, INLENGTH which is 30 bytes, this allows for the maximum variation + spare. As I write the various results, I count the number of bytes written, if at the end it is less than INLENGTH, I write <space> to the file until I've met the allocated number of bytes. Once finished I write a carriage return and linefeed to the end of the file. This is done using the commands, mySerial.write(13) and mySerial.write(10) for the carriage return and line feed respectively. The writeDataToStick() function handles this
I use the ASCII command mode with the VDIP1, it is vitally important at the end of every command, to send a carriage return. I found that a mySerial.write("\r") did not work so I send the decimal code for a carriage return (13), i.e. mySerial.write(13);
I hope these observations help other using the VDIP1, when I was searching for help on this I had a lot of contradictory information.
To save power, the VDIP1 is powered down when not needed, this reduced the +5V current from ~100mA to ~15mA. Once the VDIP is awakened, you need to wait 5 seconds before re-sending the initialization commands, see the PwrUpVDIP() function.
Assembled unit photos
A view showing the terminal connectors
A view inside the case, showing the shield and VDIP1
An inside view showing the 12V to 5V buck converter module mounted inside the case.
Closeup of the board, the power LED was too bright, hence the white tack over it
Updated 14 April 2021