Tuesday, 31 October 2017

A fortuitous ebay mistake

Today, my ultrasonic sensor arrived with the 4 digit display.  BUT - instead of the bare 4 digit display, they sent me a display module with a 4 pin interface, which is good, but it is a clock module with a colon in the middle, rather than normal digits - each with a decimal point.
After a little digging around, I have found a library to drive the module and figured out how to use it.  As it happens - since I wouldn't need a decimal point, I could use this module in the water tank gauge project, but I have already pointed out the mistake to the seller, in the hope he will send me a new display of the type shown in the ebay listing.

But as I now have an LED display geared up for a clock type display, I thought - why not pair it up with my new RTC module and have a little clock.  Ok - so it only shows hours and minutes, but it will help me to test the longevity of the 2032 battery in the DS3231.

Here is my code for the clock

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <DS3231.h>
#include <TM1637Display.h>


// Module connection pins (Digital Pins)
#define CLK 9
#define DIO 8

// Initialise LED
TM1637Display display(CLK, DIO);

// Initialise RTC & RTC variables
DS3231 Clock;
bool Century=false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;

// other variables
long counter;
uint8_t mask = 0b00010000;


void setup() {

// turn off annoying LED on 13
  pinMode(13, OUTPUT);
  digitalWrite(13,LOW);

// set brightness of LED
  display.setBrightness(0x0f);

// set all segments off for all digits
  uint8_t data[] = { 0x00, 0x00, 0x00, 0x00 };
  display.setSegments(data);

// store current millis()
  counter = millis();
}

void loop() {
// get Time from RTC
  int hrs = Clock.getHour(h12,PM);
  int mins = Clock.getMinute();

  if (hrs > 12) hrs -= 12;
  
// display the hours with colon enabled/disabled as each second passes
  // mask for colon on digit 2
  // 0x80>>3 = 0b00010000 (I have no idea WHY this works!)

  if (millis() - counter > 1000) {
    if (mask == 0b00010000) {
      mask = 0b00000000;
    } else {
      mask = 0b00010000;
    }
    counter = millis();
  }
  display.showNumberDecEx(hrs,mask,false,2,0);

// display the minutes
  display.showNumberDec(mins,true,2,2);

}

