STC15系列讀取MPU6050陀螺儀角度加速度串口顯示代碼

STC15系列讀取MPU6050陀螺儀角度加速度串口顯示程序代碼
調試通過,複製粘貼即編譯可使用,無需調試,晶振:24M,串口輸出,波特率:115200
爲方便大家調試,特附該程序的項目文件,下載打開即可調試,下載地址:
http://download.csdn.net/detail/liyu3519/9899708
效果圖片

//*********************************************************************
//STC15系列讀取MPU6505陀螺儀數據
//調試通過,複製粘貼即編譯可使用,無需調試,晶振:24M,串口輸出,波特率:115200
//版本:2.0        日期:2017-07-15
//*********************************************************************


#include <STC15W4K32S4.H>   //引用STC15系列頭文件,下載地址https://pan.baidu.com/s/1dQTSS2
#include <INTRINS.H>
#include <MATH.H>

#define     I2C_SCL     P14      //時鐘信號線
#define     I2C_SDA     P15      //數據信號線

#define PWR_MGMT_1      0x6B      //電源管理,典型值:0x00(正常啓用)
#define WHO_AM_I        0x75      //IIC地址寄存器(默認數值0x68,只讀)
#define SlaveAddress    0xD0      //IIC寫入時的地址字節數據,+1爲讀取

#define NOP1() nop_()
#define NOP2() NOP1(),NOP1()

#define MAIN_Fosc                   24000000L               //主時鐘,不同的晶振頻率可以直接修改
#define serial_one_read_max         16                      //接收緩存區長度
#define serial_one_baud_rate        115200L                 //波特率,波特率可以直接修改
#define Timer1_Reload_Usart         (65536UL -(MAIN_Fosc / 4 / serial_one_baud_rate))       //Timer1重裝值,定時器1產生波特率


//****************************************
// 定義MPU6050內部地址
//****************************************
#define SMPLRT_DIV      0x19    //陀螺儀採樣率,典型值:0x07(125Hz)
#define CONFIG          0x1A    //低通濾波頻率,典型值:0x06(5Hz)
#define GYRO_CONFIG     0x1B    //陀螺儀自檢及測量範圍,典型值:0x18(不自檢,2000deg/s)
#define ACCEL_CONFIG    0x1C    //加速計自檢、測量範圍及高通濾波頻率,典型值:0x01(不自檢,2G,5Hz)
#define ACCEL_XOUT_H    0x3B
#define ACCEL_XOUT_L    0x3C
#define ACCEL_YOUT_H    0x3D
#define ACCEL_YOUT_L    0x3E
#define ACCEL_ZOUT_H    0x3F
#define ACCEL_ZOUT_L    0x40
#define TEMP_OUT_H      0x41
#define TEMP_OUT_L      0x42
#define GYRO_XOUT_H     0x43
#define GYRO_XOUT_L     0x44    
#define GYRO_YOUT_H     0x45
#define GYRO_YOUT_L     0x46
#define GYRO_ZOUT_H     0x47
#define GYRO_ZOUT_L     0x48


void Delay1000ms()      //延時函數1秒
{
    unsigned char i, j, k;

    _nop_();
    _nop_();
    i = 85;
    j = 12;
    k = 155;
    do
    {
        do
        {
            while (--k);
        } while (--j);
    } while (--i);
}


//========================================================================
// 函數: void I2C_Start()
// 描述: I2C起始信號.
// 參數: none.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_Start()
{
    I2C_SDA = 1;                    //拉高數據線
    I2C_SCL = 1;                    //拉高時鐘線
    NOP2();                         //等待機器反應
    I2C_SDA = 0;                    //產生下降沿
    I2C_SCL = 0;                    //拉低時鐘線
}

//========================================================================
// 函數: void I2C_Stop()
// 描述: I2C停止信號.
// 參數: none.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_Stop()
{
    I2C_SDA = 0;                    //拉低數據線
    I2C_SCL = 1;                    //拉高時鐘線
    NOP2();                         //等待機器反應
    I2C_SDA = 1;                    //產生上升沿
    NOP1();                         //等待機器反應
}

//========================================================================
// 函數: void I2C_SendACK(bit ack)
// 描述: I2C發送應答信號.
// 參數: ack (0:ACK 1:NAK).
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_SendACK(bit ack)
{
    I2C_SDA = ack;                  //寫應答信號
    I2C_SCL = 1;                    //拉高時鐘線
    NOP2();                                         //等待機器反應
    I2C_SCL = 0;                    //拉低時鐘線
    NOP1();                                         //等待機器反應
}

