   Aedan Chief Systems Administrator Join Date: September 2001 Location: Europe Posts: 13,075 Analog to digital with a varying reference!

Ok, I've been working on a small circuit that measures various different voltages (basically a gyro and the speed of some motors), but I've got a small problem that I'm not 100% sure of a good way of solving.

The ADC is using the battery voltage as it's reference (It's ratiometric). However, the gyro isn't - the output voltage doesn't change as the battery voltage changes.

The good news is that I have a 1.6V reference that I can sample, so at least I have a known reference. Now, if I understand this correctly, I can measure the battery voltage by seeing what output I get from 1.6V reference. It would seem that the Bv = 410/ADC_result.

Now, I'm doing all this in assembler, and I don't have a good grip on integer maths for multiplying and dividing.

How do I convert these variable measurement back into a fixed value - effectively compensating for the changing battery voltage?
__________________  Gizmo  Chief BBS Administrator  What chip are you using? I assume it's a PIC of some flavor?

There's no external vref pin for the ADC; its only reference is the battery supply?

Where does the 1.6v come from? Also, is the 410 the sample value you get when reading the 1.6v reference?

How many bits is the ADC? I'm assuming it's linear? What's the input range? Aedan Chief Systems Administrator Join Date: September 2001 Location: Europe Posts: 13,075
It is indeed a PIC of some flavour (12F615 - an 8 pin device). Whilst there can be an external VREF, it is multiplexed with another pin, and I need the other pin functionality, otherwise I need to change the PIC I'm using.

The PIC generates two internal references, 0.6V and 1.6V, and I can set the ADC multiplexer to select one of these references, or one of the external pins. Technically, the ADC is 10bit linear, but I was only planning on using 8 bits of resolution. The input range between VDD and VSS.

The output from measuring the 1.6V reference is going to depend on the battery voltage, as it is the reference. From this, the battery voltage (Bv) is related to the reference via:
256/Bv * 1.6 = Res

Rearranging this gives me:

Bv = 410/Res

Where Bv is battery voltage, and Res is the result from the ADC when measuring the 1.6V reference voltage.
__________________  Gizmo  Chief BBS Administrator  Err.....unless you are reading a different reference manual than I am, the PIC generates an internal 1.2v reference, not 1.6v.

You're going to have to do something interesting, because the PIC doesn't support multiply and divide operations directly. Fortunately, it DOES support subtraction, so you don't have to do a bunch of two's complement crap to implement subtraction as a series of additions.

Basically, you're dealing with a fixed point precision problem. You're going to have to scale the numbers up (probably multiply by 16 or something) then do your math and shift your decimal point as appropriate.

I wrote some code a long time ago to do exactly this sort of thing on the 6502. It's not particularly difficult, just tedious. Scaling by an even binary value (like 16) is what I would suggest, simply because that's an easy rotate-left 4 times, which is very simple and fast. However, that still means you've got to do the multiplication and division using successive addition and subtraction operations.

Last edited by Gizmo; 3rd February, 2010 at 06:16 PM. Aedan Chief Systems Administrator Join Date: September 2001 Location: Europe Posts: 13,075
That's what you get for mixing 1.2 and 0.6 together. Are there any good references on fixed point to get my head around how some of these things work?
__________________  Gizmo  Chief BBS Administrator  Well basically, when you are dealing with fixed point math on an architecture that only supports integer operations, you simply shift the decimal point so that you can do everything in the integer domain.

First, the equation needs to change to reflect 1.2v rather than 1.6:

256/Bv * 1.2 = Res

Solving for Bv:

Bv = 307.2/Res

Multiply by 10 to make things easier later, and let us retain some accuracy:

Bv * 10 = 3072/Res

Do the math, and remember that the result is 10 times bigger.

As for doing the math itself, I'm sure you remember from primary-school math that multiplication is just a short-hand for successive additions, e.g.

6 * 6 = 36

is the same as

0 + 6 + 6 + 6 + 6 + 6 + 6 = 36

Division is the inverse:

36 / 6 = 6

