|
Programming and Assembly Language Please read this Topic's rules!! |
![]() |
| LinkBack | Thread Tools | Rate Thread |
| |||
![]() 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 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. |
| ||||
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. So, multiplication is your basic add-and-shift 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 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 | |
Rate This Thread | |
| |
![]() | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Set top digital to analog boxes--with 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 |