Tsinghua Icenter ChenHuan

Dependencies:   mbed

main.cpp

Committer:
heroistired
Date:
2017-03-16
Revision:
0:9b8df4f9b792

File content as of revision 0:9b8df4f9b792:

/***************************************************************
功能 : 基于mbed的动感平台SDK 包含摇杆 位置传感器 舵机 以及液晶屏等外设
作者 : 陈欢 清华大学电机工程与应用电子技术系
邮箱 : h-che14@mails.tsinghua.edu.cn OR heroistired@gmail.com
声明 : 
本程序仅供学习与交流使用,如需他用,须联系作者
All rights reserved
2017.2.15
***************************************************************/

#include "mbed.h"
#include "mpu6050_config.h"
#include "Servo.h"
#include "TFT_ILI9340.h"
#include "PinMap.h"
Serial SystemUart(SERIAL_TX, SERIAL_RX);  //系统串口初始化

//////////////////////////////////////////////////////////////////////////////////   
//头文件部分
//////////////////////////////////////////////////////////////////////////////////   

///////////////////////////////////////
//系统相关
///////////////////////////////////////

//系统监控 
//接受外部调用的变量
int TimeNow = 0;  //当前的系统时间
float CpuUsage = 0.0; //当前的CPU使用率 以主中断为基准
unsigned int MainInterruptCounter = 0; //存储系统主中断的总执行次数
float MainInterruptFreq = 0.0; //存储系统主中断的实际频率 Hz
//中间变量 不接受外部调用
int FreqTime = 0; //计算系统中断的实际频率 存储的是测量开始时的系统时间
int FreqCounter = 0; //计算系统中断的实际频率 存储的是测量开始时的中断执行次数
bool Flag_MeasureFreq = true;  //标志 是否要进行一次频率测量


///////////////////////////////////////
//mpuiic.h
///////////////////////////////////////

//声明IIC需要用到的IO口
DigitalOut MPU_IIC_SCL(Pin_MPU6050SCL); //SCL
DigitalInOut MPU_IIC_SDA(Pin_MPU6050SDA); //SDA 

//弥补屏幕LED画错的bug
DigitalOut TFT_LED(Pin_TFT_LED);

               
//定义IO操作的宏
#define MPU_SDA_IN()  MPU_IIC_SDA.input()
#define MPU_SDA_OUT() MPU_IIC_SDA.output() 
#define MPU_READ_SDA   MPU_IIC_SDA.read() //读取SDA

//兼容性宏定义
#define delay_us wait_us
#define delay_ms wait_ms
#define u8 unsigned char
#define u16 unsigned short 

//IIC所有操作函数
void MPU_IIC_Delay(void);               //MPU IIC延时函数
void MPU_IIC_Init(void);                //初始化IIC的IO口                 
void MPU_IIC_Start(void);               //发送IIC开始信号
void MPU_IIC_Stop(void);                //发送IIC停止信号
void MPU_IIC_Send_Byte(u8 txd);         //IIC发送一个字节
u8 MPU_IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 MPU_IIC_Wait_Ack(void);              //IIC等待ACK信号
void MPU_IIC_Ack(void);                 //IIC发送ACK信号
void MPU_IIC_NAck(void);                //IIC不发送ACK信号

void IMPU_IC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 MPU_IIC_Read_One_Byte(u8 daddr,u8 addr);  

///////////////////////////////////////
//mp6050.h
///////////////////////////////////////
u8 MPU_Init(void);                              //初始化MPU6050
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf);//IIC连续写
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf); //IIC连续读 
u8 MPU_Write_Byte(u8 reg,u8 data);              //IIC写一个字节
u8 MPU_Read_Byte(u8 reg);                       //IIC读一个字节

u8 MPU_Set_Gyro_Fsr(u8 fsr);
u8 MPU_Set_Accel_Fsr(u8 fsr);
u8 MPU_Set_LPF(u16 lpf);
u8 MPU_Set_Rate(u16 rate);
u8 MPU_Set_Fifo(u8 sens);


short MPU_Get_Temperature(void);
u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz);
u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az);

