//***************************************
// GY-45 MMA8452 IIC测试程序
// 使用单片机PIC16F877A
// 晶振:4M
// 显示:Nokia 5110
// 编译环境 MPLAB
// 时间:2012.9.11 吴迪
// QQ:362911737
//****************************************
#include  <pic.h>
#include"SPI-CHAR.h" 
#include  <math.h>     
#include  <stdio.h> 
__CONFIG(0x3b32);
#define  uchar unsigned char
#define  uint unsigned int
#define  SCL  RD0        //IIC时钟引脚定义
#define  SDA  RE1    //IIC数据引脚定义
#define SDA_DIR TRISE1                        //定义E口方向寄存器
#define SDA_HIGH() SDA_DIR =1                  //设置数据口为输入
#define SDA_LOW()  SDA_DIR = 0          //设置数据口为输出
#define  _nop_  NOP()
#define SlaveAddress  0x38 //定义器件在IIC总线中的从地址,根据SA0地址引脚不同修改
typedef unsigned char  BYTE;
typedef unsigned short WORD;
uchar BUF_drift[8];
BYTE BUF[8];                        //接收数据缓存区     
uchar ge,shi,bai,qian,wan;          //显示变量
int  dis_data;                      //变量
int x,y,z;
uchar CY;
void delay(unsigned int k);
void Init_MMA8452(void);            //初始化MMA8452
void conversion(uint temp_data);
void  Single_Write_MMA8452(uchar REG_Address,uchar REG_data);  //单个写入数据
uchar Single_Read_MMA8452(uchar REG_Address);                  //单个读取内部寄存器数据
void  Multiple_Read_MMA8452(void);                                  //连续的读取内部寄存器数据
//------------------------------------
void Delay5us();
void Delay5ms();
void MMA8452_Start();
void MMA8452_Stop();
void MMA8452_SendACK(uchar ack);
bit  MMA8452_RecvACK();
void MMA8452_SendByte(BYTE dat);
BYTE MMA8452_RecvByte();
void MMA8452_ReadPage();
void MMA8452_WritePage();
//*********************************************************
void conversion(uint temp_data) 
wan=temp_data/10000+16 ;
temp_data=temp_data%10000;  //取余运算
qian=temp_data/1000+16 ;
temp_data=temp_data%1000;    //取余运算
bai=temp_data/100+0x10 ;
temp_data=temp_data%100;    //取余运算
shi=temp_data/10+0x10    ;
temp_data=temp_data%10;      //取余运算
ge=temp_data+0x10; 
}
/*******************************/
void delay(unsigned int k)
{     
unsigned int i,j;   
for(i=0;i<k;i++)
for(j=0;j<110;j++); 
}     
}
/**************************************
延时5微秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数,注意时钟过快时需要修改
当改用1T的MCU时,请调整此延时函数
**************************************/
void Delay5us()
{
NOP();NOP();NOP();NOP();
NOP();//NOP();NOP();NOP();
//NOP();NOP();NOP();NOP();
}
/**************************************
延时5毫秒(STC90C52RC@12M)
不同的工作环境,需要调整此函数
当改用1T的MCU时,请调整此延时
函数
**************************************/
void Delay5ms()
{
WORD n = 560;
while (n--);
}
/**************************************
起始信号
**************************************/
void MMA8452_Start()
{
SDA_LOW();
SDA = 1;                    //拉高数据线
SCL = 1;                    //拉高时钟线
Delay5us();                //延时
SDA = 0;                    //产生下降沿
Delay5us();                //延时
SCL = 0;                    //拉低时钟线
}
/**************************************
停止信号
**************************************/
void MMA8452_Stop()
{
SDA_LOW();
SDA = 0;                    //拉低数据线
SCL = 1;                    //拉高时钟线
Delay5us();                //延时
SDA = 1;                    //产生上升沿
Delay5us();                //延时
}
/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void MMA8452_SendACK(uchar ack)
{
SDA_LOW();
SDA = ack;                  //写应答信号
SCL = 1;                    //拉高时钟线
Delay5us();                //延时
SCL = 0;                    //拉低时钟线
Delay5us();                //延时
}
/**************************************
接收应答信号
**************************************/
bit MMA8452_RecvACK()
{
SDA_HIGH();
SCL = 1;                    //拉高时钟线
Delay5us();                //延时
if(SDA==1)
CY=1;
else
CY = 0 ;                  //读应答信号
SCL = 0;                    //拉低时钟线
Delay5us();                //延时
SDA_LOW();
return CY;
}
/**************************************
向IIC总线发送一个字节数据
**************************************/
void MMA8452_SendByte(BYTE dat)
{
BYTE i;
SDA_LOW();
for (i=0; i<8; i++)        //8位计数器
{
if(dat&0x80)
CY=1;
else CY=0;
SDA = CY;              //送数据口
SCL = 1;                //拉高时钟线
Delay5us();            //延时
SCL = 0;                //拉低时钟线
Delay5us();            //延时
dat <<= 1;              //移出数据的最高位
}
MMA8452_RecvACK();
}
/**************************************
从IIC总线接收一个字节数据
**************************************/
BYTE MMA8452_RecvByte()
{
BYTE i;
BYTE dat = 0;
SDA_LOW();
SDA = 1;                    //使能内部上拉,准备读取数据,
SDA_HIGH();
for (i=0; i<8; i++)        //8位计数器
{
dat <<= 1;
SCL = 1;                //拉高时钟线
Delay5us();            //延时
if(SDA==1)
dat |= 1;            //读数据 
else
dat |=0;                     
SCL = 0;                //拉低时钟线
Delay5us();            //延时
}
SDA_LOW();
return dat;
}
//******单字节写入*******************************************
void Single_Write_MMA8452(uchar REG_Address,uchar REG_data)
{
MMA8452_Start();                  //起始信号
MMA8452_SendByte(SlaveAddress);  //发送设备地址+写信号
MMA8452_SendByte(REG_Address);    //内部寄存器地址
MMA8452_SendByte(REG_data);      //内部寄存器数据
MMA8452_Stop();                  //发送停止信号
}
//********单字节读取*****************************************
uchar Single_Read_MMA8452(uchar REG_Address)
{  uchar REG_data;
MMA8452_Start();                          //起始信号
MMA8452_SendByte(SlaveAddress);          //发送设备地址+写信号
MMA8452_SendByte(REG_Address);                  //发送存储单元地址,从0开始
MMA8452_Start();                          //起始信号
MMA8452_SendByte(SlaveAddress+1);        //发送设备地址+读信号
REG_data=MMA8452_RecvByte();              //读出寄存器数据
MMA8452_SendACK(1); 
MMA8452_Stop();                          //停止信号
return REG_data;
}
//*********************************************************
//
//连续读出MMA8452内部加速度数据,地址范围0x01~0x06
//
//*********************************************************
void Multiple_Read_MMA8452(void)
{  uchar i;
MMA8452_Start();                          //起始信号
MMA8452_SendByte(SlaveAddress);          //发送设备地址+写信号
MMA8452_SendByte(0x01);                  //发送存储单元地址,从0x01开始
MMA8452_Start();                          //起始信号
MMA8452_SendByte(SlaveAddress+1);        //发送设备地址+读信号
for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中BUF
{
BUF[i] = MMA8452_RecvByte();          //BUF[0]存储0x32地址中的数据
if (i == 5)
{
MMA8452_SendACK(1);                //最后一个数据需要回NOACK
}
else
{
MMA8452_SendACK(0);                //回应ACK
}
}
MMA8452_Stop();                          //停止信号
Delay5ms();
}
void Write_drift_MMA8452(int i,int j,int z )
{
MMA8452_Start();
MMA8452_SendByte(SlaveAddress);
MMA8452_SendByte(0x2F);
MMA8452_SendByte(i);
MMA8452_Start();
MMA8452_SendByte(SlaveAddress);
MMA8452_SendByte(0x30);
MMA8452_SendByte(j);
MMA8452_Start();
MMA8452_SendByte(SlaveAddress);
MMA8452_SendByte(0x31);
MMA8452_SendByte(z);
}
//*********************************************************
/*void Read_drift_MMA8452(void)
{
uchar i;
MMA8452_Start();                          //起始信号
MMA8452_SendByte(SlaveAddress);          //发送设备地址+写信号
MMA8452_SendByte(0x10);                  //发送存储单元
地址,从0x32开始
MMA8452_Start();                          //起始信号
MMA8452_SendByte(SlaveAddress+1);        //发送设备地址+读信号
for (i=0; i<7; i++)                      //连续读取6个地址数据,存储中BUF
{
BUF_drift[i] = MMA7455_RecvByte();          //BUF[0]存储0x32地址中的数据
if (i == 6)
{
MMA7455_SendACK(1);                //最后一个数据需要回NOACK
}
else
{
MMA7455_SendACK(0);                //回应ACK
}
}
MMA7455_Stop();                          //停止信号
Delay5ms();
}*/
void check()//自检
{
int i=0,j=0,k=0,flag1=1,flag2=1,flag3=1;
float temp1,temp2,temp3;
Single_Write_MMA8452(0x2A,0x01);  //
Single_Write_MMA8452(0x2B,0x02);  //
delay(10);
while(flag1||flag2||flag3)
{
Multiple_Read_MMA8452(); 
dis_data=BUF[0];
if(dis_data>0x7f)
dis_data=(((dis_data-1)^0xff)&0x7f);  //取反并屏掉符号位                   
temp1=(float)dis_data/63;
temp1*=100;
dis_data=BUF[1];
if(dis_data>0x7f)
dis_data=(((dis_data-1)^0xff)&0x7f);  //取反并屏掉符号位                   
temp2=(float)dis_data/63;
temp2*=100;
dis_data=BUF[2];
if(dis_data>0x7f)
dis_data=(((dis_data-1)^0xff)&0x7f);  //取反并屏掉符号位                   
temp3=(float)dis_data/63;
temp3*=100;
Write_drift_MMA8452(i,j,k);
if((temp2!=0)&&flag2)
j++;
else
flag2=0;
if((temp3<98)&&flag3)
k++;
else
flag3=0;
if((temp1!=0)&&flag1)
i++;
else
flag1=0;               
delay(1);
}
}
//******************初始化IO口
void init_IO()
{
ADCON1=0x06;              //设置A口为普通I/O口           
TRISB=0X00;
TRISA=0X00;        //设置A口为输出
// TRISE = 0xf0;
/
/ PORTE = 0;
}
//初始化MMA8452,根据需要请参考pdf进行修改************************
void Init_MMA8452()
{
Single_Write_MMA8452(0x2A,0x01);  //
Single_Write_MMA8452(0x2B,0x02);  //
LCD_clear();//清屏
LCD_write_char(2,2,'C'); LCD_write_char(3,2,'H'); LCD_write_char(4,2,'E');
LCD_write_char(5,2,'C'); LCD_write_char(6,2,'K');
LCD_write_char(7,2,14);LCD_write_char(8,2,14);
LCD_write_char(9,2,14);LCD_write_char(10,2,14);
LCD_write_char(11,2,14);LCD_write_char(12,2,14);
LCD_write_char(0,3,'P'); LCD_write_char(1,3,'L'); LCD_write_char(2,3,'E'); LCD_write_char(3,3,'A'); LCD_write_char(4,3,'S');
LCD_write_char(5,3,'E'); LCD_write_char(6,3,0); LCD_write_char(7,3,'W'); LCD_write_char(8,3,'A'); LCD_write_char(9,3,'I');
LCD_write_char(10,3,'T');
delay(500);
check();
}
//*********************************************************
//******主程序********
//********************************************************
*
void main()
{
int sign_bit;
unsigned int i;
float temp;
delay(2);                    //上电延时
init(); 
SPIINT();
delay(500);
LCD_init();  //初始化LCD模块
init_IO(); 
Init_MMA8452();                //初始化MMA8452
LCD_clear(); //清屏幕
while(1)                        //循环
{
Multiple_Read_MMA8452();      //连续读出数据,存储在BUF中
//---------显示X轴
dis_data=BUF[0];
if(dis_data>0x7f)
{
dis_data=0xff-dis_data;
sign_bit=1;
}
else
sign_bit=0;                  //确定正负符号位
recv函数
temp=(float)dis_data/63;
temp*=100;
conversion(temp);      //计算数据和显示
LCD_write_char(0,0,56); //X
LCD_write_char(1,0,26); //':'
if(sign_bit==1)LCD_write_char(2,0,13);  //-
else LCD_write_char(2,0,0); //显示正负符号位
LCD_write_char(3,0,bai);
LCD_write_char(4,0,14); //.
LCD_write_char(5,0,shi);
LCD_write_char(6,0,ge);
LCD_write_char(7,0,'G');
//---------显示Y轴
dis_data=BUF[2];
if(dis_data>0x7f){
dis_data=0xff-dis_data;
sign_bit=1;
}
else
sign_bit=0;                  //确定正负符号位
temp=(float)dis_data/63;
temp*=100;
conversion(temp);      //计算数据和显示
LCD_write_char(0,1,57); //Y
LCD_write_char(1,1,26); //:
if(sign_bit==1)LCD_write_char(2,1,13);  //-
else LCD_write_char(2,1,0);//显示正负符号位
LCD_write_char(3,1,bai);
LCD_write_char(4,1,14); //.
LCD_write_char(5,1,shi);
LCD_write_char(6,1,ge); 
LCD_write_char(7,1,'G');
//-------显示Z轴
dis_data=BUF[4];
if(dis_data>0x7f){
dis_data=0xff-dis_data;
sign_bit=1;
}
else
sign_bit=0;                  //确定正负符号位
temp=(float)dis_data/63;
temp*=100;
conversion(temp);      //计算数据和显示
LCD_write_char(0,2,58); //Z
LCD_write_char(1,2,26); //:
if(sign_bit==1)LCD_write_char(2,2,13); //-
else LCD_write_char(2,2,0);//显示正负符号位
LCD_write_char(3,2,bai);
LCD_write_char(4,2,14); //.
LCD_write_char(5,2,shi);
LCD_write_char(6,2,ge);
LCD_write_char(7,2,'G');
for (i=0;i<30000;i++);  //延时           
}
}