Hi Hugh, David,
Looking at the part of the code that generates and displays the result there are some other opportunities for simplification.
btw, this is purely meant as some hints on spotting how simplify code (which in turn, reduces bugs etc!). Don't anyone take it to heart or stop posting code in any form, whatever state! It just seems a good opportunity to give some examples of what the C language and mbed can do for you.
In this part of the example, we are basically reconstructing a reading from two bytes, then displaying it.
LowByte = OneWireInByte();
HighByte = OneWireInByte();
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000; // test most sig bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25
Whole = Tc_100 / 100; // separate off the whole and fractional portions
Fract = Tc_100 % 100;
if (SignBit) // If its negative
{
pc.printf("-");
}
pc.printf("%d", Whole);
pc.printf(".");
if (Fract < 10)
{
pc.printf("0");
}
pc.printf("%d", Fract);
pc.printf("\r\n");
With help from the datasheet, you can see this is basically:
- Reading two bytes, then constructing them in to a single value
- Detecting the sign, and transforming the value in to sign + positive value
- Adjusting the fraction, then splitting up it in to sign + value + fraction
- Displaying each part of the number to construct a human readable version
If you look at what it is doing, it is actually just reading a signed fractional number from the sensor, then displaying it, but all in a very "manual" way.
However, we can make the language work for us; it knows about signed/unsigned numbers, floating-point/fractional numbers, and how to print them out already.
From the datasheet, you basically get the result in 2 bytes:
[ 7 6 5 4 3 2 1 0 ] low byte
[ s s s s 11 10 9 8 ] high byte
which is a 2's complement 12-bit number sign-extended to 16-bits. That means if we tell the compiler it is a 16-bit signed variable (int16_t), it'll treat it like one.
Secondly, the temperature in degrees is represented as a fractional number, with the bottom 4-bits being the fraction. Think of it like:
[ s s s s v v v v v v v v . f f f f ]
So to get it in degrees, we would divide by 16 (2 ^ 4). If we do that as an integer division, we'd obviously only get the result in whole degrees, so in this case, we'll divide to create a floating point number. And printing these out is easy, so the code ends up like this:
LowByte = OneWireInByte();
HighByte = OneWireInByte();
int16_t result = (HighByte << 8) + LowByte; // construct sign extended 12-bit value
float temperature = (float)result / 16.0; // convert 12.4 fractional result to float
pc.printf("%0.2f\n", temperature); // print in format x.xx
All we've really done is avoid re-implementing things the language can already do for us, and as a result, hopefully made it easier to understand.
Hope this is useful!
Simon
I'd like to use the Maxim DS1820 one wire temperature sensor rather than an SPI or I2C device. Is there a One Wire Driver available, or do we need to do it in the main code.
Tony