///////////////////////////////////////
//软件方法解算姿态
///////////////////////////////////////
Timer SystemTimer; //系统计时器
Ticker MainInterrupt;  //主中断 100Hz
//加速度 角速度 温度(原始值)
short aacx = 0, aacy = 0, aacz = 0, gyrox = 0, gyroy = 0, gyroz = 0, temp = 0;
float Pitch = 0, Yaw = 0, Roll = 0; //绕x,y,z轴的转角
float ThetaXz = 0, ThetaYz = 0; //重力加速度在XOZ、YOZ面上与z轴夹角

//卡尔曼滤波器相关参量
#define PI 3.1415926
struct KalmanStruct
{
    float K1; 
    float angle, angle_dot;     
    float Q_angle;// 过程噪声的协方差
    float Q_gyro;//0.003 过程噪声的协方差 过程噪声的协方差为一个一行两列矩阵
    float R_angle;// 测量噪声的协方差 既测量偏差
    float dt;//                 
    char  C_0;
    float Q_bias, Angle_err;
    float PCt_0, PCt_1, E;
    float K_0, K_1, t_0, t_1;
    float Pdot[4];
    float PP[2][2];
};

struct KalmanStruct X_Axis = {0}, Y_Axis = {0};

void MainInterruptIRQ(void);  //主中断服务函数
void Kalman_Filter(float AccelX,float GyroX, float AccelY,float GyroY); //卡尔曼滤波器
void Processing(void);  //用户进程函数

//系统初始化函数
void System_Init(void);

//////////////////////////////////////////////////////////////////////////////////   
//函数实现部分
//////////////////////////////////////////////////////////////////////////////////   

///////////////////////////////////////
//mpuiic.c
///////////////////////////////////////

//MPU IIC 延时函数
void MPU_IIC_Delay(void)
{
    delay_us(2);
}
//初始化IIC
void MPU_IIC_Init(void)
{                        
    RCC->APB2ENR|=1<<4;     //先使能外设IO PORTC时钟                            
    GPIOC->CRH&=0XFFF00FFF; //PC11/12 推挽输出
    GPIOC->CRH|=0X00033000;    
    GPIOC->ODR|=3<<11;      //PC11,12 输出高
}
//产生IIC起始信号
void MPU_IIC_Start(void)
{
    MPU_SDA_OUT();     //sda线输出
    MPU_IIC_SDA=1;        
    MPU_IIC_SCL=1;
    MPU_IIC_Delay();
    MPU_IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
    MPU_IIC_Delay();
    MPU_IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}     
//产生IIC停止信号
void MPU_IIC_Stop(void)
{
    MPU_SDA_OUT();//sda线输出
    MPU_IIC_SCL=0;
    MPU_IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
    MPU_IIC_Delay();
    MPU_IIC_SCL=1;  
    MPU_IIC_SDA=1;//发送I2C总线结束信号
    MPU_IIC_Delay();                                
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 MPU_IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    MPU_SDA_IN();      //SDA设置为输入  
    MPU_IIC_SDA=1;MPU_IIC_Delay();     
    MPU_IIC_SCL=1;MPU_IIC_Delay();   
    while(MPU_READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            MPU_IIC_Stop();
            return 1;
        }
    }
    MPU_IIC_SCL=0;//时钟输出0      
    return 0;  
} 
//产生ACK应答
void MPU_IIC_Ack(void)
{
    MPU_IIC_SCL=0;
    MPU_SDA_OUT();
    MPU_IIC_SDA=0;
    MPU_IIC_Delay();
    MPU_IIC_SCL=1;
    MPU_IIC_Delay();
    MPU_IIC_SCL=0;
}
//不产生ACK应答          
void MPU_IIC_NAck(void)
{
    MPU_IIC_SCL=0;
    MPU_SDA_OUT();
    MPU_IIC_SDA=1;
    MPU_IIC_Delay();
    MPU_IIC_SCL=1;
    MPU_IIC_Delay();
    MPU_IIC_SCL=0;
}                                        
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答           
void MPU_IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
    MPU_SDA_OUT();      
    MPU_IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        MPU_IIC_SDA=(txd&0x80)>>7;
        txd<<=1;      
        MPU_IIC_SCL=1;
        MPU_IIC_Delay(); 
        MPU_IIC_SCL=0;  
        MPU_IIC_Delay();
    }    
}       
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 MPU_IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    MPU_SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        MPU_IIC_SCL=0; 
        MPU_IIC_Delay();
        MPU_IIC_SCL=1;
        receive<<=1;
        if(MPU_READ_SDA)receive++;   
        MPU_IIC_Delay(); 
    }                    
    if (!ack)
        MPU_IIC_NAck();//发送nACK
    else
        MPU_IIC_Ack(); //发送ACK   
    return receive;
}

///////////////////////////////////////
//mp6050.c
///////////////////////////////////////
//初始化MPU6050
//返回值:0,成功
//    其他,错误代码
u8 MPU_Init(void)
{ 
    u8 res; 
    MPU_IIC_Init();//初始化IIC总线
    MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); //复位MPU6050
    delay_ms(100);
    MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00); //唤醒MPU6050 
    MPU_Set_Gyro_Fsr(3);                    //陀螺仪传感器,±2000dps
    MPU_Set_Accel_Fsr(0);                   //加速度传感器,±2g
    MPU_Set_Rate(200);                      //设置采样率200Hz
    MPU_Write_Byte(MPU_INT_EN_REG,0X00);    //关闭所有中断
    MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); //I2C主模式关闭
    MPU_Write_Byte(MPU_FIFO_EN_REG,0X00);   //关闭FIFO
    MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80); //INT引脚低电平有效
    res=MPU_Read_Byte(MPU_DEVICE_ID_REG); 
    if(res==MPU_ADDR)//器件ID正确
    {
        MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); //设置CLKSEL,PLL X轴为参考
        MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //加速度与陀螺仪都工作
        MPU_Set_Rate(200);                      //设置采样率为200Hz
    }else return 1;
    return 0;
}
//设置MPU6050陀螺仪传感器满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_Gyro_Fsr(u8 fsr)
{
    return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);//设置陀螺仪满量程范围  
}
//设置MPU6050加速度传感器满量程范围
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_Accel_Fsr(u8 fsr)
{
    return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);//设置加速度传感器满量程范围  
}
//设置MPU6050的数字低通滤波器
//lpf:数字低通滤波频率(Hz)
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_LPF(u16 lpf)
{
    u8 data=0;
    if(lpf>=188)data=1;
    else if(lpf>=98)data=2;
    else if(lpf>=42)data=3;
    else if(lpf>=20)data=4;
    else if(lpf>=10)data=5;
    else data=6; 
    return MPU_Write_Byte(MPU_CFG_REG,data);//设置数字低通滤波器  
}
//设置MPU6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
//    其他,设置失败 
u8 MPU_Set_Rate(u16 rate)
{
    u8 data;
    if(rate>1000)rate=1000;
    if(rate<4)rate=4;
    data=1000/rate-1;
    data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);  //设置数字低通滤波器
    return MPU_Set_LPF(rate/2); //自动设置LPF为采样率的一半
}

