Month: November 2015

I am using an NTC to read temperature. I use the Steinhart-Hart formula to calculate the temperature from the Resistance of the NTC. The output of that formula is a float (double integer, 4 bytes).
I also want to log the results in memory. For that I have a couple of choices
Store the floating point variable : that will cost me 32 bits of memory for every temperature value logged
Store the original NTC reading and just pull that through the Steinhart-Hart formula again when needed, that will cost me 16 bits for every temperature logged.
As I really don’t need the high decimal precision that a floating point value can give and as I really didn’t expect my temperature range to go outside -15 to +30 degrees Celcius, both 16 bits and 32 bits seemed serious overkill.

So I was wondering if I just couldn’t store it in in 1 Byte. As the Steinhart-Hart formula gives an approximation of the temperature, one can wonder how precise of a reading one needs, but I decided I wanted a solution of 0.25 degrees, though no doubt 0.5 degrees would have been enough already.
I figured I would use the MSB for the sign bit, that left 7 bits
decimal number 31 is equal to 0b00011111, so to cover my range I needed 5 bits for the temperature that left 2 bits
In those two bits I can store numbers 0-3, that I could use for the decimal fraction.
Extracting the essential bits from the binary level of the float seemed to much of a problem so I mainly worked with the decimal values.
In the function floatToByte I do a couple of essential things: I first check if it is a positive or a negative number as that determines the MSB I need to set in my byte. Then Itake the absolute value of the float so I get rid of o potential minus value, which would complicate calculations.
Then I turn the float into an integer and subtract that from the float. That leaves the decimal fraction. In order to keep at least some precision in that I have to put that in a double. Initially it was my idea to turn the values 0-9 into 0-3, but a simple division by 3 didnt have the desired effect as ‘9’ was sometimes 0.89 which by division would give a 2, So I decided on some simple ‘if’ conditions to convert the double fraction into half a nibble.
I then would shift the 5 bit temperature 2 bits to the right bitwise OR it with the fraction (on the two least significant bits and bitwise OR it with the sign bit.
That gave me temperature values that I can store in 1 Byte of EEPROM.

The way back – from memory byte to sensible temperature. Goes the other way around

Trying to determine if a number is odd or even on an Arduino is rather simple. There are several ways, but the easiest ways are to either take the modulo of the number to be tested, or do a bitwise AND on the Least Significant Bit.
If x % 2 is ‘0’ that means that x is even. If it not zero, it is an uneven number.
Similar for the bitwise test
If x & 1 is ‘1’ it must be an odd number. If it is ‘0’ it must be an even number.

If you want a specific action in your program to happen every so many hours or say just on the odd or even hours, that is rather simple.

Suppose I have a hydroponics system that I want to irrigate 6 times a day.
I have an Arduino +RTC and the hours are stored in variable ‘hour’.

6 times a day is every 4 hours.
I could of course specify the action 6 times, but there is a simpler way: I can just check if the hour can be divided by 4. How do I do that? Well, a number can be divided by 4 if it can be divided by two, and then still would be even. (ofcourse you could check for x%4==0 but this is just to illustrate).
So I would have the condition:

if(((hour / 2) & 1) == 0)
{
// then it must be 0,4,8,12,16,20 hr
}

Because:
0/2=0 0&1=0
4/2=2 2&1=0
etc…

Sadly of course that may work on paper arithmetic, but it doesn’t work on a microcontroller like the Arduino, for the simple reason that bytes and integers don’t know fractions. So if ‘hour’ would be ‘3’, ‘hour/2’ would not be 1.5 but 1. Well, no problem there, but if it would be ‘5’, hour / 2 would not be 2.5 but ‘2’. That is still an even number and that would make the computer think ‘5’ is in fact even.

This is what numbers 0-23 in bytes or integers look like when divided by 2

So instead of 6 actions, I get 12 actions.
There are several solutions for this. One solution could be to use floats, but they consume 4 bytes, where we prior could use 1 byte for the hour. Also, as they are stored differently, the ‘& 1’ would give unpredictable results and the modulo function also doesn’t work on floats. So that would probably create more problems than it would solve.
The better solutions becomes immediately clear from the the table: if we first filter out the odd numbers, then divide by 2 and then check if the number is still even, then we have obtained our goal.

Floating point numbers are positive or negative numbers with a decimal fraction: numbers such as 1.0 or 17.11 or –3.12 are all floating point numbers.
On the Arduino and other microprocessors are stored in ‘floats’.
Whereas the concept of a byte or an integer is quite straightforward, a float in binary form is a bit more challenging.
A byte is simple, it is just 2⁷+2⁶+2⁵+2⁴+2³ + 2²+2¹ +2⁰.

An integer is similar, be it that it extends to 215.

But how do you store a number like –1.5 ?

Well, floats are stored on the concept that practically every number can be expressed as the multiplication of a power of 2 times a number between 1 and 2. Take for instance 7, or 7.00 for that matter, that can be expressed as 4 * 1.75 (or 2² * 1.75).

the number -1.5 is in fact 1 * 1.5 which is 2⁰ * 1.5, preceded by a ‘-‘ sign.
The same goes for higher numbers, say 20.5= 16 * 1.28125 (=2⁴ * 1.28125).
Sure 20.5 can also be expressed by 2*10.25, but the last number must be between 1 and 2.

So in fact every number can be represented by:
sign * 2x * y (y being a number between 1 and 2).

According to agreement we call ‘x’ the ‘exponent’ and ‘y’ the ‘mantissa’ though the word mantissa is also used for the fractional part of a logarithm. The IEEE standard for floating point numbers therefore encourages to use the word ‘fraction’ instead of ‘mantissa’, so we can write the above as:
floating point number= sign * 2exponent * fraction

Lets get back to the fraction part of the number 20.5 which is 1.28125 (remember? 20.5=2⁴ * 1.28125). If we look at that a bit deeper, we can see that that is actually 1+ 1/4 + 1/32. That makes sense coz 16* (1+1/4+1/32)= 16+4+0.5=20.5.
If we would break this down again we can see that the ‘fraction’ or mantissa is actually a sum of fractions that all are again 1/(a power of 2). It is probably clear by now that for 20.5 that would be 1/2⁰ + 1/2² +1/2⁵

Anyway, back to the binary storage.
As said, on the Arduino and many other processors, the floating number is stored in 32 bits and the protocol to store that follows from the notation we have learned above.
The most left bit, bit 32, stores the ‘sign’ if it is a ‘1’ the number is negative, if it is a ‘0’ it is positive.
The next 8 bits, bits 31-24 store the exponent. as we want values between 2128 and 2-127, we store 2¹ as 10000000 (decimal 128), 2² as 10000001 (decimal 129), 2³ as 10000010 (decimal 130) etc… The exponent thus follows from subtracting 127 from the decimal number that is stored in bits 31-24.

The fraction or mantissa is stored in bits 23-1. However, since we know that the fraction is always between 1 an 2, we do not store the ‘1’ as we know it is always there. We refer to that as the ‘hidden’ bit, although it is not hidden, it is just not stored. We use bits 23-1 to indicate a sum of the fractions 1/2, 1/4, 1/8, 1/16 etc.
So, the binary storage of a float is as follows:

The DS3231 RTC is a rather accurate RTC that has an internal temperature sensor that is used to calibrate the oscillator. The sensor is however also readable from external software. It has a 10 bit solution and uses two registers: 0x11 and 0x12. The information in the upper byte is stored in 2-complement notation. The lowerbyte is there for the fractional part and has a solution of 0.25 degrees Celsius.
Two’s complement notation means that with positive numbers it just follows the regular binary storage, but with negative numbers it does it a bit different. Knowing whether a number is negative or positive is indicated by the MSB in the Upper byte. If that is a ‘1’, then the number is negative.Any reading of the registers therefore needs to include a check to see if the number is positive or negative. As the Lower byte only indicates the fraction with an accuracy of 0.25 degrees it only needs to count to 4 (0.0. 0.25, 0.50, 0.75), hence two bits are enough
So suppose we have retrieved the number:
0b0001100101 => +25.25°C. We can easily see it is 25.25°C because the top 8 bits are 00011001, which is 25, while the lower two bits 0b01, mean 1×0.25.
As the lower byte, only uses the top 2 bits, it may need to be rightshifted 6 positions for calculations. So how about negative numbers, say -18 degrees.
Well -18 is 0b11101110 (=238 in twos complement notatie).
We can see that the highest bit is a 1, indicating a negative number. In order to make a check, we do the following:
0b11101110 & 0b10000000 => 0b10000000 So we know it is negative
Then we need to convert the 2 complement notation
0b11101110 XOR 0b11111111 => 0b00010001 (=17) // first XOR it
17+1= 18 // and add a ‘1’
18*-1 = -18 // and then we turn it negative
So, how does that look in a program?

Obvously this isnt a full program but just a function. You still need to define REG_TEMPM (0h11) and REG_TEMPL (0x12), and ‘readRegister’ is another function that just reads the specified registers (using the ‘Wire’library)

I know, this subject can be found all over the web, but the calculations sometimes are presented a bit cryptic as if the author wanted to put as many nested calculations on one line, so I just wanted to write something that explains it step by step, especially where the actual calculations are concerned. Lady Ada does a good job explaining the use of the thermistor, but I added some more explicit calculations.
The Arduino has several ADC ports that we can use to read a voltage, or rather an ‘ADC value’. If the Analog port is connected to Vcc, the max value one reads is 1023 and of course when connected to ground it is 0.Now if we make a voltage divider which is typically two resistors in series between Vcc and Ground and the analogport in the middle, the reading will depend on the ratio of the two resistors: If they are equal, the reading will be 512, halfway to 1023. If one of the resistors, say the bottom one is an NTC, then the readings on the analogport will vary with the temperature:
If the temperature goes down, the value of the resistor increases and so will the reading on the analog port.

Suppose we have a 10k Seriesresistor and an NTC that for now we call ‘R’.
Then the voltage that can be measured in the middle is

Vo=R/(R+10K) * Vcc

The analogPort readings however don’t give a voltage but an ADC value that can easily be calculated
ADC value= Vo*1023/Vcc // if for instance the Vo=4Volt the ADC = 818
or
ADC value= 1023 *(Vo/Vcc)

If we now combining the two formulas or as it is called ‘substitute’ Vo in the formula for ADC we get the following:
ADC value= (R/(R+10K))*Vcc*1023/Vcc
As we multiply by Vcc but also divide by Vcc we can take that out of the equation and end up with
ADC value= (R/(R+10k))*1023
ADC value= 1023*R/(10+R)
if we want to get the value of R out of that equation, that becomes
R=10k/(1023/ADC-1)
If that goes a bit too fast, here is the equation worked out. I prefer pictures over the ‘in line’ formulas as some people have problems understanding the PEMDAS / BODMAS order of operation.

This becomes
subtraction of RWork -R into the multiplicationAs we are interested in R, divide both sides by the enclosed fracture
The ’10’ stood for ’10k’
and as we don’t always use a 10k we just make it more general:So, as long as we know the value of the series resistor, we can calculate the value of the NTC from the measured ADC value. Now remember, this is valid voor a pull-up configuration. If it is a pull down configuration, the calculation of the ADC to resistor value is the inverse.

Knowing the resistance of the NTC is nice but it doesn’t tell us much about the temperature… or does it?
Well many NTC’s have a nominal value that is measured at 25 degrees Centigrade, so if you have a 10k NTC and you measure it to be 10k, that means it is 25 degrees at that moment. That doesn’t help you much when the measurement is different.
You could keep a table in which every resistance value stands for a temperature. Those tables are very accurate but require a lot of work and memory space.

However, there is a formula, the Steinhart-Hart equation, that does a good approximation of converting resistance values of an NTC to temperature. Its not as exact as the thermistor table ( after all it is an approximation) but its fairly accurate.

The Steinhart-Hart equation looks like this:That is a rather complex equation that requires several parameters (A, B, C) that we normally do not have for the run of the mill NTC.There are two things we can do. We can take 3 readings with a calibrated temperature and then work out the A, B and C parameters.

but fortunately there is a simplification of this formula, called the B-parameter Equation. That one looks as follows:To is the nominal temperature, 25 °C in Kelvin (= 298.15 K). B is the coefficient of the thermistor (3950 is a common value). Ro is the nominal resistance of the NTC (thus at 25 degrees). Let’s say we have a 10Kohm NTC. We only need to plug in R (the resistance measured) to get T (temperature in Kelvin) which we then convert to °C.

Feeding the series resistor and NTC from the 5 Volt supply from the Arduino is possible. The Arduino power line does have glitches though. For accurate measurements it is better to use the 3.3Volt line as analog reference and feed the resistor from there.
for that add the following code in the setup
// connect AREF to 3.3V and use that as VCC for the resistor and NTC!
analogReference(EXTERNAL);

EEPROMs come in handy if you want to store some data without losing it. Many microcontrollers come with some internal EEPROM, but as EEPROMs have a finite (though very large) number of writes before they start becoming faulty, my anal retentive character always had a problem with using that internal EEPROM. There are other reasons too why you might want to use an external EEPROM: data logging in which you just want to swap an EEPROM rather than having to read out your microcontroller in the field. Anyway, I just wanted to share a simple 5 minute build EEPROM module that is a bit simpler than a prior one i published. BOM1x 24LC256 EEPROM (or other size) 2x 4k7 resistors stripboard 5 strips of 8 8 pin DIL IC socket (optional)

I am using a 24LC256. That is a 256 kiloBIT EEPROM so in fact only a 32kiloBYTE EEPROM in my traditional way of thinking. These are not to expensive. Can be had for around 80 ct USD. Although the board can also be used for smaller EEPROMS, like a 24C32, I would advise against that. If that is what you need, buy a 50 ct DS1307 RTC module that includes a 24C32 (which is actually 4kByte).

Anyway, the 24LC256 is an I2C EEPROM, which is pretty standard and which makes use easy Pins A0, A1 and A2 select the I2C addresses, (A0=pin1, A1=pin1, A2=pin3). The addressing is as follows

1

0

1

0

A2

A1

A0

x

So if you connect pins A0, A1, A2 to GND the I2C address will be 1010000 = 0x50 in hexadecimal. If you connect them all to Vcc it will be 1010111=0x57. As 0x50 is an address that is often used, I decided to connect A2 and A1 to ground and A0 to Vcc, which gives 0x51. It also made the design a tadd simpler. Pin 7 is the ‘WriteProtect’ pin that needs to be pulled HIGH for ReadOnly and LOW for Read/Write. Obviously I connected it to ground. The pull up resistors are both 4k7 You will find many EEPROM libraries in the Arduino Playground I tend to use the following code to read and write: