|
|
View previous topic :: View next topic |
Author |
Message |
Classic
Joined: 22 Aug 2011 Posts: 6 Location: Thailand
|
Accelerometer calibrate problem |
Posted: Tue Sep 13, 2011 12:12 pm |
|
|
Hi, I have a problem about accelerometer MMA7455L and PIC18F2620 with SPI 4 wire in measurement mode. When I showed in LCD at ground plane the results are "XYZ:255 243 78" what's happen?
What do you think? Thank you.
http://www.ccsinfo.com/forum/viewtopic.php?t=37562
http://cache.freescale.com/files/sensors/doc/app_note/AN3745.pdf
http://www.freescale.com/files/sensors/doc/app_note/AN3468.pdf
Code: | #include <18F2620.h>
#fuses HS,NOPROTECT,NOWDT,NOLVP
#use delay(clock=20000000)
#define use_portb_lcd
#include <lcd.c>
#define XOUT8 0x06
#define YOUT8 0x07
#define ZOUT8 0x08
#define STATUS 0x09
#define I2CAD 0x0D
#define MCTL 0x16
#define XOFFL 0x10 //16 Offset drift X value (LSB) (Read/Write)
#define XOFFH 0x11 //17 Offset drift X value (MSB) (Read/Write)
#define YOFFL 0x12 //18 Offset drift Y value (LSB) (Read/Write)
#define YOFFH 0x13 //19 Offset drift Y value (MSB) (Read/Write)
#define ZOFFL 0x14 //20 Offset drift Z value (LSB) (Read/Write)
#define ZOFFH 0x15 //21 Offset drift Z value (MSB) (Read/Write)
#define Acc_CS PIN_C2
#define DRDY PIN_C0
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
//******************************************
void Acc_init(void);
void Acc_wr(char reg, char dat);
signed char Acc_rd(char reg);
void Calibrate(char Gselect);
void Data_Ready();
//********************************
void Calibrate(char G_Select)
{
signed int offs_calib[3] ; //keep Value offset X,Y,Z for Calibrate reg.XOFFL-H,YOFFL-H,ZOFFL-H
signed int offs_ave[3] ; //keep Value offset X,Y,Z for Average
signed char offs_meas[3] ; //keep Value offset X,Y,Z for Measurment currunt
char cnt_run=0,res=0,m,n ;
for(m=0;m<3;m++)
offs_calib[m]=0 ; //Clear
Acc_wr(0x16,0x01|(G_Select<<2)) ; //Set up MMa7455L Mode:Measurement
while((cnt_run++ < 55)&& (res==0)) //Loop Calibrate Offset 55 time
{
for(m=0;m<3;m++)
offs_ave[m]=0 ; //Clear
for(m=0;m<4;m++) //Loop Filter Read data 4 time
{
Data_Ready() ; //Check INT1 Conver data Ready ?
offs_meas[0] = Acc_rd(0x06); //Read data Output 8 bit GX
offs_meas[1] = Acc_rd(0x07); //Read data Output 8 bit GY
offs_meas[2] = Acc_rd(0x08); //Read data Output 8 bit GZ
for(n=0;n<3;n++)
offs_ave[n] += offs_meas[n] ; //Total value GX,GY,GZ from reading 4 time
}
for(m=0;m<3;m++)
offs_ave[m] /= 4 ; //Calculate Average for GX,GY,GZ
if(G_Select == g_2) //---- If Select Calibrate Mode 2G (8bit) ----
offs_ave[2] -= 0x3F ; //sub value GZ by 63(0x3F) when Z-Axist =1G=63
if(G_Select == g_4) //---- If Select Calibrate Mode 4G (8bit)----
offs_ave[2] -= 0x1F ; //sub value GZ by 31(0x1F) when Z-Axist =1G=31
if(G_Select == g_8) //---- If Select Calibrate Mode 8G (8bit)----
offs_ave[2] -= 0x0F ; //sub value GZ by 15(0x0F) when Z-Axist =1G=15
for(m=0;m<3;m++)
{
if(offs_ave[m]==0) //Check Value Average GX,GY,GZ =0
res++ ;
}
if(res >= 3) //if Average GX and GY and GZ =0 Give res=1 Exit Loop While
{
res=1 ;
for(n=0;n<3;n++)
offs_ave[n] += 1 ;
}
else
res =0 ; //if Average GX and GY and GZ != 0 Give res=0 Return Read GX,GY,GZ
for(m=0;m<3;m++)
offs_calib[m] -= offs_ave[m] ;
Acc_wr(0x10,offs_cal[0]/256); //Write value Calibrate offset byte Low to Reg. XOFFL
Acc_wr(0x11,offs_cal[0]%256); //Write value Calibrate offset byte HGigh to Reg. XOFFH
Acc_wr(0x12,offs_cal[1]/256); //Write value Calibrate offset byte Low to Reg. YOFFL
Acc_wr(0x13,offs_cal[1]%256); //Write value Calibrate offset byte HGigh to Reg. YOFFH
Acc_wr(0x14,offs_cal[2]/256); //Write value Calibrate offset byte Low to Reg. ZOFFL
Acc_wr(0x15,offs_cal[2]%256); //Write value Calibrate offset byte HGigh to Reg. ZOFFH
}
}
//******************************************
void Acc_wr(char reg, char dat)
{
output_low(Acc_CS);
spi_write(((reg & 0x3F) << 1) | 0x80);
spi_write(dat);
output_high(Acc_CS);
}
//******************************************
signed char Acc_rd(char reg)
{
signed char dat;
output_low(ACC_CS);
spi_write((reg & 0x3F) << 1);
dat = spi_read(0);
output_high(ACC_CS);
return(dat);
}
//*************************************
void Data_Ready()
{
while((input(DRDY)& 0x01) != 0x01){;}
}
//*************************main********************
main(void)
{
int Xdata,Ydata,Zdata;
set_tris_b(0x00);
set_tris_c(0x11);
delay_ms(500);
output_high(Acc_CS);
delay_ms(100);
setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_16);
Calibrate(0x02);//01,02,00
delay_ms(1000);
Acc_wr(0x16,0x05); //05,09,01
delay_ms(500);
lcd_init();
lcd_send_byte(0,0x01);
lcd_gotoxy(2,1);
lcd_putc("Measurement 2G");
delay_ms(1000);
while(1)
{
Data_Ready();
Xdata = Acc_rd(0x06);
Ydata = Acc_rd(0x07);
Zdata = Acc_rd(0x08);
lcd_gotoxy(2,2);
printf(lcd_putc,"XYZ:%u %u %u ",Xdata,Ydata,Zdata);
delay_ms(500);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Sep 13, 2011 4:20 pm |
|
|
Your calibration routine is complex. Do you know for sure that it works ?
Why don't you try it without calling the calibration routine, and see what
kind of values you get. Comment it out:
Quote: |
// Calibrate(0x02); //01,02,00
|
In the MMA7455L data sheet, in Table 13, it says these are the expected
output values for a given acceleration. Note that the values are signed.
Code: |
2g Mode
Hex Decimal
Acc. Output Output
-2g $80 -128
-1g $C1 -63
0g $00 0
+1g $3F 63
+2g $7F 127
|
In the code below, you have declared the X, Y, Z data variables as 'int',
which is an unsigned 8-bit integer in CCS. But it's supposed to
be signed. Change the declaration to 'signed int8'.
Quote: |
int Xdata,Ydata,Zdata;
|
Then in the code below, you are displaying the results as unsigned
decimal values. So if the result was say, -1, which is a very small
acceleration, your code would display it as 255, and you would wonder
what is happening. You need to change the format to "%d".
Also, the size of the displayed number can vary from 1 to 3 characters,
and it could have a minus sign. Because you don't clear the screen
each time, you could have residual characters on the right side of the
lcd after each update. This would cause confusion about the true value
of the Z acceleration. You can fix this by putting \f in front of the XYZ
in the format string. This will clear the lcd screen each pass.
Quote: |
while(1)
{
Data_Ready();
Xdata = Acc_rd(0x06);
Ydata = Acc_rd(0x07);
Zdata = Acc_rd(0x08);
lcd_gotoxy(2,2);
printf(lcd_putc,"XYZ:%u %u %u ",Xdata,Ydata,Zdata);
delay_ms(500);
}
} |
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|