Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 02:53 18 Sep 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM2(+): MMA8451 Triple-Axis Accelerometer

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10406
Posted: 07:55am 15 Nov 2015
Copy link to clipboard 
Print this post

The MMA8451 is a MEMS triple-axis accelerometer.

It is quite a sophisticated device but gives very good and stable output.

This code shows how to set up the accelerometer and then uses the chip's Data-Ready interrupt to trigger the conversion code.

The code outputs the raw acceleration data (in G) in the x, y and z dimensions and uses the chips orientation capability to output it orientation in text. Finally it uses some math to output the pitch and roll angles allowing for use as a digital level etc.

  Quote  
option explicit
option default none
'
' Program to demonstrate the use of the MMA8451 3-axis accelerometer
'
const MMA8451_addr = &H1C 'use if A0 pulled low
'const MMA8451_addr = &H1D 'use if A0 pulled high
const MMA8451_REG_OUT_X_MSB = &H01
const MMA8451_REG_SYSMOD = &H0B
const MMA8451_REG_WHOAMI = &H0D
const MMA8451_REG_XYZ_DATA_CFG = &H0E
const MMA8451_REG_PL_STATUS = &H10
const MMA8451_REG_PL_CFG = &H11
const MMA8451_REG_CTRL_REG1 = &H2A
const MMA8451_REG_CTRL_REG2 = &H2B
const MMA8451_REG_CTRL_REG4 = &H2D
const MMA8451_REG_CTRL_REG5 = &H2E

const MMA8451_PL_PUF = 0
const MMA8451_PL_PUB = 1
const MMA8451_PL_PDF = 2
const MMA8451_PL_PDB = 3
const MMA8451_PL_LRF = 4
const MMA8451_PL_LRB = 5
const MMA8451_PL_LLF = 6
const MMA8451_PL_LLB = 7

const MMA8451_RANGE_8_G = &B10 ' +/- 8g
const MMA8451_RANGE_4_G = &B01 ' +/- 4g
const MMA8451_RANGE_2_G = &B00 ' +/- 2g (default value)

'Used with register =&H2A (MMA8451_REG_CTRL_REG1) to set bandwidth
const MMA8451_DATARATE_800_HZ = &B000000 ' 800Hz
const MMA8451_DATARATE_400_HZ = &B001000 ' 400Hz
const MMA8451_DATARATE_200_HZ = &B010000 ' 200Hz
const MMA8451_DATARATE_100_HZ = &B011000 ' 100Hz
const MMA8451_DATARATE_50_HZ = &B100000 ' 50Hz
const MMA8451_DATARATE_12_5HZ = &B101000 ' 12.5Hz
const MMA8451_DATARATE_6_25HZ = &B110000 ' 6.25Hz
const MMA8451_DATARATE_1_56HZ = &B111000 ' 1.56Hz
const MMA8451_low_noise = &B100
const MMA8451_fast_read = &B10
const MMA8451_active = &B1
'
const int1_pin=35 'pin connected to the INT1 output of the MMA8451

