Two's Compliment to Normal Dec
TJHJ
Posts: 243
So I am receiving a number that is stored in two's complement, with a signed 1st bit, 12bits of data, stored in a 16 bit register. How do I get this back to a normal dec number so I can use it, It is incrementing 15.625 uv per increment. I am thinking that if I can get this back to dec format, than I would be able to read the voltage value in thousandths of uv by simply multiplying by 15625. But I cant seem to get it into the propeller 32bit math system and get something that makes sense.
The value is stored in a register like so.
Sign, 12 bits, X, X, X for the 16 bit system.
Its received in two 8 bit registers.
S 7 Bits.
5 bits, 3 Dead spaces.
So how do I get this back to a normal number that can be used.
TJ
The value is stored in a register like so.
Sign, 12 bits, X, X, X for the 16 bit system.
Its received in two 8 bit registers.
S 7 Bits.
5 bits, 3 Dead spaces.
So how do I get this back to a normal number that can be used.
TJ
Comments
concaternate the 2 getting rid of the 3 dead bits
no := (first << 5) + (second >> 3)
shift the sign bit to bit 31 and then sign extend back to bit 13
no := (no << (32-13)) ~> (32-13)
You combine both parts, I assume they only contain 8 bit values, if not... you have to add some "and" guarding
You shift left bit 12 to position 31 so it is used as sign and the instruction abs will take the absolute value, and a second shift this time right will reposition the significant digits where they have to be.
If you know that _all_ your variables are two's complemented, you can instead of abs neg, but there is no time or size advantage in this case.
Post Edited (Ale) : 8/13/2008 6:40:39 AM GMT
15.625uV increments? Sounds like you're reading a fuel gauge chip. I've used successfully the DS2760 and here's the code (in C) to deal with 2's-complements and extract the current value:
//msb: [noparse][[/noparse]SDDDDDDD] S=signed bit, D=data
//lsb: [noparse][[/noparse]DDDDDXXX] D=data X=ignore
write_byte (0x0E); //point to current register msb @ $0E
msb == reab_byte(); //read msb from register
lsb == reab_byte() & 0xF8; //read lsb and mask off lower 3 bits
temp = msb<<8 + lsb; //merge values
if ((msb & 0x80) == 0x80); //if sign bit is set
temp = temp - 65536; //substract to get rid of 2's-complement
//current equation: current = (Number_of_increments * uV) / Sense_resistor
//(temp * 15.625 x 10^-6 Volts) / 20 x 10^-3 Ohms sense resistor = current in mA
current = ((temp>>3) * 0.000015625) / 0.020;
Hope this help. If you do use a fuel gauge, I've stopped using the Coulomb counting approach (as the 15.625 uV would suggest you're using) for the Open-Circuit Voltage (OCV) method, which is light-years simpler to implement in LiPo fuel-gauging as you don't need to know any of the battery parameters (try finding these half-a-dozen or so parameters for a LiPo bought at SparkFun and coming from China...). The chip I currently use is DS2786 (Digikey DS2786G+-ND). It's an I2C chip, requiring very minimal external parts, and a best-fit universal battery profile is already in the chip's eeprom. Only drawback is the TDFN-10 package, but it's easier to solder than it looks (dots of solder paste & frying pan method works very well, just make the landing pads somewhat longer).
Cheers,
Alex
Does this work in a local variable? Arn't they word sized?
Is it really that simple all I need to do is subtract 65536, the maxium size for a word variable? If so wow I am way over thinking this.
Thanks
TJ
The way to look at this is
1. +ve numbers need to have 0s filling the bits you dont care about
2. -ve numbers need to have 1s filling the bits you dont care about
so no << (32-13) shifts your sign bit to bit 31 which is the real long sign bit.
~> (32-13) shifts them back copying bit 31 to the new bit 31. So this gives you the correct response in both cases. i.e. fill with 0 is +ve and fill with 1 if -ve
Any other way to do the same thing works. so testing the sign bit then - 65535 from a +ve number that is less than 32767 will give the same effect.
The other thing to look at are the spin operators ~ and ~~, ~~x will sign extend from bit 15, i.e. sign extend a work to a long. ~x will sign extend a byte to a long. ~~x is the same as x:= (x<<16)~>16 and ~x is the same as x:=(x<<24)~>24
Post Edited (Timmoore) : 8/13/2008 4:55:23 PM GMT
I hooked up a pot to test it and see if it was ranging / working correctly. With the pot at 0, almost ground I get a range of -700 ish, it jumps pretty fast. Then as I move towards positive around 3600 it jumps to 4095. Any Ideas what I am looking at? A hardware or a decode issue?
When the display is around 0, the pot is showing +8.1mv.
·
I ended up having to use the ! to flip it to positive so it would still read a negative value, versus the abs command. Otherwise it would scale backwards.
·
Here is the code I am using to read it.
edit* Test using sign extend.
Post Edited (TJHJ) : 8/13/2008 10:16:47 PM GMT
I might be completely wrong, so don't be offended if I am way out, but here's a few comments:
1. If you have only one 1-wire chip on a network, you don't need to perform a match_rom ($55) each time.
Just issue a reset cmd, followed by the skip_search ($CC) immediately followed by read_scratchpad ($BE).
2. From the datasheet for the DS1822, the way to read the registers are reverse from what you do:
The LSB seem to be first then MSB follows at the next onewire.read (page 11 of ds)
Here's a way that should work:
First, issue the conversion command sequence:
onewire.reset 'reset command
onewire.writeByte($CC) 'skip_rom command
onewire.writeByte($44) 'convert temperature command
'at this point, you MUST wait at least 750ms for the 12-bit resolution [noparse][[/noparse]Tconv]
conversion to happen (see pages 4 & 20 of ds). In the posted code you don't seem
to wait at all.
then, issue the reading sequence:
onewire.reset 'reset command
onewire.writeByte($CC) 'skip_rom command
onewire.writeByte($BE) 'read_scratchpad command
The LSB is read first, followed by the MSB (page 4):
lsb:= onewire.readByte ' read temperature LSB
msb :=onewire.readByte ' read temperature MSB
temp := (((~msb) << 5) + (lsb >> 3)) ' as from Timmoore
I don't have the chip so I can't test it but this should work. Good luck.
BTW, you mentioned the need to work with increments of 15.625 uV. I don't see where in your code
you use it nor why you need it since the chip returns the temperature in increments of 0.0625 degree C
(at 12-bit resolution) directly from the register you read. Try it with sample data shown at page 4: 85dec
should read $550 (1360dec), which multiplied by 0.0625 (12-bit res) gives... 85 deg C. Also, I doubt it is
your default temperature as suggested (it's pretty hot!): 85C is only at power-on; following a proper setup
you should read room temperature, which should give you about $191 (25C, as per ds).
Cheers,
Alex
·
What makes this very confusing is the DS2762 without an internal sense resistor, The current register reads voltage in 15.625uv, Figure 4. on the datasheet, Stored in locations MSB = 0E(h) and LSB = 0F(h). This is the voltage applied to the SNS pins.
·
If I can get this into a Dec format that each step is 15.625uv, I can use my lookup table that I made for type k, from 0deg C up to 1400Deg C. And is in thousandth of uv resolution, So then I can take the Decimal number multiply by 15625, run my lookup get the position in the table and· know Deg C of the thermocouple.
·
Right now it is just a repeating loop to a VGA out, looking up each chip. Printing it to the screen and then waiting at the end to give time for the measurement to occur again.
·
·
Under the final setup, I plan to use each ds2762 on its own pin to allow me to physically know which sensor is where. So then I plan to use the skip Match Rom command. Right now I have them all tied on one wire, so I can get an idea if they are all reading the same then I know something is going my way.
I am completely lost now:
Not reading temperature? What all your postings are about then? Which chip do you really use? the DS1822 (with thermocouple type k) as indicated in your code snippet Posted Today 9:01 AM (GMT -7) or the DS2762 that you NEVER EVER indicated anywhere before on this thread (in which case you DO refer to a LiPo battery fuel-gauge as per my first reply to you)? Perhaps it's not just me that is lost.
Also, why don't you try debugging 1 chip at a time? DS1822 is VERY simple, elementary even. Once mastered, you can use 1-wire protocols on more of the same chip in a network or more complex chips. DS2762 is a REAL pain to deal with if you don't have a clear idea of what you're doing. Unless you use this chip for the most basic function, it is really intended for fuel-gauge/Battery monitoring applications, in which case you will need to write and implement a *complex* piece of software on your processor-side. Believe me.
As for the DS2762, the chip is intended for 1 LiPo battery. How many batteries are you monitoring? The chip offers the option of an internal sense resistor and an external sense resistor. Which option are you using? There's no thermocouple there to address...
Finally, if you intend to use the DS2762 to monitor a LiPo battery in an application where you developped your own charger, be aware that you better double-check what you're doing as a mistake can lead the battery to explode. And its ugly.
Cheers,
Alex
http://www.parallax.com/Store/Sensors/TemperatureHumidity/tabid/174/CategoryID/49/List/0/Level/a/ProductID/96/Default.aspx?SortField=ProductName%2cProductName
The only catch is the ds2762 is the replacement for the ds2760. Same chip basically. But yes it is a lipo charger chip, but it is also so perfect for reading a thermocouple. This is not really a Type K reading chip, but using the current input to sense voltage in the external resistor configuration, with the thermocouple acting as my resistor. The +-64mv range is ideal.
I can get to any register I want, read the·Chip tempature just·fine, all through 1-wire. But when I read this voltage register, everything·gets screwy on me.·Sorry, I asumed my problem was in how I was dealing with the two's comp, and the MSB vs LSB. ·
Hope this clears up what is going on here.