I have tried forcing the hours to am/pm mode, as the RTC always seems to show it in 24 hour format (I expect there is a way to do it using the library functions, but I didn't find it yet), and then apply leading zero suppression to the hours, so that it shows as 9:00 for example, rather than 09:00.  However, I'm not sure what'll happen between midnight and 1am - perhaps the hour will not show at all...?  I won't be awake to see it though - at least not tonight!

I have no clue why the mask that controls the colon being displayed works... it is a bitwise shift right by three places, but by my reckoning, as the left most bit in the mask is a shift of 0, then the mask should be using a shift of either 1 or 2 places (depending if the colon is linked to the right side of digit 2 or the left side of digit 3.  But - I got it working by trial and error, and have even managed to make it flash every second.

Tomorrow, hopefully, I may start playing with the ultrasonic sensor unit.  Exciting!!

Update - 2 days later:
The RTC is still holding the time well.  I did originally have some issues with it randomly resetting itself, but I think was down to my dodgy prototyping with modules just hanging off the Uno on the end of DuPont cables - things were possibly touching other things and shorting out, etc.  After I blu-tacked all the modules down on a base board - no more problems.
By the way - even with leading zero suppression, times between midnight and 1 o'clock DO show with a single zero for the hour, as I hoped.

Update - 3 weeks later:
It is still holding the time, but given that my display is only hours and minutes, I haven't confirmed just how accurate the time is.  But the fact it still has a valid time that is even roughly correct is a big win.  

Wednesday, 25 October 2017

Success Squared

Yep - I had two successes last night when I started my tinkering.

Firstly, after soldering pins onto the Pro Mini, I was able (eventually) to use the Uno to load a sketch to it  (it came with bootloader and blink sketch already loaded).  But this was not quite the 'piece of cake' I predicted.  I have header pins on the Pro Mini, allowing easy connection to pins 11-13, Vcc, Gnd, and Rst.  Because of the ISP indicator lights widget, pins 10-13 on my Uno are not accessible, so I thought I'd be clever and connect the Pro Mini to the ISP6 pins on my Uno.  That's when the problems started.  While 'Arduino as ISP' loaded on my Uno, I couldn't get it to load a modified blink sketch to the Pro Mini.  The error was something like 'unknown board id'.  I removed the 6 connections at both ends and did them again (and again just for good measure), but with the same result.  I went back out to the garage, and re-flowed the solder joins on my Pro Mini header pins - and also the 16MHz crystal as one of the joints looked a little suspect.  Still no joy.  I was about to head out to the garage for a third time, to try and find a capacitor to put between Reset and Ground on my Uno, when I decided to take out the status lights widget and try making the connections from pins 10-13, Vcc, and Gnd on the Uno rather than the ISP6 block - and it worked!  Go figure - I have no idea why - as far as I knew, they should be connected to the same pins on the 328P chip...  Anyway - I'm not going to argue the point - I'm just happy that I now have a tried and proven mechanism to download sketches to the Pro Mini.  Unfortunately, I will have to either modify my little ISP status lights widget to free up access to pins 10-13, or just solder the second row of header pins onto my Uno - I guess that's a simpler and probably more useful option.

The second success was with my DS3231 RTC.  I downloaded a library for it, and it has several example sketches - a very simple 'Set' process, which I ran and managed to enter a time that was just 3 seconds away from my cell phone's time.  Then I used a basic 'Get' example that wrote the details back to the serial console.  I stuffed a CR2032 battery in the RTC, and then unplugged everything, and started it up again running the 'Get' script, and it was still just 3 seconds from my phone.  Next, I found one of my old sketches that I used to test the DS1302, that uses my LCD 20x4 display, and did some quick hacks on that so I can run the script without needing to be connected to the computer for serial output.  Again, I left it all unplugged overnight, and fired up the Uno, LCD and RTC simply with a 9v battery this morning - and it was still just 3 seconds from my phone.  Yay!!

So the next project with the RTC is to create a nice 'Set Date and Time' sketch that uses the LCD rather than the serial input from the console, and that allows for minor adjustments, and 1 hour advance and retard operations for daylight savings.  Then I want to experiment and understand the benefits of simply using the RTC lib on its own, as opposed to using the Time lib and 'syncing' to the RTC.  I want to find the simplest way possible, that I can use the time from my RTC in my projects, and then to use it consistently, rather than every project using a different combination of libraries and commands to handle time.  There seem to be endless different ways with different libraries and so on.

Postscript...
I spoke too soon.  Came home this evening and switched on the Uno again, and boy - what a load of cobblers came up on the screen!  I reset it and rebooted it, but still rubbish.  However, I noticed that it kept initialising to exactly the same load of cobblers each time.  So I took the battery out of the RTC and tried again, and it was still booting to the same point each time, until eventually, it started booting to 01/01/2000 at 00:00:00.  So I'm hoping that all this means is that the battery I had was at the end of its life - it had been recovered from the motherboard of an old PC after all.  I'll try again with a fresh battery tomorrow.

Tuesday, 24 October 2017

Water Tank Depth Gauge - 2

Time has passed, and the first few of my new batch of components arrived in this morning's post - well, the Pro Mini for this project has arrived at least (but I also treated myself to some 4-pin DuPont cables for IIC device connections, and another RTC after the DS1301 proved to be cr@p, so I've now got an IIC DS3231 board, which I hope will be better - or at least work!!).

In the intervening time, I've made a start on developing the code for my gauge.  It consists mainly of 3 parts - the first part deals with the sensor itself, getting the 'ping' reading (which is the echo return time in microseconds), and converting that into the sensor-to-water distance in cms.  From this measurement, and knowing the distance from the sensor to the highest and lowest water levels of the tank, I can work out the percentage capacity used or remaining in the tank. 

As an afterthought, I've also included a HIGH/LOW test on a pin I've called OpMode, which I will connect to a 3-pin header with a jumper allowing it to be connected to Vcc or GND.  This will facilitate the display of either the percentage value (as described above), or the actual distance measured.  This second mode will allow me calibrate the unit, as I am not convinced it will be accurate to 3mm as claimed by the manufacturer.  In fact I have seen many articles that show errors of several cms, even at just half the suggested max 400cm capability of the unit.  Remembering that all my purchases are of cheap (and therefore most likely 'seconds' quality, or poor quality knock-offs) Chinese ebay items, so I am fully expecting to need to add some correction factors in once I have all the parts and can do some testing.  I'll probably put up a post showing my results when I have all the parts and can do some controlled experiments.

The second section of my code simply takes the resulting number (either a distance in cms, or percentage), and breaks it down into individual digits - hundreds, tens, and units.  This means I will only use a maximum 3 of the 4 digits on the LED, so I can use the 4th to indicate the OpMode (test/normal).  Note - if the first digit is 0, I want to display nothing on that digit in the display, rather than prefixing the rest of the number with a zero.

The third part then takes each of the three digits and OpMode, and displays them on the LED digits 1-4 sequentially.  The LED is a common cathode device, which means that you can display the same value on all 4 digits at the same time, but if you want each to show a different value, then you have to do them one at a time.  Switch on digit 1 and light up all the correct segments; wait very briefly; then switch them all off again and move on to digit 2 and repeat.  The trick is to do this while looping around all 4 digits fast enough to make it appear they are all being displayed simultaneously.  I have done this by creating a subroutine called displayDigit, and passing it the digit to activate, and the value to be displayed, and placing 3 calls to it from the loop() subroutine.

In relation to my suspected faux pas regarding buying the Pro Mini board without an ISP interface board to program it, I am pleased to say that further research has reveled that the articles I referred to previously, whilst giving me hope of potential work-arounds, were perhaps over-complicating the procedure.  Thanks to Julian Ilett's youtube video - Arduino as an ISP, it looks like using an existing Arduino to load a sketch OR a bootloader to the Pro Mini or any other xxuino device, is a piece of cake!  I love Julian's videos - he has a great way of explaining things.  If you watched this video, I have already cobbled together my own version of his 3 LED ArduinoISP monitoring widget, and have installed the sketch on my Uno so I can watch the heartbeat.

For those that haven't yet watched it, there is a 2 stage process for loading a sketch or bootloader to a second device... Since I am using my Uno as the programmer, and Pro Mini as the target, I'll use these in my description below, but the concept holds true for programming any target xxuino from any programmer xxuino (as far as I can tell) though the specific pin connections may vary from device to device - especially if they don't have an ISP6 6-pin block and you are having to use digital pin equivalents. 

So the first step is to load the "ArduinoISP" sketch onto my Uno, in exactly the same way I load normal sketches, to turn it into a pass-thru ISP controller.  The second step is to load my water gauge sketch into the IDE, then select Pro Mini as the board.  Now, rather than the normal compile and upload operation, go to Tools/Programmer and select the "Arduino as ISP" option.  This compiles the sketch in the IDE and passes the compiled code to the sketch that is running on the Uno.  This sketch allows for a stream of compiled code to be received from the IDE, but NOT loaded into memory by the bootloader.  Instead, it passes the compiled code on to the Pro Mini where its bootloader DOES store it in the Pro Mini's memory, ready to go when disconnected from the Uno and given its own power supply.

In case you need to actually install the bootloader on the Pro Mini, then when you have the ArduinoISP sketch loaded on the Uno, select the Pro Mini as the target board again, then go to Tools/Programmer, and use the "Install Bootloader" option.  I am not 100% sure if the first step is really required, but I think that without it, you may end up potentially screwing the bootloader on the Uno or have the whole operation fail because the IDE see's an Uno board at the other end of the USB cable, rather than leap-frogging to the Pro Mini selected.  Personally - I'm not game to test out my theory - but if you are adventurous, go ahead and try, and let me know what happens in the comments below.

OK - So, now I just want to get the rest of my day at work over and done with , so I can get home and start tinkering this evening - first job, connect header pins to Pro Mini so I can plug it into my breadboard and see if it has a bootloader and 'blink' sketch loaded :)