cpu 48
setpin int1_pin,INTL,MMA8451_convert 'set an interrupt when dataready goes low
MMA8451_setup(MMA8451_RANGE_2_G, MMA8451_DATARATE_1_56HZ)
do
loop
'
sub MMA8451_convert
local x_g!,y_g!,z_g!,orientation%,roll!,pitch!
MMA8451_read(x_g!,y_g!,z_g!,orientation%) 'reading the data clears the interrupt
print x_g!,y_g!,z_g!," ";
roll! = (atan2(-y_g!, z_g!)*180.0)/PI
pitch! = (atan2(x_g!, sqr(y_g!*y_g! + z_g!*z_g!))*180.0)/PI
print pitch!,roll!," ";
if orientation%=MMA8451_PL_PUF then print "Portrait/Up/Front"
if orientation%=MMA8451_PL_PUB then print "Portrait/Up/Back"
if orientation%=MMA8451_PL_PDF then print "Portrait/Down/Front"
if orientation%=MMA8451_PL_PDB then print "Portrait/Down/Back"
if orientation%=MMA8451_PL_LRF then print "Landscape/Right/Front"
if orientation%=MMA8451_PL_LRB then print "Landscape/Right/Back"
if orientation%=MMA8451_PL_LLF then print "Landscape/Left/Front"
if orientation%=MMA8451_PL_LLB then print "Landscape/Left/Back"
end sub
'
sub MMA8451_setup(max_g%,sample_rate%)
local reg1%
i2c open 400,1000
if check_connection() then 'execute if device is found
print "MMA8541 found"
writeRegister8(MMA8451_REG_CTRL_REG2, &H40)
do
loop while (readRegister8(MMA8451_REG_CTRL_REG2) AND &H40))
Print "MMA8541 reset"
' enable 4G range
writeRegister8(MMA8451_REG_XYZ_DATA_CFG, max_g%)
writeRegister8(MMA8451_REG_CTRL_REG2, &H02)

writeRegister8(MMA8451_REG_CTRL_REG4, &H01)
writeRegister8(MMA8451_REG_CTRL_REG5, &H01) 'enable data ready interrupt on INT1

' Turn on orientation config
writeRegister8(MMA8451_REG_PL_CFG, &H40)

' Activate!
writeRegister8(MMA8451_REG_CTRL_REG1, sample_rate% OR MMA8451_low_noise OR MMA8451_active) '
endif
end sub
'
sub MMA8451_read(x!,y!,z!,o%)
local i2cin$ length 10,r%,div%,xx%,yy%,zz%
i2c write MMA8451_addr,1,1,MMA8451_REG_OUT_X_MSB
i2c read MMA8451_addr,0,6,i2cin$
o%=readRegister8(MMA8451_REG_PL_STATUS) AND &H07
xx%= intconv(mid$(i2cin$,1,2),1) \ 4 'convert signed two byte number
yy%= intconv(mid$(i2cin$,3,2),1) \ 4
zz%= intconv(mid$(i2cin$,5,2),1) \ 4
r%=getRange()
if (r% = MMA8451_RANGE_8_G) then div% = 1024
if (r% = MMA8451_RANGE_4_G) then div% = 2048
if (r% = MMA8451_RANGE_2_G) then div% = 4096
x!=xx% / div%
y!=yy% / div%
z!=zz% / div%

end sub

function check_connection() as integer
local r%
r%=readRegister8(MMA8451_REG_WHOAMI)
if r%=&H1A then
check_connection=1
else
check_connection=0
endif
end FUNCTION
'
function getRange() as integer
local r%
getRange=readRegister8(MMA8451_REG_XYZ_DATA_CFG) AND 3
end FUNCTION
'
sub writeRegister8(reg%,value%)
i2c write MMA8451_addr,0,2,reg%,value%
end sub
'
function readRegister8(reg%) as integer
local r%
i2c write MMA8451_addr,1,1,reg%
i2c read MMA8451_addr,0,1,r%
readRegister8=r%
end function
'
FUNCTION atan2(y!,x!) as float
local float arctan
IF ABS(x!) < 0.0000001 THEN
arctan = 0
x! = 0
ELSE
arctan = ATN(y!/x!)
ENDIF
IF x! > 0 THEN
atan2 = arctan
ELSEIF y!>=0 AND x!<0 THEN
atan2 = PI + arctan
ELSEIF y!< 0 AND x!<0 THEN
atan2 = arctan - PI
ELSEIF y!> 0 AND x!=0 THEN
atan2 = PI / 2
ELSE ' y< 0 and x=0
atan2 = PI / -2
ENDIF
END FUNCTION
'
CFunction intconv 'converts bytes in char array to integer with optional sign extend
00000000
27bdfff8 00001021 00001821 afa20000 afa30004 90880000 1900000b 01003821
2503ffff 03a31821 24020001 00823021 90c60000 a0660000 24420001 00e2302a
10c0fffa 2463ffff 8ca20000 1040000d 03a81021 9042ffff 30420080 10400009
29020008 10400007 03a81021 27a40008 2403ffff a0430000 24420001 5444fffe
a0430000 8fa20000 8fa30004 03e00008 27bd0008
End CFunction
 
twofingers

Guru

Joined: 02/06/2014
Location: Germany
Posts: 1629
Posted: 10:11am 15 Nov 2015
Copy link to clipboard 
Print this post

Hi Peter,

it is always a pleasure to read your code - clean and
straight -, thanks!

I wanted already since long time to play with my acceleration module.
Maybe your code (or parts of it) will fit. Even more interesting seems a
combinated compass/accelerometer module (like GY-511).
Anyhow, thanks for contributing!

Do you like to share your C-code source also, please?

Regards
MichaelEdited by twofingers 2015-11-16
causality ≠ correlation ≠ coincidence
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10406
Posted: 11:57am 15 Nov 2015
Copy link to clipboard 
Print this post

  Quote  Do you like to share your C-code source also, please?


unsigned long long intconv(unsigned char innumber[],unsigned int *signednum){//Cfunction
int k,j;
union utype{
unsigned long long b;
unsigned char a[8];
}u;
u.b=0;
j=innumber[0];//get the number of bytes
for(k=1;k<=innumber[0];k++)u.a[j-k] =innumber[k];
if (*signednum){k=u.a[j-1] & 0x80;//get the top bit
if(k){
for( ;j<=7;j++)u.a[j]=0xFF;//sign extend
}
}
return u.b;
}
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2948
Posted: 08:56pm 15 Nov 2015
Copy link to clipboard 
Print this post

Your timing is amazing. Today I am writing code for a MMA8452 so I immediately wonder if these two chips are 'compatible' in terms of code!

All I have done so far is connected it up and got a 'I'm here' response. Your code has hopefully saved me some time once again

I haven't even Googled yet - but do you know if the MMA8451 and MMA8452 are like-for-like in terms of code?

WW
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2948
Posted: 10:37pm 15 Nov 2015
Copy link to clipboard 
Print this post

Just tried your code on the MMa8452.

I had to change the value of the response of WHO_AM_I from &h1A to &h2A, but now getting some data.
Need to convert output string (due to orientation of chip in enclosure), but otherwise looks good!

Thanks for posting this code - saved a few hours by the look of things!

WW
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10406
Posted: 11:18pm 15 Nov 2015
Copy link to clipboard 
Print this post

Glad it works.

Do you get an acceleration of approximately 1 in the z direction when the chip is flat?

The 8452 is 12-bit, the 8451 is 14-bit. If the z-value is either 4 or 0.25 then change the divide ratio as applicable in these statements:

xx%= intconv(mid$(i2cin$,1,2),1) \ 4 'convert signed two byte number
yy%= intconv(mid$(i2cin$,3,2),1) \ 4
zz%= intconv(mid$(i2cin$,5,2),1) \ 4
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2948
Posted: 11:45pm 15 Nov 2015
Copy link to clipboard 
Print this post

  matherp said   Do you get an acceleration of approximately 1 in the z direction when the chip is flat?


Yes, I get near perfect values for X, Y, and Z (i.e 1 or -1) depending on orientation with no need to modify the division. Will examine your Pitch & Roll next.

The one thing I am wanting to 'configure' is INT2 as a movement trigger. Am working my way through the data sheet (for both the 100th time) to see exactly how to set up all the necessary thresholds and configurations.

Your code has giving me a great head-start; thanks once again for posting this in such a timely manner

WW
 
twofingers

Guru

Joined: 02/06/2014
Location: Germany
Posts: 1629
Posted: 04:09am 16 Nov 2015
Copy link to clipboard 
Print this post

@Peter,

thanks a lot for your code, greatly appreciated!

Michael
causality ≠ correlation ≠ coincidence
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025