
Programming and Assembly Language Please read this Topic's rules!! 
 LinkBack  Thread Tools  Rate Thread 
 
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?
__________________ 
 
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.
__________________ 
 
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 rotateleft 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. 
 
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 primaryschool math that multiplication is just a shorthand 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. So, multiplication is your basic addandshift algorithm and looks like this: 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 8bit 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 8bit 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 16bit register). Finally, ROR C. If the LSB is 0, simply ROR C (To implement this with an 8bit 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 8bit multiply). When you're done, C will contain the 16bit 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 shiftandsubtract algorithm, and looks like this: Given two numbers: Let C be the 16bit 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 highorder 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 8bit 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  
Rate This Thread  
 
Similar Threads  
Thread  Thread Starter  Forum  Replies  Last Post 
Set top digital to analog boxeswith cabling?  cloasters  General Hardware Discussion  3  11th January, 2009 11:00 PM 
Digital speakers to analog  booman  Graphics and Sound cards; Speakers and other Peripherals  8  4th April, 2007 04:59 PM 
Vdimm/Vdd reference points.  MONKEYMAN  Hardware Hacking  18  16th December, 2005 03:03 AM 
ISO/OSI Reference Model  lplate80  Random Nonsense!  3  10th July, 2003 12:19 PM 
digital vs analog audio output from 8rda+  bigmouse  EPoX MotherBoards  7  15th February, 2003 09:51 PM 