Showing posts with label Yard Light Logger. Show all posts
Showing posts with label Yard Light Logger. Show all posts

Wednesday, October 28, 2015

Daylight Logger for Gardening Part 3

Now that we've covered the function and design of the logger device, let's look at a few of the obstacles.

Unexpected Data:
One of the functions that needed to be coded and tested early on was dumping the light data to a PC.  I used a C# program that I wrote for doing two way serial communication and added features to have to send and show data in either ASCII or hex.

So the issue I ran into was that data seemed to be getting distorted, specifically for sunny conditions.  I wasn't seeing any values greater than 0x7F, which is the maximum ASCII value (7 bits).  However this wasn't immediately noticeable as most of the values I was receiving were 0x3F.  It almost looked like maybe there was a memory issue and that was a default value of some sort.  My other thought was that maybe there was a baud rate issue and I kept losing that first bit somehow.  I was pulling at straws.  I spent a whole bunch of time looking at scope captures of the data and measuring pulses manually to compute the baud error to no avail.  Then I took note of how the ASCII value of 0x3F is a '?'.  Maybe there was something to that.

So I started poking around in my C# code for a reason that portions of my data was being converted to '?'s.  I was using hte built-in SerialPort object that is part of .NET and upon received data used the "ReadChar()" method because it returned printable characters.  I had added the ability to print hex as an afterthought, and as such, simply formatted the returned value as a hex byte when printing to the window.  Seeing as the "ReadChar" method actually returns an integer value, I assumed I was getting the raw data.

Turns out I was wrong.  The SerialPort object allows for the setting of a text encoder, which I believe by default is ASCII.  And ASCII does not support values over 0x7F.  A little code rewrite using the "ReadByte()" and all was good.  My firmware or circuit were fine from the start.  Admittedly, the PC side of things is usually much easier to develop and debug, which gave me a false sense of security.  I assumed my debug tool worked because it didn't fail catastrophically (as embedded software often can).  But it usually helps to know what goes on under the hood, otherwise some issues are seemingly impossible.

Small Optomizations:
Seeing as the logger was going to run off of batteries, I took some care to reduce power draw.  I only had so many I/O pins which meant I had to be mindful of idle states when combining functions.  So for instance, I used a PNP for both the TX and the power to the ambient light sensor and buffer amp in order that they both share the same off state.  I only turn the sensor and amp on for a very short period of time, which does turn on the TX transistor (Q4), but the TX resistor is sized to reduce current draw.  It's a compromise, but at least they are both off for the vast majority of the time.  The op amp was even chosen amongst the ones I had (and ones I would have preferred to use up) because of its lower supply current.  Fortunately the memory chip only draws a 1uA while idle, leaving it power on all the time is inconsequential.  And the RX transistor is stuck off unless something unless a com port is attached.

But hardware isn't the only place to save on power.  Efficient code and good use of microcontroller features helps a lot.  The most obvious features is the SLEEP function.  In a 24 hour logging period, the device is inactive 99.9945% of the time.  By putting the MCU in a lower power state, the circuit hardly draws any power (my secondary multimeter of suspect accuracy claims around 60uA, which actually seems a little high).  This amounts to about 1.5mA hours spent idling over 24 hours.  Not too bad.

But some code efficiency can also help.  Ideally, you don't want to be waiting for anything if it can be helped.  In my case, it took a certain amount of time for the sensor output and internal voltage reference to settle when the MCU woke up and turned everything on.
Green line shows the sensor being turned on and off once sampled.  Yellow line is the data signal going to the memory (clock signal would have been better, but you get the idea of  the time it takes).  MCU turns on at the start of green signal and off and the end of the yellow signal.
I didn't like the extra waiting and realized I could save a bit of on time by writing the next address to the memory while things settled.  This knocked the system on time from about 10ms to 7ms.  It may not seem like much, but that's a 30% reduction in total awake time for the microcontroller over the whole 24 hour cycle.

Should have captured the same signals as before.... Green line is the clock signal to the memory, and Yellow line is the light sensor output.  The important thing is that the signals overlap instead of happening in sequence.
Another savings in power is running the MCU at a lower frequency.  Nothing going on here is that time critical, and even at my 500KHz clock, the micro is still fast compared to the analog sensor setup time.  But if running slower also means running longer, it may not net you a total power savings, keep that in mind.

Improvements:
There are of course other improvements to be made on this device though I'm not unhappy with its current state.  Larger resistors can be used for both the I2C pull-ups and for the TX and RX bits of the circuit as the data rates for both are rather slow.  Mechanically I can shade the light sensor so that the sense resistor can be made larger reducing its current draw.  It'd also be nice to slap in a bluetooth module making connection to a computer easier.  Maybe some day....

