I think I have met my match on the programming side. Actually, its less the programming and more the technique I need to use to solve the problem that I am stuck with.
The DS18B20 returns a 16 bit sign-extended twos complement number like so:
and the datasheet shows these examples.
In "Hardware mini-projects" Leo Nechaev shows code to read the older DS1820 and a routine for converting the two byte temperature that that device returns.
That device produces a lower resolution result i.e there is only 1 bit for 0.5 degreeC so he simply outputs .5 if the bit is set and .0 if it is clear.
I can't get my head around an algorithm for converting the low 4 bits of the DS18B20's results to fractions - i.e. ^0001 converts to 0.0625 (^ is implied binary point)
so binary 00000000 00010001 becomes decimal 1.0625
Does anyone have any thought/example code/example algorithms that might help me please?
DS18B20 - 16bit sig-extended twos complement to ASCII conv
-
adrianhudson
- Posts: 169
- Joined: 30 Apr 2022
- Location: Devon. UK
- Contact:
-
kernelthread
- Posts: 166
- Joined: 23 Jun 2021
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
To convert a binary fraction to base 10, multiply it by 10. That gives an integer part, which gives you the next digit, and a remaining fractional part. Repeat the process until the remainder fraction is zero or you have as many digits as you want. In the latter case you might need to round the result up if the first ignored digit would be 5 or more.
For example if you start with 1/16:
First iteration 1/16 -> 10/16, integer 0 remainder 10/16=5/8 -> output digit 0
2nd iteration 5/8 -> 50/8 = 6 + 2/8 -> output digit 6
3rd iteration 2/8 -> 20/8 = 2 + 4/8 -> output digit 2
4th iteration 4/8 -> 40/8 = 5 -> output digit 5
At this point the remainder is zero, so we stop. So we end up with the string 0625, which is what appears after the decimal point.
For example if you start with 1/16:
First iteration 1/16 -> 10/16, integer 0 remainder 10/16=5/8 -> output digit 0
2nd iteration 5/8 -> 50/8 = 6 + 2/8 -> output digit 6
3rd iteration 2/8 -> 20/8 = 2 + 4/8 -> output digit 2
4th iteration 4/8 -> 40/8 = 5 -> output digit 5
At this point the remainder is zero, so we stop. So we end up with the string 0625, which is what appears after the decimal point.
-
adrianhudson
- Posts: 169
- Joined: 30 Apr 2022
- Location: Devon. UK
- Contact:
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
Fantastic.Thank you very much indeed!
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
You seem like the type of person who likes to "DIY", but if you have a specific output format you would like to share, I'm sure a few of us would enjoy a friendly competition for smallest and/or fastest and/or soonest. Do you want leading and/or trailing zeros and/or decimal point suppression? Do you want the output right or left or center justified? Do you have a display buffer or a character stream output?
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!
Mike B. (about me) (learning how to github)
Mike B. (about me) (learning how to github)
-
adrianhudson
- Posts: 169
- Joined: 30 Apr 2022
- Location: Devon. UK
- Contact:
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
Hello Mike,
Thanks for your reply.
However, I really haven't got as far as thinking about output formats yet! After kernelthread's fantastic reply I have coded the fractional part of the output but without thinking about efficiency yet!
Ideally I suppose I want a simple fixed length output with a floating minus sign and leading zero
blanking. Nothing fancy. So, -1 would be " -1.000", 3.142 would be " 3.142". The thermometer can output from -55C to +125C and I intend to use it with 12 bit mode so it outputs up to 4 places of decimals after conversion - I will probably round to 3dp.
Thanks for your reply.
However, I really haven't got as far as thinking about output formats yet! After kernelthread's fantastic reply I have coded the fractional part of the output but without thinking about efficiency yet!
Ideally I suppose I want a simple fixed length output with a floating minus sign and leading zero
blanking. Nothing fancy. So, -1 would be " -1.000", 3.142 would be " 3.142". The thermometer can output from -55C to +125C and I intend to use it with 12 bit mode so it outputs up to 4 places of decimals after conversion - I will probably round to 3dp.
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
Let me be the first one to say: Wow! 1-Wire on a 6502 - neat!
I've done lots with 1-wire stuff but never on a 6502... Interesting concept but the timings should be easy to achieve - which I guess you've done.
Cheers,
-Gordon
I've done lots with 1-wire stuff but never on a 6502... Interesting concept but the timings should be easy to achieve - which I guess you've done.
Cheers,
-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
-
adrianhudson
- Posts: 169
- Joined: 30 Apr 2022
- Location: Devon. UK
- Contact:
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
Well, I can't take all the credit for the 1-wire code. There is (old) code on here (for the DS1820) that I borrowed. Unfortunately it didn't work with the DS15B20 - the newer device seems to conform more strictly to the 1-wire specs - so I fixed it. Now I need some other 1-wire devices to hook up - any suggestions? 
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
May I ask where I might find the old DS1820 code you mentioned, please?
-
adrianhudson
- Posts: 169
- Joined: 30 Apr 2022
- Location: Devon. UK
- Contact:
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
Michael wrote:
May I ask where I might find the old DS1820 code you mentioned, please?
http://6502.org/mini-projects/ds1820/ds1820.htm
Re: DS18B20 - 16bit sig-extended twos complement to ASCII co
Thank you.
I've used DS18x20 temperature sensors in several different PIC microcontroller projects in the past. It's an interesting device and protocol. Instead of using a 256 byte 'CRC' table or a separate routine to perform the 'scratchpad' CRC test, I built a cumulative bit-level CRC calc' into my One Wire read/write bit routine that performs the calculation on-the-fly within each 60-microsecond read/write bit 'slot' which pretty much eliminates CRC calculation overhead. If anyone is interested, here's a couple excerpts (apologies -- PIC Assembly code);
I've used DS18x20 temperature sensors in several different PIC microcontroller projects in the past. It's an interesting device and protocol. Instead of using a 256 byte 'CRC' table or a separate routine to perform the 'scratchpad' CRC test, I built a cumulative bit-level CRC calc' into my One Wire read/write bit routine that performs the calculation on-the-fly within each 60-microsecond read/write bit 'slot' which pretty much eliminates CRC calculation overhead. If anyone is interested, here's a couple excerpts (apologies -- PIC Assembly code);
Code: Select all
/* *
* use remaining r/w 'slot' time for cumulative bit level CRC calc *
* using data in Carry status bit *
* */
//asm clrf _wreg // wreg already 0 (see above)
asm rlf _wreg,W // save C in wreg (0x00 or 0x01)
asm xorwf _crc,F // xor b0 bits, result in 'crc'
asm rrf _crc,F // is xor result 0 (C=0)?
asm skpnc // yes, skip, else
asm iorlw 0x18 // wreg = x8+x5+x4+1 poly and b0 bit
asm rrf _wreg,W // restore C (wreg = 0x8C or 0x00)
asm xorwf _crc,F // apply the polynomial, or not
//asm movlb owtris // bank 1 (inserted by compiler)
asm bsf owtris,owpin // set owpin to hi-z '1' @ 61-usecs
//intcon.GIE = 1; // interrupts on
} //
Code: Select all
/******************************************************************
* main loop *
******************************************************************/
while(1) //
{ owreset(); // reset one-wire devices
owrw(OwSkipRom); // send "skip rom" command
owrw(OwConvert); // start temperature conversion
delay_ms(2); // wait for conversion to complete
lastdiscrep = 0; // start new search
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
do // repeat for each sensor
{ u08 i = 0; //
owsearch(); // put first/next ROMID in owbuff[]
owreset(); // reset one-wire devices
owrw(OwMatchRom); // send "match rom" command
do // send & print 64-bit rom id
{ putHex(owrw(owbuff[i++]));
} while(i < 8); // 8 bytes
/* *
* read temperature and 'count_remain' bytes from the DS18x20 *
* scratchpad memory (optionally print the CRC8 result). *
* */
owrw(OwScratch); // send "read scratchpad" command
//crc = 0; // reset 'crc' variable
rawtemplo = owrd(); // read temperature lo byte
rawtemphi = owrd(); // read temperature hi byte
owrd(); owrd(); // dummy scratchpad reads
owrd(); owrd(); // dummy scratchpad reads
frac = 16 - owrd(); // frac = 16 - 'count_remain'
//owrd(); owrd(); // last scratch byte & crc byte
//put232(" CRC="); // print scratchpad CRC8 result
//putHex(crc); // should be "00" (no error)
put232(' '); //
/* *
* expand DS18S20 9-bit temperature value (1/2° resolution) *
* to DS18B20 12-bit format (1/16th° resolution). *
* */
if(familyid == 0x10) // if DS1820 or DS18S20
{ rawtemp16.0 = 0; // clear the 0.5° bit
rawtemp16 <<= 3; // make room for fraction bits
rawtemp16 |= frac; // frac = (16 - 'count_remain')
//rawtemp16 -= 4; // subtract 1/4° (per datasheet)
}