Saturday, 27 June 2015

Don't be so wet! ...

.... or so dry!

It's been six months since my last post, a long time but I've been busy.

Continuing my exploration of all things electronic, I've been happily making stuff, making mistakes, making a fool out of myself by asking stupid questions of anyone and everyone, but also learning a lot. I've compounded all the practical work with a couple of free online courses too - both from Coursera, I've stumbled successfully through Linear Circuits and also Introduction to Electronics - not too advanced, but useful nonetheless and certainly as much as I could manage with a full time job!

So, what's with the "wet and dry" theme?

How to explore your own hobby while keeping your "significant other" happy!

My wife is a keen gardener. That's keen with a capital K, and gardener with a capital G. So we have an active and ever evolving garden, plus more houseplants than you can shake a stick at.

So, for my next project, I cunningly suggested that I might make her something that would allow her to monitor the state of her houseplants from the comfort of the sofa - that is to say, a wireless plant moisture monitoring system! No, I didn't mention that you can buy such things for very little money and with much more hope of success, but I got the green light to start building things, which was the main result I wanted ... hehe.

Wireless wetness

If you Google or eBay for nRF24l01p, you'll find loads and loads of people who will sell you these little units very cheaply:

What it is, is a 2.4GHz wireless transceiver that you can talk to with Arduino, Pi, PIC, whatever and generally get simple wireless capability into your projects very easily. So I bought a handful.

They run off 3.3V so rather than using my normal preference of 5V PICs, I chose to use one of the PIC16LF range of low power microcontrollers, in this case the PIC16LF1554, which has much more available than I needed for this project (I just need SPI and ADC really) but it did allow me to test and prototype with a UART talking to my PC via a TTL to USB adapter.

The grand plan

So the grand plan was to have a number of moisture monitoring sensors, each one stuck into a favoured houseplant pot, and each periodically measuring the soil moisture level and pinging off a packet of data to a central monitoring station, which would collect and collate the various wetness reports and allow them to be presented in a suitable manner.

I planned to use simple resistive moisture sensors because a) they are cheap, and b) they are cheap. So a few quid on eBay and a long wait for China Post and I harvested a dozen of these:

To read the moisture level, you simply wire this as part of a voltage divider that you sample through the microcontroller's ADC (analog to digital) pin to get a resistance measurement that you blindly assume is both accurate and varies in a linear relationship with the moisture level. Neither of these are true, but who cares - that's not the point! I did pay homage to some advice though that warned against always sampling with the same polarity - risk of gradual electroplating of one prong from the other - so I always take two ADC readings, one with polarity reversed, to even up the battle a little.

To make things even more interesting (complicated), I also wanted a way to reconfigure the sensor units without having to reprogram their PICs, so I used a simple protocol that allows me to remotely adjust the frequency of wetness sampling for each individual sensor. It goes something like this:

  • Sensor wakes from sleep mode.
  • Sensor takes two ADC readings and creates a packet of data.
  • Sensor sends data to the master unit.
  • Sensor waits a reasonable number of milliseconds for a reply.
  • If the reply arrives and requests reconfiguration, the sensor adjusts its sleeping time.
  • Sensor goes back to sleep.

By using the PIC's watchdog timer to wake it from sleep mode, along with some suitable preset combinations of prescaler and counter, I could manage a sampling period of anything between 15 seconds and 16 hours. The former useful for testing and the latter 8-hour or 16-hour period being used in practice.

The sensor

The sensor circuit went through two revisions. Mainly because I was stupid. Ok, no "mainly", but only because I was stupid!

But then you don't learn anything without making mistakes, so stupidity is a good thing ;-)

So the first version of the sensor PCB looked like this:

The first stupid mistake is the battery on the left. I chose the wrong part in Eagle, so instead of having a battery holder, I had a fixed battery with welded solder tags that you can't remove from the board without desoldering. So obviously, you also can't switch it off. Hmmm .. too keen to get the boards ordered, and I don't mind admitting it. Lesson learnt. Probably.