Tuesday, September 29, 2015

Daylight Logger for Gardening Part 2

Previously we established (loosely) the need for a sunlight logging device.  We came up with a basic design plan and the requirements of each necessary element.  And here is what I built:

It's a bit more complicated than I may have led you to believe, but not all that much so.  Let's take a look at the blocks.

Memory:
The memory is nearly as expected straight off the data sheet.  I have the address and write protect lines wired low to make life simpler.  R7 & R8 provide the expected pull up resistors for the I2C protocol but there is an LED in parallel with the SCL signal.  D2 is basically my status LED and the only means by which I can communicate with a user.  The SCL signal is used because the memory chip will not respond to "spurious" changes on that line.  An I2C start condition requires the SDA line to go low while the SCL line stays high.  So as long as the SDA signal stays high, the memory chip will ignore changes on the SCL line.

Communication:
Q1 & Q4 are setup so that no current flows while not sending or receiving data.  Since the device will spend most of the time logging, it's prudent not to have any excess idle current draw.  Q1 didn't have to be a FET, but it just made it easier to deal with inputs that could range something like +/-12 volts.  The TX pin of the MCU is combined with another feature of the circuit, so Q4 will turn on during normal operation for small amounts of time, but R3 was sized to reduce power consumption.

Detector:
The first major change to the detector is the addition of Q3.  It takes only small amount of time to measure a light sample, so the circuit really spends most of its time idle.  The amplifier has a quiescent current of  230uA which isn't half bad, but not as good as zero.  The ambient light sensor is much worse, drawing several mA in full sunlight.  So Q3 is only turned on just prior to reading sample, which in turn supplies power to the light sensor and amplifier.  As a side effect, Q3 also turns on, but hey, I only had so many I/O pins to work with.  I also added a pot to adjust the sensitivity of the sensor.  The sensor will try to allow a current proportional to the amount of light (voltage source permitting) so the amount of resistance will directly have an effect on the voltage seen by the ADC.  A lower resistance will provide less sensitivity, and a wider input range, while a higher resistance will max out and clip quite quickly.  R2 is included only so that while programming the PIC12F1572, the amplifier output and data line of the programming tool don't drive each other directly.  You may have noticed that the memory is never powered off; it has a standby current of only 1uA, and more importantly, the signal for Q3 cannot be used to turn it off and on while also being used as the TX line for communications.
Nearly finished design

Microcontroller:
As stated before, the PIC12F1572 doesn't have a ton to do, but it does make this whole thing work, and keeps the batteries alive.  When power is turned on, LED D2 lights up and the device sits in a "ready" state.  At this point it will accept requests from a PC to dump previous logging data, and assists in calibration.  By exposing the light to full sunlight, the potentiometer can be adjusted by a watching the LED.  Steady on means that the ADC is maxed out, and a rhythmic blink indicates that the ADC is reading between max and min values.  So ideally, one would adjust the pot until the LED is steady, then back off slightly until it blinks.  A slow blink indicates the battery is low.

How does the micro know that battery is low?  Well I think the solution is rather ingenious, but I strongly doubt I'm the only person to come up with it.  I already discussed the fixed voltage reference used to ensure consistent ADC results over varying levels of battery.  So why not measure the voltage reference using the battery as the upper ADC voltage.  As the voltage of the batteries drops, the measured value of the fixed reference gets larger.  Consider an 8-bit ADC result (0-255) with the voltage reference set tot 2.048 and the battery supply at a nominal 3V.  We can come up with the equation Vref/Vbat*resolution = result.  By substitution we get 2.048/3*255 = 174.  That means a reading of 174 indicates a full battery.  Our low end is unfortunately only 2.7V (that's the minimum input supply of our op amp, I would/will change op amps for future revisions, but it was one that I had on hand), but we can calculate that value too.  2.048/2.7*255 = 193.  If we reada value larger than 193, we cannot assume that our op amp is properly biased.  And that is all there is to it, just periodically make the measurement and blink the LED if necessary.

Now that covers the "ready" state of the device. but how do we get it to take light readings?  By pushing reset button S1.  Yes, the reset button.  And yes, it does reset the device.  This is another clever trick that I will pat myself on the back for.  The PIC12F1572 has a control register that keeps track of the cause of a reset.  Early in the code, that register is read to determine whether power was just supplied or the button was pushed.  If the button was pushed, the device skips the "ready" state and starts a 16 second timer to allow a user to place the sensor.  Then, for the next 24 hours, the circuit takes sunlight readings at approximately two minute intervals, after which it goes into a permanent sleep state.