Wednesday, 11 October 2017

Water Tank Depth Gauge - 1

I've got a 2000 litre rainwater tank by my garage (actual usable capacity is around 1750), but it is really difficult to know just how much water remains in it at any time, so I am going to try and build a depth gauge based on an ultrasonic sounder that I can hold at the top opening of the tank, and measure the distance from there to the surface of the water.  Once I have that, the rest is just maths.

I initially fancied mounting the sounder permanently inside the top of the tank, with the display inside my garage - but I fear that the humidity and condensation in the tank would probably very quickly render the sounder unit useless, or at the very least, it would drop into the water.  So I am now thinking of making a 'portable' unit that will be mounted to a bar that can be placed across the opening into the tank, thus providing a consistent starting point for the measurement to be taken each time.

I have ordered an HC-SR04 ultrasonic sounder from eBay, that also comes with a 4-digit 7-segment LED display.  That takes care of the measuring and displaying of the output.  I also decided to buy the cheapest xxduino device I could find, which I could therefore afford to have dedicated to this specific project... I found and ordered an Arduino Pro Mini device, without really knowing too much about them.  Luckily, it only cost $2.20, as subsequent investigations and planning my project have revealed I may have made a booboo, and could face some difficulties with it...

The Pro Mini I have purchased is by happy accident, the 5v version, so I won't have any power woes (I later found there is also a 3.3v variant, and combining the 3.3v version with the 5v requirement of the sounder and display would have meant dual voltage complications) , BUT more frightening - I suddenly realised that this board has no USB connector on it... I had ordered the wrong item in my excitement - I had meant to order a Nano which DID have the USB connector.  I had a sudden feeling of dread - how am I supposed to program and test this thing?

Well, some late night research was done so I wouldn't have to admit to my blunder, and I think I may be OK (but only time will tell).  Thankfully, I have found a couple of "Instructables" articles aimed at using my Uno as a middle man between my PC and the Pro Mini, without having to remove the ATMega chip from the Uno (there were plenty of articles that relied on removing the ATMega328 chip, but this is not really a practical proposition on mine, as it has the small form factor surface mounted chip soldered directly on the board).  One of these articles shows how to use the Uno as an ISP to burn a new bootloader to the Pro Mini if required without needing an FTDI board (sure enough, subsequent readings of the seller's notes makes no mention of a bootloader having been installed...), and the other explains how to load sketches to the Pro Mini using USB from PC to Uno, and then Serial (TX/RX) from the Uno to the Pro Mini.  So, fingers crossed, I will be able to set these connections up semi-permanently while I am testing and developing my gauge, and just disconnect them once I am happy with the final programming.

As always - having ordered these things from China, it will be about 4-6 weeks before I actually receive them (and a few other bits I ordered at the same time), so I don't know when the next instalment of this project will appear.  Watch this space...!