Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Need some help with assembly floating point division

Status
Not open for further replies.
I was able to get my LGA-14 accelerometers from Freescale up and running on a board I made. I have verified that it's good with a multimeter on the analog outputs. Now, of course, I need to get this going with my PIC to display the G force on an LCD. Eventually I'd like to do some trig functions to show angle of lean and what not.

For now I just want to show the g force on each axis on an LCD. I'm using PIC ASM on a a PIC16F1934 and I don't want a ridiculously long lookup table for the 255 measurements of the 8 bit LCD. I've done math to convert binary readings to decimal. That's not a problem. What is a problem is the fact that I need to do this math:
G force = (volts read - 1.4 volts) / 0.0836
G force = (8 bit ADC reading - 174) / 0.0836

FYI, 174 is roughly the value of the 8 bit ADC at 0 g (1.4 volts) on a 2.048 fixed voltage reference.

I only really need the accuracy to 1 or 2 decimal places.

I have no idea where to begin doing that in PIC ASM.

I tried DLing something from PIClist, but the file won't unzip.

Thanks!
 
Last edited:
hi,
Its possible by using 16,24 or 32 bit maths routines to calculate results that give a 'decimal' part.
The method is to multiply the decimal numbers by say 1000,10,000 or 100,000 to give the required 'integer' part.
Also multiply the other values in the equation by the same multiplier then evaluate the equation, convert to BCD and insert a decimal point in the appropriate position when displaying.

Do you follow that OK.?

In your 1st equation get the 1.4/0.0836 into a fixed constant, it will make the maths easier, likewise for the 174/0.0836.
 
Last edited:
Thanks for that. I think I follow all of it except for the part on converting to BCD. I guess I don't get where that is helpful.

In other news, my 2nd equation is WRONG. In fact, I'm having trouble modeling that relationship.

It is embarrassingly simple. 1.4 volts = 0 g. 12 volts reading both ways. 2.048 fixed voltage reference caps the highest reading at 7.751 positive G's. Resolution is 2.048/255 = .008301 roughly.

The best model I can come up with is off up to .4 g's at the extreme ends.
I'm trying to use this:
g force = (ADC reading - 174) * .09265.....(further decimals in spreadsheet)

.09265 is derived from divided 19.7751 by 255 and then dividing that by .836 which is a mv per mg.
 
