4 ms·
IIRC, the DS18B10 (like its cousins) does not return celsius multiplied by 10 (i.e., not '153' for 15.3°C), but returns a 7 bit integer celsius value plus a sig
by beeforpork 6y ago
IIRC, the DS18B10 (like its cousins) does not return celsius multiplied by 10 (i.e., not '153' for 15.3°C), but returns a 7 bit integer celsius value plus a sign plus a few fractional bits -- by default 1 (i.e, a +-7.1 bit format), but maybe this device has a few more bits in a secondary register -- I remember using one that had four sub-celsius bits, i.e., would output 1/16 celsius steps (a +-7.4 bit value). In any case, not a value multiplied by 10, but a celsius unit with binary fractional bits.
Am I wrong? Looking for DS18B10 data sheet always gives me the DS18S20. Hmm, dunno.
Anyway, assuming a sign + 7 bits integer + 4 bits fractional format, you can calculate inside 16 bit signed without overflow with a 3-bit shifted 9/5 constant without overflowing, up to beyond 100°C. With a bit of shifting, the following is quite accurate:
int16_t celsius2fahrenheit(int16_t c)
{
int16_t f = 0;
f += c << 4;
f -= c;
f -= c >> 1;
f -= c >> 3;
f += c >> 5;
f += 32 << 7;
f >>= 3;
return f;
}
Accuracy:
C=0 (int: 0), F=32 (exact: 32, int: 512)
C=15.3 (int: 244), F=59.4375 (exact: 59.54, int: 951)
C=37 (int: 592), F=98.625 (exact: 98.6, int: 1578)
C=100 (int: 1600), F=212.062 (exact: 212, int: 3393)
- noexani 6y agoYou are correct. the conversion to Celsius * 10 is done earlier on, because it is easy to optionally perform this conversion, and it's easy to render the various formats (positive/negative/DP,no DP) of it to the 7-segment display banks. Also worth considering that I originally had no interest in fahrenheit (I live in the UK). This was done as an extra later on. Didn't want to poo the original implementation taking fahrenheit straight off the sensors.
- beeforpork 6y agoOK, I understand. The approach works even better if you multiply by 10: int16_t celsius2fahrenheit10(int16_t c) { int16_t f = 0; f += c << 4; f -= c; f -= c >> 1; f -= c >> 3; f += c >> 5; f += 320 * 8; f >>= 3; return f; } This is really accurate: C=0 (int 0) F=32 (int: 320, exact: 32) C=15.3 (int 153) F=59.5 (int: 595, exact: 59.54) C=37 (int 370) F=98.6 (int: 986, exact: 98.6) C=100 (int 1000) F=212 (int: 2120, exact: 212)
- noexani 6y agoIt's really interesting to see that it could be done like that, but, that pseudo code you've given me would translate to a heck of a lot of MCS-48 instructions! 16-bit subtraction in particular is really expensive. Potentially not much gain there?
- beeforpork 6y agoBut you do have CPL -- that does not help? Anyway, without subtraction, you could do the very same with one additional add: int16_t celsius2fahrenheit(int16_t c) { int16_t f = 0; f += c << 1; f += c << 2; f += c << 3; f += c >> 2; f += c >> 3; f += c >> 5; f += 320 * 8; f >>= 3; return f; }
- beeforpork 6y agoThis is the same code in MCS48 assembly. Or so I hope. ; INPUT: r1:r0 celsius * 10 ; OUTPUT: r3:r2 fahrenheit * 10 MOV A, r0 ADD A, r0 MOV r2, A MOV r4, A MOV A, r1 RLC A MOV r3, A MOV r5, A MOV A, r4 ADD A, r4 XCH A, r5 RLC A MOV r4, A MOV A, r2 ADD A, r5 XCH A, r3 ADDC A, r4 MOV r2, A MOV A, r5 ADD A, r5 XCH A, r4 RLC A MOV r5, A MOV A, r3 ADD A, r4 XCH A, r2 ADDC A, r5 MOV r3, A MOV A, r1 ADD A, r1 MOV A, r1 RRC A MOV r5, A MOV A, r0 RRC A MOV r4, A MOV A, r5 ADD A, r5 MOV A, r5 RRC A XCH A, r4 RRC A MOV r5, A MOV A, r2 ADD A, r5 XCH A, r3 ADDC A, r4 MOV r2, A MOV A, r4 ADD A, r4 MOV A, r4 RRC A XCH A, r5 RRC A MOV r4, A MOV A, r3 ADD A, r4 XCH A, r2 ADDC A, r5 MOV r3, A MOV A, r5 ADD A, r5 MOV A, r5 RRC A XCH A, r4 RRC A MOV r5, A MOV A, r4 ADD A, r4 MOV A, r4 RRC A XCH A, r5 RRC A MOV r4, A MOV A, r2 ADD A, r4 XCH A, r3 ADDC A, r5 ADD A, 10 MOV r2, A ADD A, r2 MOV A, r2 RRC A XCH A, r3 RRC A MOV r2, A MOV A, r3 ADD A, r3 MOV A, r3 RRC A XCH A, r2 RRC A MOV r3, A MOV A, r2 ADD A, r2 MOV A, r2 RRC A XCH A, r3 RRC A MOV r2, A