The second stupid mistake was that I forgot to add the recommended 10uF capacitor across the power terminals of the RF unit. In practice it didn't seem to matter, but as I was going to redesign anyway, the second version attempted to fix these issues. The final schematic for the sensor was like so:

At the top left is the 4x2 header to receive the nRF24l01+ unit, then under that is the voltage divider circuit to the moisture sensor (JP1), and apart from power and bypass cap, that's it. So it now looks like this:

The battery can be removed or replaced as required and so I now have a nice stock of the other, fixed tag, batteries because I found I could buy 80 of them for ~£5 on Amazon. Ho hum.

Anyway, I made six sensor boards, each PIC pre-programmed with a unique identifier that gets put in the data packet when sending to the master. So the master correlates the sensor ID with its - also pre-programmed - list of houseplant names, ready for display. Hooray - nearly done.

Mastering the master

The master unit is actually the more complicated part of the system. Not because it has any inherent complexity, but really because it's difficult to fit all of the code into the 4096 words of flash memory and 256 bytes of RAM. For anyone familiar with MPLAB X, how many times have you seen your resources so completely used as this?

This is because we need the code for talking to the RF unit, the code for talking to the OLED, the code for interacting with the 23LCV1024 SRAM, various text strings, and also font mappings. Quite a lot to fit in!

Anyway, here's the schematic:

I've put a 3.3V LDO there because I'm powering it from a 5V wall-wart even though it's 3.3V throughout - it's much easier to find spare 5V supplies in the rummage boxes. So, nothing too difficult to see there - the external RAM has a fixed battery (I knew they would come in useful!) to keep its content safe during power off and I've also added a jumper in there to clear the RAM if I want to start again. In the code, it first reads the RAM looking for a magic number to see if it was previously initialised or not. If not, it writes six pages of empty data to the SRAM with the plant names coded from a 5x7 font. So the display is really just mapped to the SRAM and the PIC only needs to write the bars for the incoming data and read back a single page at a time to display.

The populated board looks like so:

Power comes in top left, the PIC is bottom left and the SRAM bottom right. The momentary push switch at top right allows one to cycle through the six houseplants to see the current moisture level and a bar chart history over the last 128 sample periods (only 128 because the OLED is 128 pixels wide).

Seeing is believing ...

So, finally (yes I know I'm rushing), I've made a short video of the master unit in action so you can see the principle. As usual, I'll link to the code downloads at the bottom ...

One thing that may be interesting is what happens to the soil moisture sensor after a few months use. This is what my first sensor looks like now, after something like five months in an indoor plant pot (over-watered, as it happens!):

Source code downloads

As promised!

Plant monitor sensor
Plant monitor master


  1. Very nice. I cant ser the vid. Dont know why. How bad is forma pic, since i al starting whit arduino!

    1. Thanks. You need Flash player to see the video - not sure if I can change that but will check. I really like PICs but there's quite a learning curve unless you're either vary familiar with another micro (like Atmel) or maybe have a good C background.


  2. Thanks Man!@RogerRowland You just saved me. Let me explain my project to you, I am sure you can help me. I basically want my PIC16F887 to transfer some calculated values to a raspberry Pi.
    I already have my Pi set up to receive these values. Going through your project, i figured out the only part i need is the plantMonitorSensor.X since i only need the PIC to just transmit.
    Please what changes do i need to make to your main.c to make this work with PIC16F887, I am not too familiar with reading registers but i will.You can illustrate this with a code that simply sends "AB" at intervals. Thanks!

    1. No problem, I don't have that PIC device here so I can't test anything and I have not looked at the Pi either, but I've just put together a small example of the sort of code that *should* work on a PIC16F887. Read the comments, pinouts are different and I removed some redundant code to try to make it clearer. I hope it helps - you can download the example from

      Good luck!

    2. Thanks Roger, I have tried it but didn't work. I tried going through the PIC datasheet too and a part of it talks about SSPSTAT(SSP Status Register), this i think has not been considered in the code and also the part about setting the SS pin. You can go through the code again and see if there is any way you can still help. I really appreciate..!

    3. It's going to be difficult for me to get this working for you without having any of the hardware you're using. There are so many things that need to be checked. Maybe working through this checklist might help:

      1. Check schematics, make sure you have used the correct pins on PIC and nRF24l01+.
      2. Check power supplies, you need 3V3 for everything and also need decoupling caps and a 10uF on the RF power pins.
      3. Make sure SPI works on the PIC by using it to talk to another device first. In my tests, I used a small serial EEPROM and a logic analyser.
      4. Check the RasPi receiving code and schematic. Are you listening on the same address as the sender? Are the speeds and protocols correct?

      I know it's not easy, I went through the pain myself, but there's no way you're going to be able to copy/paste some code and get this working without some debugging on your side. Separate the problems, tackle them one by one then put things together.

      I hope that's helpful - I'm not sure what else I can suggest at the moment.

    4. Thanks, I think it would help to show the Configuration settings at my receiving end.

      ================ SPI Configuration ================
      CSN Pin = CE0 (PI Hardware Driven)
      CE Pin = Custom GPIO25
      Clock Speed = 1 Mhz
      ================ NRF Configuration ================
      STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
      RX_ADDR_P0-1 = 0xffffffffff 0xf0f0f0f0e1
      RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
      TX_ADDR = 0xf0f0f0f0d2
      RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00
      EN_AA = 0x3f
      EN_RXADDR = 0x03
      RF_CH = 0x4c
      RF_SETUP = 0x11
      CONFIG = 0x0e
      DYNPD/FEATURE = 0x3f 0x04
      LINUX Data Rate = 1MBPS
      Model = nRF24L01+
      CRC Length = 16 bits
      PA Power = PA_MIN
      PA Power =
      ************ Role Setup ***********
      Choose a role: Enter 0 for receiver, 1 for transmitter (CTRL+C to exit)

      With this, do you think they are in synchronism with each other?

    5. No, they are not in synch.

      If you compare the register values with my example code in NRF_Setup(), you will see that I use the following different settings:

      RX_ADDR_P0-1 = 0xE1A3B0D5F1
      TX_ADDR = 0xE1A3B0D5F1
      EN_AA = 0x00
      EN_RXADDR = 0x01
      RF_CH = 0x4C
      RF_SETUP = 0x27
      CONFIG = 0x0B

      You need to align these by changing either my sending code or your receiving code, but do bear in mind my previous comments - I can't realistically do much to help you here, you could have compared these settings yourself.

    6. Thanks so far Sir, I am very close to getting it now. I have been making sure that they have aligned configuration. Please (1)how do i set CRC Length of the NRF to 16 Bits instead of 8bits. (2) How to do set the data rate to 1Mbps instead of 250kbps. The raspberry Pi can least communicate with those specs. I found that out by establishing a Pi to Pi connection. Thanks

    7. Don't worry about the last message, i have figured that out from the nRF datasheet. But please can you help me check the code you sent to me if there is anything you are missing out regarding the PIC?(especially the SPI settings). I have tried but i still can figure anything out

    8. Ok, if I get time at the weekend, I'll read the PIC16F887 datasheet and compare it with my code. However, I can't really do much more than that for now. If I can get my hands on a sample of that PIC, I could make sure that SPI works ok, so maybe I'll include one in my next order. In the meantime, you could try getting the PIC to talk to another device using SPI (e.g. an EEPROM like I suggested before) just to make sure that all is well. You could even check with a logic analyser if you have one.

      I'll reply again after the weekend if I have anything that might help - let me know if you get it working though so I don't waste too much time.

    9. Any new development so far Sir?