#include "include.h"
void main()
{
WDT_A_hold(WDT_A_BASE);
_DINT(); //禁止所有中断
Hardware_Init();//硬件初始化
_EINT();//使能中断
while (1)
{
PollingKernel();
}
}
void Hardware_Init(void)
{
System_Clock_Init();
I2C_Init(); //IO口模拟IIC时序
Motor_Init();
LEDInit(); //LED灯闪初始化
MPU6050Init(); //g_MPUManager初始化
SPL06_Init(); //SPL06初始化
NRF_Radio_Init();
if(HARDWARE_CHECK) //硬件检测
{
g_LedManager.emLEDPower = PowerOn;
}
gcs_init(); //地面站通信初始化
PID_Init(); //PID参数初始化
USART_Init(USCI_A_UART_CLOCKSOURCE_ACLK,115200);
Timer_Init();
}
/*************************************************************************************
*函数名称:I2C_Init
*函数描述:初始化I2C总线
*输 入:void
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void I2C_Init()
{
//P3.1是SCL时钟
P3DIR |= (1 << SCL); //方向寄存器,P3.1置1,设为输出,看上图
}
//宏定义
#define SCL 1
#define IIC_SDA_Out P3DIR |= BIT0
#define IIC_SDA_In P3DIR &= ~BIT0
#define IIC_SCL_Out P3DIR |= BIT1
##MPU6050的寄存器初始化
/*************************************************************************************
*函数名称:MPU6050Init
*函数描述:g_MPUManager的初始化
*输 入:void
*输 出:g_MPUManager初始化结果
* 0:初始化成功
* 1:初始化失败
*返 回:void
*备 注:null
*
*
*************************************************************************************/
//就是初始化寄存器
bool MPU6050Init(void)
{
uint8_t check =0;
//从机地址B11010000(最后一位是写位),寄存器地址
I2C_Write_Byte(MPU6050_ADDRESS, PWR_MGMT_1, 0x80); //复位
delay_ms(30);
//陀螺仪采样率,0x00(333Hz) //经验总结的333Hz=1000/(1+2)
I2C_Write_Byte(MPU6050_ADDRESS, SMPLRT_DIV, 0x02);
//设置设备时钟源,陀螺仪Z轴
I2C_Write_Byte(MPU6050_ADDRESS, PWR_MGMT_1, 0x03);
//低通滤波频率,0x03(42Hz)
I2C_Write_Byte(MPU6050_ADDRESS, CONFIGL, 0x03);
// +-2000deg/s //陀螺仪量程
I2C_Write_Byte(MPU6050_ADDRESS, GYRO_CONFIG, 0x18);
// +-4g //加速度量程
I2C_Write_Byte(MPU6050_ADDRESS, ACCEL_CONFIG, 0x09);
//0x75寄存器中保存了从机地址
check = I2C_Read_Byte(MPU6050_ADDRESS, 0x75); //判断g_MPUManager地址
if(check != MPU6050_PRODUCT_ID)//如果地址不正确
{
g_MPUManager.Check = false;
return false;
}
else
{
//静止状态下,除了Z轴的加速度g外全都为零
GetMPU6050Offset(); //调用校准数据
g_MPUManager.Check = true;
return true;
}
}
//遵循I2C协议的时序图
void I2C_Write_Byte(uint8_t Slaveaddr, uint8_t REG_Address, uint8_t REG_data)
{
IIC_Start(); //发送起始信号
IIC_SendByte(Slaveaddr); //从机地址B11010000(最后一位是写位)
IIC_SendByte(REG_Address);
IIC_SendByte(REG_data);
IIC_Stop();
}
//宏定义
#define SDA 0
//P3OUT是P3口寄存器
#define IIC P3OUT
void IIC_Start()
{
//P3.0是SDA线
P3DIR |= (1 << SDA); //P3.0置1,设为输出
IIC |= (1 << SDA); //P3.0输出1,SDA高电平
delay(1); //让数据保持一段时间(电平嘛)
IIC |= (1 << SCL); //P3.1输出1,SCL高电平
delay(1); //延时1ms
IIC &= ~(1 << SDA); //P3.0输出0,SDA低电平
delay(1);
IIC &= ~(1 << SCL); //P3.1输出0,SCL低电平 为后面发送地址做准备
//所以将SCL拉低
delay(1);
}
void IIC_SendByte(uint32_t dat)
{
uint32_t i;
P3DIR |= (1 << SDA); //P3.0置1,设为输出
i = 8; //八位数据需要发送
IIC &= ~(1 << SCL); //P3.1输出0,SCL低电平
delay(1); //延时1ms
while(i--)
{
//为啥要从最高位发送呢?规定
if((dat & 0x80) >> 7) //判断最高位是0还是1,然后写入P3.0,写入总线
{
IIC |= (1 << SDA); //P3.0输出1
}
else
{
IIC &= ~(1 << SDA); //P3.0输出0
}
dat <<= 1; //将数据(地址)左移一位
delay(1);
IIC |= (1 << SCL); //P3.1高电平,SCL高电平
delay(1);
IIC &= ~(1 << SCL); //P3.1低电平,SCL低电平,为写下一位数据做准备
delay(1);
}
IIC |= (1 << SDA); //P3.0高电平,SDA高电平
IIC RecvACK(); //等待应答信号
}
/*************************************************************************************
*函数名称:GetMPU6050Offset
*函数描述:获取g_MPUManager静态下传感器偏差
*输 入:void
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void GetMPU6050Offset(void) //校准
{
int32_t buffer[6] = {0};
int16_t i = 0;
uint8_t k = 30;
const int8_t MAX_GYRO_QUIET = 5; //最大最小误差
const int8_t MIN_GYRO_QUIET = -5;
int16_t LastGyro[3] = {0}; //wait for calm down
int16_t ErrorGyro[3] = {0}; //set offset initial to zero
memset(g_MPUManager.Offset,0,12);
g_MPUManager.Offset[2] = 8192; //根据手册量程设定加速度标定值
while(k--) //判断飞控是否处于静止状态
{
do
{
delay_ms(10);
GetMPU6050Data();
for(i=0; i<3; i++)
{
ErrotGyro[i] = pMpu[I + 3] - LastGyro[i];
LastGyro[i] = pMpu[i + 3];
}
}while((ErrorGyro[0] > MAX_GYRO_QUIET)
|| (ErrorGyro[0] < MIN_GYRO_QUIET)
|| (ErrorGyro[1] > MAX_GYRO_QUIET)
|| (ErrorGyro[1] < MIN_GYRO_QUIET)
|| (ErrorGyro[2] > MAX_GYRO_QUIET)
|| (ErrorGyro[2] < MIN_GYRO_QUIET));
//在误差范围内,认为静止的,退出循环,不在的话则是运动的,死循环
}
for(i=0; i<356; i++) //取第100到第356组的平均值作为校准值
{
}
}
/*************************************************************************************
*函数名称:GetMPU6050Data
*函数描述:读取陀螺仪和加速度计的数据并做滤波处理
*输 入:void
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void GetMPU6050Data(void)
{
uint8_t buffer[12];
const float factor = 0.15f; //滤波因素
static float tBuff[3] = {0};
static EKF_Filter_t s_EKF[3] = {{0.02, 0, 0, 0, 0.001, 0.543},
{0.02, 0, 0, 0, 0.001, 0.543},
{0.02, 0, 0, 0, 0.001, 0.543}};
Acc_Read(buffer);
Gyro_Read(buffer);
for(int i=0; i<6; i++) //将buffer中的高八位和低八位合起来
{
pMpu[i] = (((int16_t)buffer[i << 1] << 8) | buffer[(i << 1) + 1]) //
- g_MPUManager.Offset[i];
//此处对加速度做一维卡尔曼滤波
if(i<3)
{
KalmanFilter(&s_EKF[i],(float)pMpu[i]); //一维卡尔曼
pMpu[i] = (int16_t)s_EKF[i].out;
}
//此处对角速度做一阶低通滤波
if(i>2)
{
uint8_t k = i - 3;
pMpu[i] = (int16_t)(tBuff[k] * (1 - factor) + pMpu[i] * factor);
tBuff[k] = tBuff[k] * (1 - factor) + pMpu[i] * factor;
}
}
}
//私有变量区
MPU6050Manager_t g_MPUManager; //g_MPUManager原始数据
int16_t *pMpu = (int16_t *)&g_MPUManager;
typedef struct
{
int16_t accX;
int16_t accY;
int16_t accZ;
int16_t gyroX;
int16_t gyroY;
int16_t gyroZ;
int16_t Offset[6];
bool Check;
}MPU6050Manager_t;
##Acc_Read
/*************************************************************************************
*函数名称:Acc_Read
*函数描述:获取加速度值
*输 入:uint8_t *ptr ,写入地址
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void Acc_Read(uint8_t *ptr)
{
for(int i=0; i<6; i++)
{
//0xD0,就是MPU6050从机地址
ptr[i] = I2C_Read_Byte(0xD0,0x3B+i);
}
}
##Gyro_Read
/*************************************************************************************
*函数名称:Gyro_Read
*函数描述:获取陀螺仪值
*输 入:uint8_t *ptr ,写入地址
*输 出:void
*返 回:void
*备 注:null
*
*
*************************************************************************************/
void Gyro_Read(uint8_t *ptr)
{
for(int i=0; i<6; i++)
{
//0xD0,就是MPU6050从机地址
ptr[i+6] = I2C_Read_Byte(0xD0,0x43+i);
}
}