2.048v - 1.400v = 0.648v
7.751 G = 0.648v
2.048v = 256 total ADC counts (that's what you said?)

so 7.751 G = 256 / 2.048 * 0.648
so 7.751 G = 81 adc counts

then each adc count = 7.751 G / 81 = 0.096 G

So if each adc count is 96 mG just zero your adc value (subtract the 1.4v) then multiply the remaining adc reading by 96.
The 16bit answer is in mG.

Code:
if(adc >= 174)     // if + G
{
  gpositive = 1;
  adc -= 174;      // subtract 1.4v to get reading in G
  g = (adc * 96);  // convert to G
}
else               // if - G
{
  gpositive = 0;
  adc = (174 - adc);  // subtract from 1.4v to get reading in G
  g = (adc * 96);  // convert to G
}
// g = result in mG; so 1248 = 1.248 G

The code above gives you a reading in mG and a sign digit to display.
 
Thanks for that. I think I follow all of it except for the part on converting to BCD. I guess I don't get where that is helpful.

hi,
Roman has broken down the equations quite nicely.

Ref the BCD comments, I guess you are going to display the results from the calculations.??
If yes, it will be necessary to convert the binary result to BCD/ASCII in order to drive the display.
When using assembler source code.
 
Last edited:
Thanks for the help on that guys. Perhaps I had been focusing on it for too long because my mind wasn't working. What I ended up doing was taking the reciprocal of the .09265 to get ~10.79 and then using that as a constant once I inflated it appropriately to get rid of the decimcal places. So I ended up taking the ADC reading, subtracting the 0 g reading point, multiplying that by 100, and then dividing by 1079.... errr, something along those lines because I'm not in front of my code right now.

What was wierd was that I had to trim the 0 g point in the code. It says plain as day in the datasheet that 1.4 Volts is the 0g point on any axis. 2.048/255*174 = 1.397, so I don't know why I had to use about 190 instead of 174 to reflect 1g when it was just sitting there, or turned such that any particular axis was in plane with the acceleration of gravity. That one kind of baffled me, but it could be that when I reflowed the board the accelero didn't end up perfectly in plane with the board.

What's also wierd is that each axis reads as expected (after trimming the 0 g point) individually, but when I try to read all three axis I show the same reading. I'm using a "MOVLW" and "MOVWF ADCON0" to select the channels, so I'm not sure why it would be doing this. At the top of the loop I am incrementing a file called "AXIS LOOP." Then the code tests for a one using subtraction and and bit test on the zerobit. If it's one, it sends it to read the X, if it's two, it reads the Y, if it's three it reads the Z and then the Z axis portion of the code clears the file to start it over again. Perhaps I just need to read up and see if there are any quirks with this PIC in terms of ADC channel selection.
 
Last edited:
It's reading the 1G of gravity. They do that. :)

That will take your 174 count up to about 185.

If you want to speed your code up, binary 16bit divisions are very slow. The system I showed used no divisions, just a 16bit multiply.
 
I'll have to look at doing that. Thanks for the advice.

My point was that my code takes the ADC reading and then subtracts 174. Thus, the difference should indicate the g force from 0 (after running it throug g/mV calculations). The problem that caused me to need to trim it was that it was reading 1.3g on the Z axis when laying flat on the table and -0.7g on the Z axis. Changing 174 up to the 190s or something like that brought it to 1g when flat and -1g when inverted.

The next step, after I finish dealing with the channel selection problems, will be displaying a degree of inclination from the the direction of acceleration (gravity) for each axis. I'm not sure where I am going to find a arc cosine routine.
 
Last edited:
Changing 174 up to the 190s or something like that brought it to 1g when flat and -1g when inverted.

Ahh I see. Well that sounds a little high but you can just put it down to "trimming" the sensor. They all need a bit of trimming to suit your adc.

Is the main goal of the device to measure angle? It's just with only 256 adc counts and a large range accelerometer you have quite poor resolution. At 0.096 G per adc count, you only get 1/0.096 = 10.4 adc counts to 1 G.

When measuring angle you will be going from 0G to 1G using 2 axes, so you will only get a very coarse reading of angle, with maybe 20 or 22 steps. You could forget the trig math processing and just use a 22 entry lookup table.

Of course if measuring angle is important you would be better off with an accelerometer with a smaller range (like a 1.5G version) and an adc resolution of 1024 adc counts.
 
Last edited:
I actually switched to 4g mode on this accelero for now. I'll actually be using all 3 axis to do the calculation of angle.

It was my understanding that the force vector, R, equals SqRt (Xg^2 + Yg^2 + Zg^2) and that the angle of inclination in respect to the direction of acceleration (gravity in this case) = arccos (Axis_g/R). If I remember right, the arc cosine is only good from 0 to 180 degrees so I'll have to keep track of whether the G on a particular axis is positive or negative. I think that the Z axis is really the most useful in determining the angle of inclination (Z points to the sky normally in my setup).

I'm not keen enough with math to know off the top of my head what that extra dimension will add to the 20 or 22 steps you were talking about with a 2 axis, but it seems like it would increase a great deal using 3 axis.

I guess I'll have to play with some possibilities in a spreadsheet to see how many different numbers can come about.

I saw something on spark fun forums where a guy is using accelerometers and servo's mounted to a motorcycle to keep a video camera flat with the horizon regardless of the lean angle of the bike. It makes for some very cool videos. I'd ultimately like to get there, but I'm not sure how to cancel out the centripetal force experienced by the unit goes through a turn quickly.
 
Status
Not open for further replies.

Latest threads

Back
Top