One for the techies
In between enjoying the sun, painting and keeping up with FSB work, I’ve been working on my home control hardware and software while here in Spain – and I’ve been constantly battling to ensure that various sensors in use don’t get in the way of the NRF24L01 radio links which need to be polled constantly (until someone comes up with a SAFE way to do this under interrupts).
One issue is the Dallas DS18B20 temperature sensors – accurate but slow (or so it seemed). Most of the Arduino code out there is rehashing of original ideas presented in the Arduino playground – and the most popular example resets the chip – builds up the data – resets it, reads the data – and produces a result. I say Arduino – I don’t use their boards, I do my own – but as I’m using some of the free libraries and the IDE I think the name deserves credit.
Take a look at the this typical code below – firstly it does a scan to see what is available on the wire.. Well, if you only have one Dallas chip on a wire – you KNOW it’s there! Then it checks for a bunch of chips that are not being used.. then it checks for mode – the default will always be 12-bit operation unless you actually tell the chip otherwise! Now, you could argue that conversion time is shorter if you go for less accuracy – but are you really going to check the temperature more than every few seconds max?
It then implements a wait of nearly a second after starting the conversion before reading it.
The problem with the existing code is that it wastes your time EVERY time it checks builds up the reading. Surely a better way would be to do that while you’re doing something else?
As I’m powering my chips from 5v I wondered if I could do away with that 1-second delay. Indeed it appeared I could – but not for all variations – for example the P suffix version just returned garbage.
Having gotten rid of all the un-necessary stuff I’ve mentioned above, it then it occurred to me… why not put the conversion at the END (ie writing 0x44) – ok on first power-up, reading will be rubbish – so I put a loop in to stop that – if the conversion is rubbish (ie over 100 degrees c) then simply loop through again after a delay – that sorts the initial case. So that does away with the delays ASSUMING you’re likely to take readings slower than 1 second apart – the important thing is to be able to minimise your time sitting in that routine. The first shot below has the delay down to around 30ms.
For my purposes I don’t need accuracy better than 1c… but simply using an integer means truncating down so I also added in a check for the 0.5c bit – to correct the temperature so it is truly accurate to the NEAREST degree C. That got rid of the FLOAT. THEN I realised that they were using 12-byte buffer – WHY when you’re only interested in the first 2 bytes..Another 10 bytes gone.
By passing the port bit to the function you don’t have to set that up separately – so a single, self-contained function can call chips on any pin –one per pin!
Here’s the end result of version one as a complete test sketch – as they say, shorter, faster, better. Feel free to use. In my test there is a delay of a second between readings but in reality you’d be doing something else – just make sure you leave around a second before you come back to read the sensor – or more of course. If you have sensors on Arduino bits A4 and A5 as I do – with 5k or thereabouts pullups and the +v wire going to 5v – this should work out of the box. Note the VERY short time between reading the two sensors.
But then – thanks to a chat with my friend Peter Oakes and a FURTHER read of the datasheet – I’ve realised you neither need the checks at the start if you’re on reasonably short wires NOR the address if you only have one chip per pin.
And so VOILA – a routine that takes maybe 5ms to run – yes FIVE MILLISECONDS – and uses even LESS RAM and is simpler…. enjoy. Sorry, some day I’ll figure out how to put code in here without it looking awful – hence the images. The ++result below and above is the 0.5c correction. In this final version – I’ve included a call to go into the setup – to ensure that by the time you use the function properly you’re getting proper data – ie no false data on the first read. Note that the second parameter is always 0 (zero) except in the setup routine – THAT call will take a second per unit.