Here is a screenshot of the program I made to accompany the project.  It lets you connect to the device via a serial port and download the light data, as well as save or import the data as a CSV file.  You can see that this particular data set is for a rather sunny day with little shade (though I hadn't calibrated it before running this test).  It should also be noticeable that I began logging on the latter part of sunset as the beginning of the graph is mostly nighttime.  Sunrise should be pretty obvious by that dramatic ramp up in recorded light.  I'm actually quite proud of my background that I drew up.

Although it's an embarrassingly ugly construction, I'll show the working prototype anyway.  There was definitely a lot of design after the fact leading to a bit of chaos.  But I temporarily stuck it to the lid of a salsa jar (my "weatherproofing") using a little putty and it works just fine.  We can look into a few of the design hurdles in the next post.

Saturday, September 19, 2015

Daylight Logger for Gardening

While I don't much like to garden personally, a certain someone really wanted to improve my landscaping as well as grow a variety of vegetables and herbs and whatnot.  As we shopped for various plants and seeds I took note of the sunlight requirements listed on each.  Generally it was a qualitative statement such as "Full Sun" or "Partial Shade".....  Well what does that really even mean?   Being the engineery kind of guy that I am I needed something more quantitative.  So a quick internet search while at the store yielded answers as such:

Full Sun = 6 or more hours of direct sunlight daily
Partial Sun/Partial Shade = Between 3 and 6 hours of direct sunlight daily
Full Shade = Less than 2 hours of direct sunlight daily

However, the more reading you do on certain plants you find that while six hours may constitute the minimum requirement if you will, many plants will do better with even more sunlight.  And all of this kind of begs more questions: what about the variations in amount of shade?    Are these aggregate amounts of sun daily? (and from what I've figured out, yes)  Is sunlight at certain times better than others?  But most importantly, what kind of sun do I get in my yard?

I live in a neighborhood with many old and massive oaks.  While the neighborhood is by no means new, when built they did a good job of leaving many of the existing trees.  So areas of the yard that may be next to the sidewalk and nowhere near a tree might get lots of morning shade due to the oaks behind the neighbor across the street.  Then late morning and afternoon sun.  Then late afternoon shade.  Then early evening sun.  Just from observation working outside or mowing the lawn I've noticed that the amount of sun can swing both directions several times throughout the day.  It'd be interesting to find out how much.....  Especially if I want optimize my planting (and yes, normal people don't "optimize" their gardens, nor is the effort likely worth it).

The Project:
Where to start.  Basically, we need to measure the sunlight a bunch of times over an interval, say one complete day.  We then must store those measurements and then be able to recall them for consumption later.  This will also have to run off of batteries and be resilient to weather.  That should pretty much cover it.
Sunlight Detection:
Measuring the sunlight won't be all that much different than the IR detector used in the Virtual Whammy Bar.  Instead of a narrow spectrum detector though, we'll use an ambient light sensor.  This is more or less the same idea as an IR photo sensor except its response resembles our ability to see light.  I believe such devices are used to automatically turn on the head lights in newer cars when it gets dark.
That's the fundamental circuit.  It'll have to evolve going forward, but functionally it will remain the same.  I probably could do away with the buffer on this one,  Our ambient light sensor sources quite a bit of current.

Memory:
The memory chip will be a Microchip 24AA08.  Why?  Because I had a couple.  It's a whopping 1KB, though marketed as 8Kb (B = bytes, b = bits).  At least the 1K actually equals 1,024.  I had larger memory, but it was SRAM instead of EEPROM.  It does have a 1uA standby current, which is convenient for our battery powered circuit.  The I2C interface is handy too as I have to manually bit-bang the protocol.

ADC/Microcontroller:
We'll actually be using the internal ADC of the microcontroller, which is a Microchip PIC12F1572.  I showed it separately only be cause it needs a little consideration.  Since our circuit will be battery powered, the circuit voltage will vary over the life of the batteries, which means we can't use our circuit power as the ADC's positive voltage reference.  Fortunately the micro contains a fixed voltage reference module.  By manipulating the appropriate registers you can get a 2.048V reference, which can also be connected to the ADC module.  I'm taking a guess that the light sensor is less dependent on the applied voltage as it is to the applied light, as its response is to allow current flow.  Truthfully, I don't know the actual part number of the ambient light sensor, but some datasheets I've looked into support my conclusion.  But regardless of the voltage from the batteries, the ADC will always measure the incoming light based on a 0 to 2.048V scale.

Our microcontroller does all of our grunt work.  It will schedule when to take light measurements, store the results in the memory, and communicates via a serial port with a PC.  It'll perform a few other functions we'll discuss later, but these are it's core responsibilities.

In the next post I'll show the resulting circuit and discuss more details of the design.