//========================================================================
// 函數: bit I2C_RecvACK()
// 描述: I2C接收應答信號.
// 參數: none.
// 返回: 1:成功,0:失敗.
// 版本: V1.0, 2017-06-23
//========================================================================
bit I2C_RecvACK()
{
    I2C_SCL = 1;            //拉高時鐘線
    NOP2();                         //等待機器反應
    CY = I2C_SDA;           //讀應答信號
    I2C_SCL = 0;            //拉低時鐘線
    return CY;
}

//========================================================================
// 函數: void I2C_SendByte(u8 dat)
// 描述: 向I2C總線發送一個字節數據.
// 參數: dat:要發送的數據.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void I2C_SendByte(unsigned char dat)
{
    unsigned char i;
    for (i=0; i<8; i++)         //8位計數器
    {
        dat <<= 1;              //移出數據的最高位
        I2C_SDA = CY;           //送數據口
        I2C_SCL = 1;                //拉高時鐘線
        NOP2();                                 //等待機器反應
        I2C_SCL = 0;                //拉低時鐘線
    }
    I2C_RecvACK();
}

//========================================================================
// 函數: unsigned char I2C_RecvByte()
// 描述: 從I2C總線接收一個字節數據.
// 參數: none.
// 返回: 接收到的數據.
// 版本: V1.0, 2017-06-23
//========================================================================
unsigned char I2C_RecvByte()
{
    unsigned char i;
    unsigned char dat = 0;
    I2C_SDA = 1;                    //使能內部上拉,準備讀取數據,
    for (i=0; i<8; i++)                       //8位計數器
    {
        dat <<= 1;
        I2C_SCL = 1;                //拉高時鐘線
        NOP2();                                 //等待機器反應
        dat |= I2C_SDA;             //讀數據               
        I2C_SCL = 0;                //拉低時鐘線
    }
    return dat;
}

//========================================================================
// 函數: void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
// 描述: 向I2C設備寫入一個字節數據.
// 參數: REG_Address:地址.
//           REG_data:要寫入的數據.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data)
{
    I2C_Start();                  //起始信號
    I2C_SendByte(SlaveAddress);   //發送設備地址+寫信號
    I2C_SendByte(REG_Address);    //內部寄存器地址,
    I2C_SendByte(REG_data);       //內部寄存器數據,
    I2C_Stop();                   //發送停止信號
}

//========================================================================
// 函數: unsigned char Single_ReadI2C(unsigned char REG_Address)
// 描述: 從I2C設備讀取一個字節數據.
// 參數: REG_Address:地址.
// 返回: 讀取到的數據.
// 版本: V1.0, 2017-06-23
//========================================================================
unsigned char Single_ReadI2C(unsigned char REG_Address)
{
    unsigned char REG_data;
    I2C_Start();                   //起始信號
    I2C_SendByte(SlaveAddress);    //發送設備地址+寫信號
    I2C_SendByte(REG_Address);     //發送存儲單元地址,從0開始  
    I2C_Start();                   //起始信號
    I2C_SendByte(SlaveAddress+1);  //發送設備地址+讀信號
    REG_data=I2C_RecvByte();       //讀出寄存器數據
    I2C_SendACK(1);                //接收應答信號
    I2C_Stop();                    //停止信號
    return REG_data;
}

//========================================================================
// 函數: void MPU6050_init()
// 描述: 初始化MPU6050.
// 參數: none.
// 返回: none.
// 版本: V1.0, 2017-06-23
//========================================================================
void MPU6050_Init()
{
    Single_WriteI2C(PWR_MGMT_1, 0x00);  //解除休眠狀態
    Single_WriteI2C(SMPLRT_DIV, 0x07);
    Single_WriteI2C(CONFIG, 0x06);
    Single_WriteI2C(GYRO_CONFIG, 0x18);
    Single_WriteI2C(ACCEL_CONFIG, 0x01);
}

//========================================================================
// 函數: int GetData(u8 REG_Address)
// 描述: 讀取數據併合成爲int型數據.
// 參數: REG_Address:地址.
// 返回: 讀取到的數據.
// 版本: V1.0, 2017-06-23
//========================================================================
int GetData(unsigned char REG_Address)
{
    unsigned char H,L;
    H = Single_ReadI2C(REG_Address);
    L = Single_ReadI2C(REG_Address + 1);
    return (H << 8) + L;   //合成數據
}

////========================================================================
//// 函數: int get_x_angle()
//// 描述: 獲取三軸角速度,三軸加速度
//// 參數: gyro_id:數據ID,1:x角速度,2:y角速度,3:z角速度,4:x加速度,5:y加速度,6:z加速度.
//// 返回: 陀螺儀值.
//// 版本: V2.0, 2017-07-15
////========================================================================
int Get_Gyro_Data(unsigned char gyro_id)
{
    switch(gyro_id)
    {
        case 1: return GetData(ACCEL_XOUT_H);   break;
        case 2: return GetData(ACCEL_YOUT_H);   break;
        case 3: return GetData(ACCEL_ZOUT_H);   break;
        case 4: return GetData(GYRO_XOUT_H) ;   break;
        case 5: return GetData(GYRO_YOUT_H) ;   break;
        case 6: return GetData(GYRO_ZOUT_H) ;   break;
    }
    return 0;
}

//========================================================================
// 函數: int MPU6050_Get_Angle(float x,float y,float z,u8 dir)
// 描述: 轉化成與三個方向的夾角.
// 參數: x:x方向數據.
//       y:y方向數據.
//       z:z方向數據.
//       dir:方向ID.
// 返回: 夾角角度值(放大10倍).
// 版本: V1.0, 2017-06-23
//========================================================================
int MPU6050_Get_Angle(int x,int y,int z,unsigned char dir)
{
    float xdata temp;
    float xdata res = 0;
    switch(dir)
    {
        case 0://與z軸的夾角
                temp = sqrt(((float)x*(float)x+(float)y*(float)y))/(float)z;
                res  = atan(temp);
        break;
        case 1://與x軸的夾角
                temp = (float)x/sqrt(((float)y*(float)y+(float)z*(float)z));
                res  = atan(temp);
        break;
        case 2://與y軸的夾角
                temp = (float)y/sqrt(((float)x*(float)x+(float)z*(float)z));
                res  = atan(temp);
        break;
    }
    return (int)(res*1800/3.1416);//弧度轉換爲角度,擴大10倍
}

//========================================================================
// int get_included_angle(unsigned dat)
// 描述: 獲取角度或加速度
// 參數: angle_id:方向指示變量(1:X軸角度,2:Y軸角度,3:Z軸角度,4:X軸加速度,5:Y軸加速度,6:Z軸加速度).
// 返回: 夾角角度值(放大10倍).
// 版本: V1.0, 2017-06-23
//========================================================================
int MPU6050_Get_Data(unsigned angle_id)
{
    switch(angle_id)
    {
        case 1:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 1);break;
        case 2:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 2);break;
        case 3:return MPU6050_Get_Angle( Get_Gyro_Data(1), Get_Gyro_Data(2), Get_Gyro_Data(3), 0);break;
        case 4:return (int)((float)((float)Get_Gyro_Data(4)/16384)*9.8*100);
        case 5:return (int)((float)((float)Get_Gyro_Data(5)/16384)*9.8*100);
        case 6:return (int)((float)((float)Get_Gyro_Data(6)/16384)*9.8*100);
    }
    return 0;
}

//串口初始化
void Uart_Init()
{
    SCON |= 0x40;               //8位數據
    P_SW1 &=  ~0xc0;       //UART1 使用P30 P31口  默認
    TR1 = 0;                        //關閉定時器1
    AUXR &= ~0x01;         //串口1波特率使用定時器1
    TMOD &= ~(1<<6);       //Timer1 set As Timer
    TMOD &= ~0x30;         //16位自動重裝
    AUXR |=  (1<<6);        //定時器使用1T模式
    TH1 = (unsigned char)(Timer1_Reload_Usart >> 8);
    TL1 = (unsigned char)Timer1_Reload_Usart;
    TR1 = 1;                        //打開定時器1
    PS  = 1;                        //高優先級中斷
    REN = 1;                        //允許接收
    ES  = 1;                        //允許中斷
    EA  = 1;                        //允許全局中斷
}