//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
    u8 buf[2]; 
    short raw;
    float temp;
    MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf); 
    raw=((u16)buf[0]<<8)|buf[1];  
    temp=36.53+((double)raw)/340;  
    return temp*100;;
}
//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
{
    u8 buf[6],res;  
    res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
    if(res==0)
    {
        *gx=((u16)buf[0]<<8)|buf[1];  
        *gy=((u16)buf[2]<<8)|buf[3];  
        *gz=((u16)buf[4]<<8)|buf[5];
    }   
    return res;;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
    u8 buf[6],res;  
    res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
    if(res==0)
    {
        *ax=((u16)buf[0]<<8)|buf[1];  
        *ay=((u16)buf[2]<<8)|buf[3];  
        *az=((u16)buf[4]<<8)|buf[5];
    }   
    return res;;
}
//IIC连续写
//addr:器件地址 
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//    其他,错误代码
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
    u8 i; 
    MPU_IIC_Start(); 
    MPU_IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令 
    if(MPU_IIC_Wait_Ack())  //等待应答
    {
        MPU_IIC_Stop();      
        return 1;       
    }
    MPU_IIC_Send_Byte(reg); //写寄存器地址
    MPU_IIC_Wait_Ack();     //等待应答
    for(i=0;i<len;i++)
    {
        MPU_IIC_Send_Byte(buf[i]);  //发送数据
        if(MPU_IIC_Wait_Ack())      //等待ACK
        {
            MPU_IIC_Stop();  
            return 1;        
        }       
    }    
    MPU_IIC_Stop();  
    return 0;   
} 
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//    其他,错误代码
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
    MPU_IIC_Start(); 
    MPU_IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令 
    if(MPU_IIC_Wait_Ack())  //等待应答
    {
        MPU_IIC_Stop();      
        return 1;       
    }
    MPU_IIC_Send_Byte(reg); //写寄存器地址
    MPU_IIC_Wait_Ack();     //等待应答
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令 
    MPU_IIC_Wait_Ack();     //等待应答 
    while(len)
    {
        if(len==1)*buf=MPU_IIC_Read_Byte(0);//读数据,发送nACK 
        else *buf=MPU_IIC_Read_Byte(1);     //读数据,发送ACK  
        len--;
        buf++; 
    }    
    MPU_IIC_Stop(); //产生一个停止条件 
    return 0;   
}
//IIC写一个字节 
//reg:寄存器地址
//data:数据
//返回值:0,正常
//    其他,错误代码
u8 MPU_Write_Byte(u8 reg,u8 data)                
{ 
    MPU_IIC_Start(); 
    MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令 
    if(MPU_IIC_Wait_Ack())  //等待应答
    {
        MPU_IIC_Stop();      
        return 1;       
    }
    MPU_IIC_Send_Byte(reg); //写寄存器地址
    MPU_IIC_Wait_Ack();     //等待应答 
    MPU_IIC_Send_Byte(data);//发送数据
    if(MPU_IIC_Wait_Ack())  //等待ACK
    {
        MPU_IIC_Stop();  
        return 1;        
    }        
    MPU_IIC_Stop();  
    return 0;
}
//IIC读一个字节 
//reg:寄存器地址 
//返回值:读到的数据
u8 MPU_Read_Byte(u8 reg)
{
    u8 res;
    MPU_IIC_Start(); 
    MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令 
    MPU_IIC_Wait_Ack();     //等待应答 
    MPU_IIC_Send_Byte(reg); //写寄存器地址
    MPU_IIC_Wait_Ack();     //等待应答
    MPU_IIC_Start();
    MPU_IIC_Send_Byte((MPU_ADDR<<1)|1);//发送器件地址+读命令 
    MPU_IIC_Wait_Ack();     //等待应答 
    res=MPU_IIC_Read_Byte(0);//读取数据,发送nACK 
    MPU_IIC_Stop();         //产生一个停止条件 
    return res;     
}

///////////////////////////////////////
//软件方法解算姿态
///////////////////////////////////////

/**************************************************************************
函数功能:简易卡尔曼滤波
入口参数:加速度、角速度
返回  值:无
**************************************************************************/

void Kalman_Filter(float AccelX,float GyroX, float AccelY,float GyroY)      
{
    X_Axis.angle+=(GyroX - X_Axis.Q_bias) * X_Axis.dt; //先验估计
    X_Axis.Pdot[0]=X_Axis.Q_angle - X_Axis.PP[0][1] - X_Axis.PP[1][0]; // Pk-先验估计误差协方差的微分

    X_Axis.Pdot[1]=-X_Axis.PP[1][1];
    X_Axis.Pdot[2]=-X_Axis.PP[1][1];
    X_Axis.Pdot[3]=X_Axis.Q_gyro;
    X_Axis.PP[0][0] += X_Axis.Pdot[0] * X_Axis.dt;   // Pk-先验估计误差协方差微分的积分
    X_Axis.PP[0][1] += X_Axis.Pdot[1] * X_Axis.dt;   // =先验估计误差协方差
    X_Axis.PP[1][0] += X_Axis.Pdot[2] * X_Axis.dt;
    X_Axis.PP[1][1] += X_Axis.Pdot[3] * X_Axis.dt;
        
    X_Axis.Angle_err = AccelX - X_Axis.angle;  //zk-先验估计
    
    X_Axis.PCt_0 = X_Axis.C_0 * X_Axis.PP[0][0];
    X_Axis.PCt_1 = X_Axis.C_0 * X_Axis.PP[1][0];
    
    X_Axis.E = X_Axis.R_angle + X_Axis.C_0 * X_Axis.PCt_0;
    
    X_Axis.K_0 = X_Axis.PCt_0 / X_Axis.E;
    X_Axis.K_1 = X_Axis.PCt_1 / X_Axis.E;
    
    X_Axis.t_0 = X_Axis.PCt_0;
    X_Axis.t_1 = X_Axis.C_0 * X_Axis.PP[0][1];

    X_Axis.PP[0][0] -= X_Axis.K_0 * X_Axis.t_0;       //后验估计误差协方差
    X_Axis.PP[0][1] -= X_Axis.K_0 * X_Axis.t_1;
    X_Axis.PP[1][0] -= X_Axis.K_1 * X_Axis.t_0;
    X_Axis.PP[1][1] -= X_Axis.K_1 * X_Axis.t_1;
        
    X_Axis.angle   += X_Axis.K_0 * X_Axis.Angle_err;  //后验估计
    X_Axis.Q_bias  += X_Axis.K_1 * X_Axis.Angle_err;  //后验估计
    X_Axis.angle_dot   = GyroX - X_Axis.Q_bias;     //输出值(后验估计)的微分=角速度
    
    Y_Axis.angle+=(GyroY - Y_Axis.Q_bias) * Y_Axis.dt; //先验估计
    Y_Axis.Pdot[0]=Y_Axis.Q_angle - Y_Axis.PP[0][1] - Y_Axis.PP[1][0]; // Pk-先验估计误差协方差的微分

    Y_Axis.Pdot[1]=-Y_Axis.PP[1][1];
    Y_Axis.Pdot[2]=-Y_Axis.PP[1][1];
    Y_Axis.Pdot[3]=Y_Axis.Q_gyro;
    Y_Axis.PP[0][0] += Y_Axis.Pdot[0] * Y_Axis.dt;   // Pk-先验估计误差协方差微分的积分
    Y_Axis.PP[0][1] += Y_Axis.Pdot[1] * Y_Axis.dt;   // =先验估计误差协方差
    Y_Axis.PP[1][0] += Y_Axis.Pdot[2] * Y_Axis.dt;
    Y_Axis.PP[1][1] += Y_Axis.Pdot[3] * Y_Axis.dt;
        
    Y_Axis.Angle_err = AccelY - Y_Axis.angle;  //zk-先验估计
    
    Y_Axis.PCt_0 = Y_Axis.C_0 * Y_Axis.PP[0][0];
    Y_Axis.PCt_1 = Y_Axis.C_0 * Y_Axis.PP[1][0];
    
    Y_Axis.E = Y_Axis.R_angle + Y_Axis.C_0 * Y_Axis.PCt_0;
    
    Y_Axis.K_0 = Y_Axis.PCt_0 / Y_Axis.E;
    Y_Axis.K_1 = Y_Axis.PCt_1 / Y_Axis.E;
    
    Y_Axis.t_0 = Y_Axis.PCt_0;
    Y_Axis.t_1 = Y_Axis.C_0 * Y_Axis.PP[0][1];

    Y_Axis.PP[0][0] -= Y_Axis.K_0 * Y_Axis.t_0;       //后验估计误差协方差
    Y_Axis.PP[0][1] -= Y_Axis.K_0 * Y_Axis.t_1;
    Y_Axis.PP[1][0] -= Y_Axis.K_1 * Y_Axis.t_0;
    Y_Axis.PP[1][1] -= Y_Axis.K_1 * Y_Axis.t_1;
        
    Y_Axis.angle   += Y_Axis.K_0 * Y_Axis.Angle_err;  //后验估计
    Y_Axis.Q_bias  += Y_Axis.K_1 * Y_Axis.Angle_err;  //后验估计
    Y_Axis.angle_dot   = GyroY - Y_Axis.Q_bias;     //输出值(后验估计)的微分=角速度
}

//////////////////////////////////////////////////////////////////////////////////   
//功能 : 主中断的服务函数
//参数 : 无
//返回值 : 无                              
//////////////////////////////////////////////////////////////////////////////////

