天天看點

利用51單片機讀取MPU9150中AK8975C的原始資料

//利用51單片機,晶振11.0592,序列槽調試助手上波特率設定為9600,資料位8位,停止位1
#include <REG51.H>  
#include <math.h>    //Keil library  
#include <stdio.h>   //Keil library 
#include <INTRINS.H>
typedef unsigned char  uchar;
typedef unsigned short ushort;
typedef unsigned int   uint;
//****************************************
// 定義51單片機端口
//****************************************
#define DataPort P0     //LCD1602資料端口
sbit    SCL=P2^2;           //IIC時鐘引腳定義
sbit    SDA=P2^3;           //IIC資料引腳定義

//****************************************
// 定義MPU6050内部位址
//****************************************
#define SMPLRT_DIV      0x19    //陀螺儀采樣率,典型值:0x07(125Hz)
#define CONFIG          0x1A    //低通濾波頻率,典型值:0x06(5Hz)
#define HXL             0X03
#define HXH             0X04
#define HYL             0X05
#define HYH             0X06
#define HZL             0X07
#define HZH             0X08
#define CNTL            0X0A
#define INT_PIN_CFG     0X37
#define USER_CTRL       0X6A
#define MPU9150SLAADD   0XD0
#define MAGADD          0X18
#define PWR_MGMT_1      0x6B    //電源管理,典型值:0x00(正常啟用)
#define WHO_AM_I            0x75    //IIC位址寄存器(預設數值0x68,隻讀)
//****************************************
//定義類型及變量
//****************************************
uchar dis[6];                           //顯示數字(-511至512)的字元數組
int dis_data;                       //變量
//****************************************
//函數聲明
//****************************************
void  delay(unsigned int k);                                        //延時                        
void  lcd_printf(uchar *s,int temp_data);

//MPU6050操作函數
void  InitMPU6050();                                                    //初始化MPU6050
void  Delay5us();
void  I2C_Start();
void  I2C_Stop();
void  I2C_SendACK(bit ack);
bit   I2C_RecvACK();
void  I2C_SendByte(uchar dat);
uchar I2C_RecvByte();
void  I2C_ReadPage();
void  I2C_WritePage();
void  display_ACCEL_x();
void  display_ACCEL_y();
void  display_ACCEL_z();
uchar Single_ReadI2C(uchar Slave_Address,uchar REG_Address);                        //讀取I2C資料
void  Single_WriteI2C(uchar Slave_Address,uchar REG_Address,uchar REG_data);    //向I2C寫入資料
//****************************************
//整數轉字元串
//****************************************
void lcd_printf(uchar *s,int temp_data)
{
    if(temp_data<0)
    {
        temp_data=-temp_data;
        *s='-';
    }
    else *s=' ';

    *++s =temp_data/10000+0x30;
    temp_data=temp_data%10000;     //取餘運算

    *++s =temp_data/1000+0x30;
    temp_data=temp_data%1000;     //取餘運算

    *++s =temp_data/100+0x30;
    temp_data=temp_data%100;     //取餘運算
    *++s =temp_data/10+0x30;
    temp_data=temp_data%10;      //取餘運算
    *++s =temp_data+0x30;   
}
//****************************************

void  SeriPushSend(uchar send_data)
{
    SBUF=send_data;  
    while(!TI);TI=0;      
}
//****************************************
//延時
//****************************************
void delay(unsigned int k)  
{                       
    unsigned int i,j;               
    for(i=0;i<k;i++)
    {           
        for(j=0;j<121;j++);
    }                       
}

//**************************************
//延時5微秒([email protected])
//不同的工作環境,需要調整此函數
//當改用1T的MCU時,請調整此延時函數
//**************************************
void Delay5us()
{
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
}
//**************************************
//I2C起始信号
//**************************************
void I2C_Start()
{
    SDA = 1;                    //拉高資料線
    SCL = 1;                    //拉高時鐘線
    Delay5us();                 //延時
    SDA = 0;                    //産生下降沿
    Delay5us();                 //延時
    SCL = 0;                    //拉低時鐘線
}
//**************************************
//I2C停止信号
//**************************************
void I2C_Stop()
{
    SDA = 0;                    //拉低資料線
    SCL = 1;                    //拉高時鐘線
    Delay5us();                 //延時
    SDA = 1;                    //産生上升沿
    Delay5us();                 //延時
}
//**************************************
//I2C發送應答信号
//入口參數:ack (0:ACK 1:NAK)
//**************************************
void I2C_SendACK(bit ack)
{
    SDA = ack;                  //寫應答信号
    SCL = 1;                    //拉高時鐘線
    Delay5us();                 //延時
    SCL = 0;                    //拉低時鐘線
    Delay5us();                 //延時
}
//**************************************
//I2C接收應答信号
//**************************************
bit I2C_RecvACK()
{
    SCL = 1;                    //拉高時鐘線
    Delay5us();                 //延時
    CY = SDA;                   //讀應答信号
    SCL = 0;                    //拉低時鐘線
    Delay5us();                 //延時
    return CY;
}
//**************************************
//向I2C總線發送一個位元組資料
//**************************************
void I2C_SendByte(uchar dat)
{
    uchar i;
    for (i=0; i<8; i++)         //8位計數器
    {
        dat <<= 1;              //移出資料的最高位
        SDA = CY;               //送資料口
        SCL = 1;                //拉高時鐘線
        Delay5us();             //延時
        SCL = 0;                //拉低時鐘線
        Delay5us();             //延時
    }
    I2C_RecvACK();
}
//**************************************
//從I2C總線接收一個位元組資料
//**************************************
uchar I2C_RecvByte()
{
    uchar i;
    uchar dat = 0;
    SDA = 1;                    //使能内部上拉,準備讀取資料,
    for (i=0; i<8; i++)         //8位計數器
    {
        dat <<= 1;
        SCL = 1;                //拉高時鐘線
        Delay5us();             //延時
        dat |= SDA;             //讀資料               
        SCL = 0;                //拉低時鐘線
        Delay5us();             //延時
    }
    return dat;
}
//**************************************
//向I2C裝置寫入一個位元組資料
//**************************************
void Single_WriteI2C(uchar Slave_Address,uchar REG_Address,uchar REG_data)
{
    I2C_Start();                  //起始信号
    I2C_SendByte(Slave_Address);   //發送裝置位址+寫信号
    I2C_SendByte(REG_Address);    //内部寄存器位址,
    I2C_SendByte(REG_data);       //内部寄存器資料,
    I2C_Stop();                   //發送停止信号
}
//**************************************
//從I2C裝置讀取一個位元組資料
//**************************************
uchar Single_ReadI2C(uchar Slave_Address,uchar REG_Address)
{
    uchar REG_data;
    I2C_Start();                   //起始信号
    I2C_SendByte(Slave_Address);    //發送裝置位址+寫信号
    I2C_SendByte(REG_Address);     //發送存儲單元位址,從0開始  
    I2C_Start();
                   //起始信号
    I2C_SendByte(Slave_Address+1);  //發送裝置位址+讀信号

    REG_data=I2C_RecvByte();       //讀出寄存器資料
    I2C_SendACK(1);                //接收應答信号
    I2C_Stop();                    //停止信号
    return REG_data;
}
//**************************************
//初始化MPU6050
//**************************************
void InitMPU6050()
{
    Single_WriteI2C(MPU9150SLAADD,PWR_MGMT_1,0x00); //解除休眠狀态
    Single_WriteI2C(MPU9150SLAADD,SMPLRT_DIV,0x07);
    Single_WriteI2C(MPU9150SLAADD,CONFIG, 0x06);
    Single_WriteI2C(MPU9150SLAADD,INT_PIN_CFG,0x02);
    Single_WriteI2C(MPU9150SLAADD,USER_CTRL,0x00);
    Single_WriteI2C(MAGADD,CNTL, 0x00);
    delay(100);
    Single_WriteI2C(MAGADD,CNTL, 0x01);

}
//**************************************
//合成資料
//**************************************
int GetData(uchar REG_Address)
{
    uchar H,L;
    H=(Single_ReadI2C(MAGADD,REG_Address));
    Single_WriteI2C(MAGADD,CNTL, 0x01);//此處非常關鍵,
    //因為日本公司的資料手冊上說,在單次測量模式下,每讀取一次,
    //會自動回歸power down mode ,是以這裡重新設定為單次測量模式
    L=Single_ReadI2C(MAGADD,REG_Address-1);
    Single_WriteI2C(MAGADD,CNTL, 0x01);
    return (H<<8)+L;   //合成資料

}
//**************************************
//在1602上顯示10位資料
//**************************************
void Display10BitData(int value)
{  uchar i;
//  value/=64;                          //轉換為10位資料
    lcd_printf(dis, value);         //轉換資料顯示
    for(i=0;i<6;i++)
    {
    SeriPushSend(dis[i]);
    }
}



void init_uart()
{
    TMOD=0x21;              
    TH1=0xfd;               
    TL1=0xfd;       

    SCON=0x50;
    PS=1;      //序列槽中斷設為高優先級别
    TR0=1;     //啟動定時器          
    TR1=1;
    ET0=1;     //打開定時器0中斷           
    ES=1;   
    EA=1;
}

//*********************************************************
//主程式
//*********************************************************
void main()
{ 
    delay(500);     //上電延時      
     init_uart();
    InitMPU6050();  //初始化MPU6050
    delay(150);
    while(1)
    {

        Display10BitData(GetData(HXH)); 
        Display10BitData(GetData(HYH));
        Display10BitData(GetData(HZH)); 


        SeriPushSend(0x0d); 
        SeriPushSend(0x0a);//換行,回車
        delay(100);
    }
}
           

繼續閱讀