//========================================================================
// 函數: serial_one_send_byte(unsigned char dat)
// 描述: 串口1發送一個字節.
// 參數: dat:字符(無符號八位整型數據).
// 返回: none.
// 版本: V1.0, 2017-06-22
//========================================================================
void serial_one_send_byte(unsigned char dat)
{
    SBUF = dat;
    while(!TI);
    TI = 0; 
}

//========================================================================
// 函數: serial_one_send_string(u8 *dat)
// 描述: 串口1發送字符串.
// 參數: dat:字符串.
// 返回: none.
// 版本: V1.0, 2017-06-22
//========================================================================
void serial_one_send_string(unsigned char *dat)
{
    while(*dat)
        serial_one_send_byte(*dat++);
}

//========================================================================
// 函數: void serial_one_send_number(long num)
// 描述: 串口1發送整型數據.
// 參數: num:整型數值.
// 返回: none.
// 版本: V1.0, 2017-06-22
//========================================================================
void serial_one_send_number(long num)
{
    long dat = 0;
    unsigned char  length = 0;
    if(num < 0)                                     //當數值爲負數時
    {
        serial_one_send_byte('-');  //輸出負號
        num = -num;                                 //將數值取相反數
    }

    if(num == 0)                                    //當數值爲0時
        serial_one_send_byte('0');  //輸出字符0
    else                                            //當數值不爲0時
    {
        while(num)                                  //將數值倒過來
        {
            dat = dat * 10;
            dat = dat + num % 10;
            num = num / 10;
            length++;
        }

        while(length--)                         //從第一位開始輸出倒過來的數值
        {
            serial_one_send_byte(dat % 10 + '0');
            dat = dat / 10;
        }
    }
}

void serial_one_send_float(double float_val, char bit_val)
{
    long xdata value_int = 0;
    long xdata value_flt = 0;

    if(float_val < 0)
    {
        serial_one_send_byte('-');
        float_val = -float_val;
    }

    value_int = (long)float_val;

    float_val = float_val - (double)value_int;

    for(;bit_val;bit_val--)
        float_val = float_val * 10;

    serial_one_send_number(value_int);
    serial_one_send_byte('.');
    serial_one_send_number((long)float_val);
}

float value = 0;

//主函數
void main()
{
    Delay1000ms();
    Uart_Init();            //串口初始化
    MPU6050_Init();         //初始化MPU6505
    while(1)
    {
        value = MPU6050_Get_Data(1);                    //獲取與x軸的夾角,角度被放大10倍
        serial_one_send_string("模塊與x軸的夾角爲:");
        serial_one_send_float(value / 10,1);            //角度除以10,並從串口發出,第二個參數爲保留一位小數
        serial_one_send_string("\r\n");                 //換行

        value = MPU6050_Get_Data(2);                    //獲取與y軸的夾角,角度被放大10倍
        serial_one_send_string("模塊與y軸的夾角爲:");
        serial_one_send_float(value / 10,1);            //角度除以10,並從串口發出
        serial_one_send_string("\r\n");                 //換行

        value = MPU6050_Get_Data(3);                    //獲取與z軸的夾角,角度被放大10倍
        serial_one_send_string("模塊與z軸的夾角爲:");
        serial_one_send_float(value / 10,1);            //角度除以10,並從串口發出
        serial_one_send_string("\r\n");                 //換行

        value = MPU6050_Get_Data(4);                    //獲取與x軸加速度,數值被放大100倍
        serial_one_send_string("x軸加速度爲:");
        serial_one_send_float(value/100,1);         //角度除以100,並從串口發出,第二個參數爲保留一位小數
        serial_one_send_string(" M/S2\r\n");                    //換行

        value = MPU6050_Get_Data(4);                    //獲取與y軸加速度,數值被放大100倍
        serial_one_send_string("y軸加速度爲:");
        serial_one_send_float(value / 100,1);           //角度除以100,並從串口發出
        serial_one_send_string(" M/S2\r\n");                    //換行

        value = MPU6050_Get_Data(4);                    //獲取與z軸加速度,數值被放大100倍
        serial_one_send_string("z軸加速度爲:");
        serial_one_send_float(value / 100,1);           //角度除以100,並從串口發出
        serial_one_send_string(" M/S2\r\n\r\n");                    //換行

        Delay1000ms();
        Delay1000ms();
    }
}

//串口中斷
void Uart1_Int (void) interrupt 4
{
    if(RI)
        RI = 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章