void MainInterruptIRQ(void)
{
    float cpu_usage = 0;
    //系统监控部分代码
    TimeNow = SystemTimer.read_us();
    if(Flag_MeasureFreq)
    {
        FreqTime = TimeNow;
        FreqCounter = MainInterruptCounter;
        Flag_MeasureFreq = false;
    } 
    if((MainInterruptCounter - FreqCounter) == 100)
    {
        MainInterruptFreq = 100.0 * 1000000 / (TimeNow - FreqTime);
        Flag_MeasureFreq = true;
    }
    MainInterruptCounter++;
    
    
    //temp=MPU_Get_Temperature(); //得到温度值
    MPU_Get_Accelerometer(&aacx,&aacy,&aacz);   //得到加速度传感器数据
    MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);    //得到陀螺仪数据
    if(gyroy>32768)  gyroy-=65536;                       //数据类型转换  也可通过short强制类型转换
    if(gyroz>32768)  gyroz-=65536;                       //数据类型转换
    if(gyrox>32768)  gyrox-=65536;                       //数据类型转换
    if(aacx>32768) aacx-=65536;                      //数据类型转换
    if(aacz>32768) aacz-=65536;                      //数据类型转换
    if(aacy>32768) aacy-=65536;                      //数据类型转换

    ThetaXz=atan2((double)aacy,(double)aacz)*180/PI;  //重力加速度在XOZ、YOZ面上与z轴夹角
    ThetaYz=atan2((double)aacx,(double)aacz)*180/PI;                 //计算倾角   
    gyroy=gyroy/16.4;                                    //陀螺仪量程转换
    gyrox=gyrox/16.4;                                    //陀螺仪量程转换
    Kalman_Filter(ThetaXz,-gyrox, ThetaYz,-gyroy);

    Processing(); //用户进程
    cpu_usage = (float)(SystemTimer.read_us() - TimeNow) / 10000; //计算CPU使用率
    if(cpu_usage > 0)
        CpuUsage = cpu_usage;
}



//////////////////////////////////////////////////////////////////////////////////   
//功能 : 系统初始化
//参数 : 无
//返回值 : 无                              
//////////////////////////////////////////////////////////////////////////////////
void System_Init(void)
{
    SystemTimer.start();

    //TFT.DispInit();
    //TFT.FillScreen(ILI9340_BLACK);
    //TFT.SetRotation(3);
    //TFT.DrawString("System initing......", 50, 120, 3, ILI9340_WHITE);
    
    MPU_Init();
    MainInterrupt.attach(&MainInterruptIRQ, 0.01);
    
    Flag_MeasureFreq = true; //开始一次测量
    
    X_Axis.K1 = 0.02;
    X_Axis.Q_angle=0.001;
    X_Axis.Q_gyro=0.003;
    X_Axis.R_angle=0.5;
    X_Axis.dt=0.005;
    X_Axis.C_0 = 1;
    X_Axis.Pdot[0] = 0;
    X_Axis.Pdot[1] = 0;
    X_Axis.Pdot[2] = 0;
    X_Axis.Pdot[3] = 0;
    X_Axis.PP[0][0]=1;
    X_Axis.PP[0][1]=0;
    X_Axis.PP[1][0]=1;
    X_Axis.PP[1][1]=0;
    
    Y_Axis.K1 = 0.02;
    Y_Axis.Q_angle=0.001;
    Y_Axis.Q_gyro=0.003;
    Y_Axis.R_angle=0.5;
    Y_Axis.dt=0.005;
    Y_Axis.C_0 = 1;
    Y_Axis.Pdot[0] = 0;
    Y_Axis.Pdot[1] = 0;
    Y_Axis.Pdot[2] = 0;
    Y_Axis.Pdot[3] = 0;
    Y_Axis.PP[0][0]=1;
    Y_Axis.PP[0][1]=0;
    Y_Axis.PP[1][0]=1;
    Y_Axis.PP[1][1]=0;
}

//此处--推荐--配置外设、定义全局变量
//-------------------代码块开始

//DigitalOut myled(LED1);
AnalogIn LeftJoystickX(Pin_LeftJoystickX);
AnalogIn LeftJoystickY(Pin_LeftJoystickY);
AnalogIn RightJoystickX(Pin_RightJoystickX);
AnalogIn RightJoystickY(Pin_RightJoystickY);

float LeftJoystickValueX = 0.0, LeftJoystickValueY = 0.0, RightJoystickValueX = 0.0, RightJoystickValueY = 0.0;  //摇杆x,y轴的读数 归一化到 0-1

Servo Servo1(Pin_Servo1);
Servo Servo2(Pin_Servo2);
Servo Servo3(Pin_Servo3);
Servo Servo4(Pin_Servo4);
Servo Servo5(Pin_Servo5);
Servo Servo6(Pin_Servo6);
Servo Servo7(Pin_Servo7);
Servo Servo8(Pin_Servo8);
Servo Servo9(Pin_Servo9);
Servo Servo10(Pin_Servo10);
Servo Servo11(Pin_Servo11);
Servo Servo12(Pin_Servo12);

Serial UserUart(PC_10, PC_11);


//-------------------代码块结束

    int i = 0, j;
        float degree1 =  45.0, degree2 = 135.0;
//////////////////////////////////////////////////////////////////////////////////   
//功能 : 用户进程函数 用于执行用户自定义的后台任务 执行频率是100Hz
//参数 : 无
//返回值 : 无                              
//////////////////////////////////////////////////////////////////////////////////
void Processing(void)
{
    LeftJoystickValueX = LeftJoystickX.read();
    LeftJoystickValueY = LeftJoystickY.read();
    RightJoystickValueX = RightJoystickX.read();
    RightJoystickValueY = RightJoystickY.read();
    if((MainInterruptCounter % 50) == 0)
        {
            if(i == 0)
            {
                i = !i;
                Servo1.SetDegree(degree1);
                Servo2.SetDegree(degree1);
                Servo3.SetDegree(degree1);
                Servo4.SetDegree(degree1);
                Servo5.SetDegree(degree1);
                Servo6.SetDegree(degree1);
                Servo7.SetDegree(degree1);
                Servo8.SetDegree(degree1);
                Servo9.SetDegree(degree1);
                Servo10.SetDegree(degree1);
                Servo11.SetDegree(degree1);
                Servo12.SetDegree(degree1);
            }
            else
            {
                i = !i;
                Servo1.SetDegree(degree2);
                Servo2.SetDegree(degree2);
                Servo3.SetDegree(degree2);
                Servo4.SetDegree(degree2);
                Servo5.SetDegree(degree2);
                Servo6.SetDegree(degree2);
                Servo7.SetDegree(degree2);
                Servo8.SetDegree(degree2);
                Servo9.SetDegree(degree2);
                Servo10.SetDegree(degree2);
                Servo11.SetDegree(degree2);
                Servo12.SetDegree(degree2);
            }
        }
}
 
int main() 
{
    ILI9340_Display TFT = ILI9340_Display(Pin_TFT_MOSI, Pin_TFT_MISO, Pin_TFT_SCLK, Pin_TFT_CS, Pin_TFT_RESET, Pin_TFT_DC); //液晶屏初始化 已知bug 液晶屏类的定义必须在所有DigitalOut类的定义之后否则无法正常工作
    TFT_LED = 1; //点亮TFT背光
    TFT.DispInit();
    TFT.FillScreen(ILI9340_BLACK);
    TFT.SetRotation(3);
    TFT.DrawString("iCenter", 76, 86, 3, ILI9340_WHITE);
    TFT.DrawString("System initing...", 24, 146, 2, ILI9340_WHITE);
    System_Init();
    TFT.DrawString("iCenter", 76, 86, 3, ILI9340_BLACK);
    TFT.DrawString("System initing...", 24, 146, 2, ILI9340_BLACK);
    
    while(true) {    
        printf("CPU Usage : %.2f\r\n", CpuUsage);
        printf("Pitch : %.2f\r\n", Y_Axis.angle);
        printf("Roll : %.2f\r\n", X_Axis.angle);
        printf("LeftJoystickValueX : %.2f\r\n", LeftJoystickValueX);
        printf("LeftJoystickValueY : %.2f\r\n", LeftJoystickValueY);
        printf("RightJoystickValueX : %.2f\r\n", RightJoystickValueX);
        printf("RightJoystickValueY : %.2f\r\n", RightJoystickValueY);
        
        // Small amount of text to the display.
        
        
        // Do the waiting thang...
        wait(0.5);

    }
}