Is the same as

36 - 6 - 6 - 6 - 6 - 6 - 6 = 0

For a machine that only knows how to do addition and subtraction, you have to manually implement the operations necessary to do multiplication and division.

(Side note: anyone know how to do subtraction on a machine that only supports addition? Hint: It requires a fixed register, i.e. number size, and an operation that I mentioned in a previous post)

Turns out, though, that you don't have to be quite that pedantic about it. ROR and ROL instructions (Rotate register right, rotate register left) have the effect of multiplying or dividing a number by 2. It's the binary equivalent of shifting the decimal point and thus allows you to implement the algorithmic equivalent of long multiplication and division.

Given two numbers:
Let A be the Multiplicand
Let B be the Multiplier
Let C be the Product of A and B
(Note: the product of two 8-bit numbers can be up to 16 bits in size, so A and B are constrained to 8 bits, and C must be implemented as 16 bits. For 8-bit oriented architectures, this means you have to do a lot of shifting)

Set C to 0.
Begin
Test the LSB of B. If it is 1, add the contents of A to the high order byte of C (remember, C is a 16-bit register). Finally, ROR C.

If the LSB is 0, simply ROR C (To implement this with an 8-bit architecture, you first clear the Carry flag, ROR through Carry on the high byte, then ROR through Carry on the low byte. Finally, test the Carry flag and if it's set you've had an overlow, so bail with an error.)

ROR B, rinse and repeat until you've run the loop 8 times (for an 8-bit multiply). When you're done, C will contain the 16-bit product.

(Note: this architecture supports the bit test operation allowing you to test any bit in the byte, but does not support directly testing the carry flag. Some architectures do not support testing a bit in the byte, but do support directly testing the carry flag. As a result, you'll have to adjust the code accordingly.)

Division follows a similar operation, but as your basic shift-and-subtract algorithm, and looks like this:

Given two numbers:
Let C be the 16-bit Dividend
Let B be the Divisor
Let A be the quotient

Set A to 0
If B is 0 the result is undefined, so bail with an error.
Begin
Clear Carry
ROR through Carry A.
Test Carry: if set, you've had an underflow. Signal error and bail.
ROL through carry the 16 bits of C.
Test high-order byte of C, if equal or greater than B, subtract B from C (C - B), and set High order bit of A.

Rinse and repeat 8 times (for an 8-bit subtraction). When you're done, whatever's left in C is your remainder and A is your quotient.

Note: on the PIC, there is no specific comparison operation, but the subtraction operation has the same effect: subtract the two numbers you want to compare (C - B): if the carry flag is set B is larger; it the zero flag is set, they are equal; otherwise C is larger.

I would bet if you look around, there is probably a math library for the PIC you can use that already does this stuff, and more besides.

Edit: Here's one example: http://www.piclist.com/techref/microchip/math/index.htm

Last edited by Gizmo; 4th February, 2010 at 04:26 AM. Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 Thread Tools Show Printable Version Email this Page Rate This Thread Rate This Thread: 5 : Excellent 4 : Good 3 : Average 2 : Bad 1 : Terrible Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is Off HTML code is OffTrackbacks are On Pingbacks are On Refbacks are On Forum Rules Similar Threads Thread Thread Starter Forum Replies Last Post cloasters General Hardware Discussion 3 11th January, 2009 11:00 PM booman Graphics and Sound cards; Speakers and other Peripherals 8 4th April, 2007 04:59 PM MONKEYMAN Hardware Hacking 18 16th December, 2005 03:03 AM lplate80 Random Nonsense! 3 10th July, 2003 12:19 PM bigmouse EPoX MotherBoards 7 15th February, 2003 09:51 PM

All times are GMT +1. The time now is 06:11 AM.

 -- Mobile ---- iPhone and Palm Pre -- AOA Red/Gray ---- AOA Neutral ---- AOA Blue/Gray -- English (British) -- English (US) Contact Us - AOA Front Page - Privacy Statement - Terms of Service - Top Copyright ©2001 - 2010, AOA Forums