打印
[四轴原创DIY]

召集小伙伴们DIY自己的微型四轴飞行器(STM32主控)

[复制链接]
楼主: mohanwei
手机看帖
扫描二维码
随时随地手机跟帖
81
mohanwei|  楼主 | 2014-12-10 20:53 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
气压传感器MS5611的I2C接口改为IO模拟方式。温湿度传感器就忽略了,在这个四轴上其实不是必须的,只是我看板子会比较多,临时加上,到时候就当做一块锂电+MCU+2.4G+温湿度的无线传感器板,可以通过电脑监测一下室外温湿度而已……

首先是I2C底层驱动。I2C说简单也简单,对照I2C规范写一下就行了;说难也难,我都不知道给客户反复解决过多少这方面的使用问题了……
这份代码是根据I2C规范V2.1来写的,精简了一下,只有7bit地址模式(现实中绝大部分都是这种模式),速率可配置,从几KHz到十几MHz。时序经过逻辑分析仪抓包能跟规范吻合。只要改5个宏定义,就可以移植到其他MCU

I2C_Soft_IO_Lib.c

/***************************************************************************
程序名称:I2C驱动程序(软件模拟I2C总线方式)
程序功能:提供I2C总线底层操作,如起始位、停止位、发送数据、接收数据等
程序作者:莫汉伟
Email:   amo73@126.com
修改日期:2005-10-3
程序版本:V1.0
作者声明:本软件完全免费,但引用时需保留以上信息
****************************************************************************/
#include "includes.h" //本工程其他头文件集合
#include "I2C_Soft_IO_Lib.h" //I2C驱动库IO定义、函数声明等

//移植步骤:
/*
1-在外部定义以下5个操作
Clr_SCL_0()//拉低SCL(宏定义或函数)
Set_SCL_1()//拉高SCL(宏定义或函数)
Clr_SDA_0()//拉低SDA(宏定义或函数)
Set_SDA_1()//拉高SDA(宏定义或函数)
Read_SDA()//读取SDA(宏定义或函数)

2-定义精密延时函数(或宏定义):void delay_us(volatile u32 us)
  可在某地方延时固定时间并翻转某个IO,用示波器查看实际延时,如不符合则调整参数

3-上电后初始化SDA和SCL这两个IO为开漏输出(硬件接4.7K-10K上拉电阻)
*/

//以下是参考的delay_us()函数。但我们这个工程里已经在其它地方定义了,所以这里屏蔽掉
//void delay_us(volatile u32 us)//STM32在72MHz下大约相当于1us
//{
//        volatile u32 i;
//        while(us--)
//        {
//                i=15;
//                while(i--)
//                        ;
//        }
//}
//#define I2C_DELAY() delay_us(20) //2.4G Model。允许的时钟速率比较低,不超过25KHz
#define I2C_DELAY()  //MS5611允许20MHz的时钟速率,而STM32全速翻转也不超过18MHz,所以无需延迟

//I2C主机发出“起始条件”
void I2C_Start(void)
{//起始条件:在SCL为1时,产生SDA下降沿
    I2C_DELAY();//空闲时SCL和SDA都是1,所以只需拉低SDA即可
    Clr_SDA_0();
    I2C_DELAY();
}
//I2C主机发出“重复起始条件”
void I2C_RepeatStart(void)
{//重复起始条件:在SCL为1时,产生SDA下降沿
    Clr_SCL_0();//确保在SCL为低时,SDA才能改变(这里要初始化SDA为1)
        Set_SDA_1();
        I2C_DELAY();
        Set_SCL_1();
    I2C_DELAY();
    Clr_SDA_0();
    I2C_DELAY();
}

//I2C主机发出“停止条件”
void I2C_Stop(void)
{//停止条件:在SCL为1时,产生SDA上升沿
    Clr_SCL_0();
    Clr_SDA_0();
        I2C_DELAY();
    Set_SCL_1();
    I2C_DELAY();
    Set_SDA_1();
    I2C_DELAY();
}

//I2C主机读取从机的应答位(直接返回SDA的电平):
unsigned char I2C_Rec_Ack(void)
{
        unsigned char i;
    unsigned char Ack;
    Clr_SCL_0();//拉低SCL,此时从机输出ACK/NAK
    Set_SDA_1();//释放SDA
        I2C_DELAY();
    Set_SCL_1();//SCL高电平期间,SDA必须保持不变
        I2C_DELAY();
    Ack=Read_SDA();
    Clr_SCL_0();//从机会在此进入中断,中断期间会自动拉低SCL,直到处理完成
        //主机按理应该在此释放SDA,并检测SDA,直到变高(说明从机已经处理完成),才允许返回
        for(i=0;i<255;i++)
        {
                if(Read_SDA())//等待SDA变高
                        break;
        }
        return(Ack);
}

//I2C主机向从机发出“应答”:
void I2C_ACK(void)
{
        Clr_SCL_0();//拉低SCL
        Clr_SDA_0();//送出ACK到SDA
        I2C_DELAY();
    Set_SCL_1();//产生SCL上升沿,通知从机读取
    I2C_DELAY();
        //以下3行可去掉。
    Clr_SCL_0();
    I2C_DELAY();
    Set_SDA_1();//释放SDA
}

//I2C主机向从机发出“不应答”:
void I2C_NAK(void)
{
        Clr_SCL_0();//拉低SCL
    Set_SDA_1();//送出NAK到SDA
        I2C_DELAY();
    Set_SCL_1();//产生SCL上升沿,通知从机读取
    I2C_DELAY();
}

//I2C主机发送1字节数据:
void I2C_Send_Byte(unsigned char sendbyte)
{
    unsigned char i=8;
    while(i--)
    {
        Clr_SCL_0();
        if(sendbyte & 0x80)
        {
            Set_SDA_1();
        }
        else
        {
            Clr_SDA_0();
        }
        I2C_DELAY();
        Set_SCL_1();
        sendbyte<<=1;   //左移1位
                I2C_DELAY();
    }
}

//I2C主机读取1字节数据:
unsigned char I2C_Receive_Byte(void)
{
        unsigned char receive_byte=0,i=8;
    while(i--)
    {
                Clr_SCL_0();//SCL低电平期间,从机送出数据到SDA
                I2C_DELAY();
        Set_SCL_1();//拉高SCL,是SDA保持
                I2C_DELAY();
        receive_byte=(receive_byte<<1) | Read_SDA();
    }
    return(receive_byte);
}


I2C_Soft_IO_Lib.h

#ifndef _I2C_Soft_IO_Lib_h_
#define _I2C_Soft_IO_Lib_h_

        //SCL和SDA的操作:(这里是STM32,用其他MCU时需要修改一下)
//        #define Clr_SDA_0()                        GPIO_ResetBits(Port_I2C2_SDA, Pin_I2C2_SDA)
//        #define Set_SDA_1()                            GPIO_SetBits(Port_I2C2_SDA, Pin_I2C2_SDA);
//        #define Clr_SCL_0()                        GPIO_ResetBits(Port_I2C2_SCL, Pin_I2C2_SCL)
//        #define Set_SCL_1()                            GPIO_SetBits(Port_I2C2_SCL, Pin_I2C2_SCL);
//        #define Read_SDA()                  GPIO_ReadInputDataBit(Port_I2C2_SDA,Pin_I2C2_SDA)//读取SDA

        void I2C_Start(void);
        void I2C_RepeatStart(void);
        void I2C_Stop(void);
        unsigned char  I2C_Rec_Ack(void);
        void I2C_NAK(void);
        void I2C_ACK(void);
        unsigned char I2C_Receive_Byte(void);
        void I2C_Send_Byte(unsigned char sendbyte);
       
#endif

使用特权

评论回复
82
mohanwei|  楼主 | 2014-12-10 21:00 | 只看该作者
本帖最后由 mohanwei 于 2014-12-19 22:37 编辑

MS5611的I2C版驱动,I2C底层操作接口基于上一贴的驱动库
这份代码结构不尽合理,但是为了不做大改动,先只是在作者的基础上把SPI读写改为I2C,等飞机飞稳后,下一次迭代再改进。

MS5611.c
改动:2014-12-19 调试时发现MS5611无法读取,观察波形发现是发送起始位、从地址后,MS5611没有发出应答,核实手册,发现是原先对CSB的理解有误……从地址的bit1应该是CSB的反码。修改后(参考下面代码的红色字体部分)可以正常读取温度和气压,用手指摸MS5611,能看到温度值升高几度,拿开手指过一会温度又会降下来,说明IC正常工作了。

#define DEBUG_MODULE "MS5611"
#include "includes.h"
/*
COMMANDS
The MS5611-01BA has only five basic commands:
1. Reset
2. Read PROM (128 bit of calibration words)
3. D1 conversion
4. D2 conversion
5. Read ADC result (24 bit pressure / temperature)


*/
//在我们的电路里,MS5611的CSB接地,bit1为CSB的反码,所以I2C从地址为1110 111x(x为读写标记):
#define MS5611_ReadAddr        0xEF //从地址+读标记
#define MS5611_WriteAddr    0xEE //从地址+写标记


#define EXTRA_PRECISION      5 // trick to add more precision to the pressure and temp readings
#define MS5611_CONVERSION_TIME_MS   10 // conversion time in milliseconds. 10 is minimum
#define PRESSURE_PER_TEMP 5 // Length of reading cycle: 1x temp, rest pressure. Good values: 1-10
#define FIX_TEMP 25         // Fixed Temperature. ASL is a function of pressure and temperature, but as the temperature changes so much (blow a little towards the flie and watch it drop 5 degrees) it corrupts the ASL estimates.
                            // TLDR: Adjusting for temp changes does more harm than good.

typedef struct
{
  uint16_t psens;
  uint16_t off;
  uint16_t tcs;
  uint16_t tco;
  uint16_t tref;
  uint16_t tsens;
} CalReg;

//static uint8_t devAddr;
//static I2C_TypeDef *I2Cx;
static bool isInit;

static CalReg   calReg;
static uint32_t lastPresConv;
static uint32_t lastTempConv;
static int32_t  tempCache;

static uint8_t readState=0;
static uint32_t lastConv=0;
static int32_t tempDeltaT;

bool ms5611Init(void)
{
  if (isInit)
    return TRUE;

  ms5611Reset(); // reset the device to populate its internal PROM registers
  vTaskDelay(M2T(5));
  if (ms5611ReadPROM() == FALSE) // reads the PROM into object variables for later use
  {
    return FALSE;
  }

  isInit = TRUE;

  return TRUE;
}

bool ms5611SelfTest(void)
{
  bool testStatus = TRUE;
  int32_t rawPress;
  int32_t rawTemp;
  int32_t deltaT;
  float pressure;
  float temperature;

  if (!isInit)
    return FALSE;

  ms5611StartConversion(MS5611_D1 + MS5611_OSR_4096);
  vTaskDelay(M2T(MS5611_CONVERSION_TIME_MS));
  rawPress = ms5611GetConversion(MS5611_D1 + MS5611_OSR_4096);

  ms5611StartConversion(MS5611_D2 + MS5611_OSR_4096);
  vTaskDelay(M2T(MS5611_CONVERSION_TIME_MS));
  rawTemp = ms5611GetConversion(MS5611_D2 + MS5611_OSR_4096);

  deltaT = ms5611CalcDeltaTemp(rawTemp);
  temperature = ms5611CalcTemp(deltaT);
  pressure = ms5611CalcPressure(rawPress, deltaT);

  if (ms5611EvaluateSelfTest(MS5611_ST_PRESS_MIN, MS5611_ST_PRESS_MAX, pressure, "pressure") &&
      ms5611EvaluateSelfTest(MS5611_ST_TEMP_MIN, MS5611_ST_TEMP_MAX, temperature, "temperature"))
  {
    DEBUG_PRINT("Self test [OK].\n");
  }
  else
  {
   testStatus = FALSE;
  }

  return testStatus;
}

bool ms5611EvaluateSelfTest(float min, float max, float value, char* string)
{
  if (value < min || value > max)
  {
    DEBUG_PRINT("Self test %s [FAIL]. low: %0.2f, high: %0.2f, measured: %0.2f\n",
                string, min, max, value);
    return FALSE;
  }
  return TRUE;
}

float ms5611GetPressure(uint8_t osr)
{
  // see datasheet page 7 for formulas
  int32_t rawPress;
  int64_t dT, off, sens;

  rawPress = ms5611RawPressure(osr);
  dT = (int64_t)ms5611GetDeltaTemp(osr);
  if (dT == 0)
  {
    return 0;
  }
  off = (((int64_t)calReg.off) << 16) + ((calReg.tco * dT) >> 7);
  sens = (((int64_t)calReg.psens) << 15) + ((calReg.tcs * dT) >> 8);
  if (rawPress != 0)
  {
    return ((((rawPress * sens) >> 21) - off) >> (15 - EXTRA_PRECISION))
        / ((1 << EXTRA_PRECISION) * 100.0);
  }
  else
  {
    return 0;
  }
}

float ms5611CalcPressure(int32_t rawPress, int32_t dT)
{
  int64_t off;
  int64_t sens;

  if (rawPress == 0 || dT == 0)
  {
    return 0;
  }

  off = (((int64_t)calReg.off) << 16) + ((calReg.tco * (int64_t)dT) >> 7);
  sens = (((int64_t)calReg.psens) << 15) + ((calReg.tcs * (int64_t)dT) >> 8);

  return ((((rawPress * sens) >> 21) - off) >> (15 - EXTRA_PRECISION))
          / ((1 << EXTRA_PRECISION) * 100.0);
}

float ms5611GetTemperature(uint8_t osr)
{
  // see datasheet page 7 for formulas
  int32_t dT;

  dT = ms5611GetDeltaTemp(osr);
  if (dT != 0)
  {
    return ms5611CalcTemp(dT);
  }
  else
  {
    return 0;
  }
}

int32_t ms5611GetDeltaTemp(uint8_t osr)
{
  int32_t rawTemp = ms5611RawTemperature(osr);
  if (rawTemp != 0)
  {
    return ms5611CalcDeltaTemp(rawTemp);
  }
  else
  {
    return 0;
  }
}

float ms5611CalcTemp(int32_t deltaT)
{
  if (deltaT == 0)
  {
    return 0;
  }
  else
  {
    return (float)(((1 << EXTRA_PRECISION) * 2000)
            + (((int64_t)deltaT * calReg.tsens) >> (23 - EXTRA_PRECISION)))
            / ((1 << EXTRA_PRECISION)* 100.0);
  }
}

int32_t ms5611CalcDeltaTemp(int32_t rawTemp)
{
  if (rawTemp == 0)
  {
    return 0;
  }
  else
  {
    return rawTemp - (((int32_t)calReg.tref) << 8);
  }
}

int32_t ms5611RawPressure(uint8_t osr)
{
  uint32_t now = xTaskGetTickCount();
  if (lastPresConv != 0 && (now - lastPresConv) >= MS5611_CONVERSION_TIME_MS)
  {
    lastPresConv = 0;
    return ms5611GetConversion(MS5611_D1 + osr);
  }
  else
  {
    if (lastPresConv == 0 && lastTempConv == 0)
    {
      ms5611StartConversion(MS5611_D1 + osr);
      lastPresConv = now;
    }
    return 0;
  }
}

int32_t ms5611RawTemperature(uint8_t osr)
{
  uint32_t now = xTaskGetTickCount();
  if (lastTempConv != 0 && (now - lastTempConv) >= MS5611_CONVERSION_TIME_MS)
  {
    lastTempConv = 0;
    tempCache = ms5611GetConversion(MS5611_D2 + osr);
    return tempCache;
  }
  else
  {
    if (lastTempConv == 0 && lastPresConv == 0)
    {
      ms5611StartConversion(MS5611_D2 + osr);
      lastTempConv = now;
    }
    return tempCache;
  }
}

// see page 11 of the datasheet
bool ms5611StartConversion(uint8_t command)
{
        bool result = FALSE;//预置执行结果为:失败
        I2C_Start();//起始条件
        I2C_Send_Byte(MS5611_WriteAddr);//发送从地址+写标记
        if(I2C_Rec_Ack()==0)//收到应答
        {
                I2C_Send_Byte(command);//发送启动转换命令
            if(I2C_Rec_Ack()==0)//收到应答
                {
                        result = TRUE;//成功
                }
        }
    I2C_Stop();//停止条件
        return(result);
}

int32_t ms5611GetConversion(uint8_t command)
{
        int32_t conversion = 0;
//        uint8_t buffer[MS5611_D1D2_SIZE];
        bool result = FALSE;//预置执行结果为:失败
        // start read sequence
        I2C_Start();//起始条件
        I2C_Send_Byte(MS5611_WriteAddr);//发送从地址+写标记
        if(I2C_Rec_Ack()==0)//收到应答
        {
                I2C_Send_Byte(0x00);//发送读取ADC命令
            if(I2C_Rec_Ack()==0)//收到应答
                {
                        result = TRUE;//成功
                }
        }
    I2C_Stop();//停止条件
//        i2cdevWriteByte(I2Cx, devAddr, I2CDEV_NO_MEM_ADDR, 0);
        
        // Read conversion
        if(result)
        {
                result = _Fail;//预置执行结果为:失败
                I2C_Start();//起始条件
                I2C_Send_Byte(MS5611_ReadAddr);//发送从地址+读标记
                if(I2C_Rec_Ack()==0)//收到应答
                {
                        conversion = ((u32)I2C_Receive_Byte())<<16;//读取24位数据的高字节
                        I2C_ACK();//送出ACK
                        conversion += ((u32)I2C_Receive_Byte())<<8;//读取24位数据的中字节
                        I2C_ACK();//送出ACK
                        conversion += ((u32)I2C_Receive_Byte())<<0;//读取24位数据的低字节
                        I2C_NAK();//送出NAK
                        result = TRUE;//成功
                }
                I2C_Stop();//停止条件
        }
        
//        i2cdevRead(I2Cx, devAddr, I2CDEV_NO_MEM_ADDR, MS5611_D1D2_SIZE, buffer);
//        conversion = ((int32_t)buffer[0] << 16) |
//                           ((int32_t)buffer[1] << 8) | buffer[2];
        return conversion;
}

/**
* Reads factory calibration and store it into object variables.
*/
bool ms5611ReadPROM(void)//从MS5611读取出厂校准值
{
        uint16_t* pCalRegU16 = (uint16_t*)&calReg;
        int32_t i = 0;
        bool result = FALSE;//预置执行结果为:失败

        for (i = 0; i < MS5611_PROM_REG_COUNT; i++)
        {
                //第1步:设置MS5611进入“读PROM”模式:
                result = _Fail;//预置执行结果为:失败
                I2C_Start();//起始条件
                I2C_Send_Byte(MS5611_WriteAddr);//发送从地址+写标记
                if(I2C_Rec_Ack()==0)//收到应答
                {
                        I2C_Send_Byte(MS5611_PROM_BASE_ADDR + (i * MS5611_PROM_REG_SIZE));//发送读PROM命令
                        if(I2C_Rec_Ack()==0)//收到应答
                        {
                                result = TRUE;//成功
                        }
                }
                I2C_Stop();//停止条件
                //第2步:读取校准值:
                if(result)
                {
                        result = _Fail;//预置执行结果为:失败
                        I2C_Start();//起始条件
                        I2C_Send_Byte(MS5611_ReadAddr);//发送从地址+读标记
                        if(I2C_Rec_Ack()==0)//收到应答
                        {
                                pCalRegU16 = I2C_Receive_Byte();//读取16位数据的高字节
                                I2C_ACK();//送出ACK
                                pCalRegU16 <<= 8;
                                pCalRegU16 += I2C_Receive_Byte();//读取16位数据的低字节
                                I2C_NAK();//送出NAK
                                result = TRUE;//成功
                        }
                        I2C_Stop();//停止条件
                }
        }

  return result;
}

/**
* Send a reset command to the device. With the reset command the device
* populates its internal registers with the values read from the PROM.
*/
bool ms5611Reset(void)//向MS5611发送复位命令
{
        bool result = FALSE;//预置执行结果为:失败
        I2C_Start();//起始条件
        I2C_Send_Byte(MS5611_WriteAddr);//发送从地址+写标记
        if(I2C_Rec_Ack()==0)//收到应答
        {
                I2C_Send_Byte(MS5611_CMD_RESET);//发送复位命令
            if(I2C_Rec_Ack()==0)//收到应答
                {
                        result = TRUE;//成功
                }
        }
    I2C_Stop();//停止条件
        return(result);
}




/**
* Gets pressure, temperature and above sea level altitude estimate (asl).
* Best called at 100hz. For every PRESSURE_PER_TEMP-1 pressure readings temp is read once.
* Effective 50-90hz baro update and 50-10hz temperature update if called at 100hz.
*/
void ms5611GetData(float* pressure, float* temperature, float* asl)
{
    int32_t tempPressureRaw, tempTemperatureRaw;

    // Dont reader faster than we can
    uint32_t now = xTaskGetTickCount();
    if ((now - lastConv) < MS5611_CONVERSION_TIME_MS)
    {
        return;
    }
    lastConv = now;

    if (readState == 0)
    {
        // read temp
        ++readState;
        tempTemperatureRaw = ms5611GetConversion(MS5611_D2 + MS5611_OSR_DEFAULT);
        tempDeltaT = ms5611CalcDeltaTemp(tempTemperatureRaw);
        *temperature = ms5611CalcTemp(tempDeltaT);
        // cmd to read pressure
        ms5611StartConversion(MS5611_D1 + MS5611_OSR_DEFAULT);
    }
    else
    {
        // read pressure
        ++readState;
        tempPressureRaw = ms5611GetConversion(MS5611_D1 + MS5611_OSR_DEFAULT);
        *pressure = ms5611CalcPressure(tempPressureRaw, tempDeltaT);
        *asl = ms5611PressureToAltitude(pressure);
        if (readState == PRESSURE_PER_TEMP){
            // cmd to read temp
            ms5611StartConversion(MS5611_D2 + MS5611_OSR_DEFAULT);
            readState = 0;
        }
        else
        {
            // cmd to read pressure
            ms5611StartConversion(MS5611_D1 + MS5611_OSR_DEFAULT);
        }
    }
}

//TODO: pretty expensive function. Rather smooth the pressure estimates and only call this when needed

/**
* Converts pressure to altitude above sea level (ASL) in meters
*/
float ms5611PressureToAltitude(float* pressure/*, float* ground_pressure, float* ground_temp*/)
{
    if (*pressure > 0)
    {
        //return (1.f - pow(*pressure / CONST_SEA_PRESSURE, CONST_PF)) * CONST_PF2;
        //return ((pow((1015.7 / *pressure), CONST_PF) - 1.0) * (25. + 273.15)) / 0.0065;
        return ((pow((1015.7 / *pressure), CONST_PF) - 1.0) * (FIX_TEMP + 273.15)) / 0.0065;
    }
    else
    {
        return 0;
    }
}

使用特权

评论回复
83
fengyefeng| | 2014-12-10 23:56 | 只看该作者
能不能上传一下AD版的原理图呀,谢谢了

使用特权

评论回复
84
mohanwei|  楼主 | 2014-12-11 13:40 | 只看该作者
fengyefeng 发表于 2014-12-10 23:56
能不能上传一下AD版的原理图呀,谢谢了

你好,如果你熟悉软件,两三个小时就能画好;如果不熟悉,画好就熟悉了....呵呵

使用特权

评论回复
85
ljj0736| | 2014-12-11 13:53 | 只看该作者
学习中,持续关注

使用特权

评论回复
86
张瑜明| | 2014-12-12 23:33 | 只看该作者
学生党一枚,想课余时间学习做一个,能不能帮忙给点资料。184870598@qq.com

使用特权

评论回复
87
mohanwei|  楼主 | 2014-12-13 22:41 | 只看该作者
张瑜明 发表于 2014-12-12 23:33
学生党一枚,想课余时间学习做一个,能不能帮忙给点资料。

我也想要啊……

使用特权

评论回复
88
mohanwei|  楼主 | 2014-12-13 22:54 | 只看该作者
强忍不适,把BMX055的手册粗看一遍,没记住什么东西……只要从顶层开始,先看看系统原先都对MPU6050做了哪些操作,搜一下:
查找 'mpu6050' 于 '\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c' :
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(40): #include "mpu6050.h"
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(126):   mpu6050Init(I2C1);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(127):   if (mpu6050Test() == TRUE)
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(136):   mpu6050Reset();
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(138):   mpu6050SetSleepEnabled(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(139):   mpu6050SetTempSensorEnabled(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(140):   mpu6050SetIntEnabled(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(141):   mpu6050SetI2CBypassEnabled(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(142):   mpu6050SetClockSource(MPU6050_CLOCK_PLL_XGYRO);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(143):   mpu6050SetFullScaleGyroRange(IMU_GYRO_FS_CFG);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(144):   mpu6050SetFullScaleAccelRange(IMU_ACCEL_FS_CFG);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(145):   mpu6050SetRate(15);  // 8000 / (1 + 15) = 500Hz
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(146):   mpu6050SetDLPFMode(MPU6050_DLPF_BW_256);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(208):       mpu6050GetMotion6(&accelMpu.x, &accelMpu.y, &accelMpu.z, &gyroMpu.x, &gyroMpu.y, &gyroMpu.z);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(218):     mpu6050SetGyroXSelfTest(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(219):     mpu6050SetGyroYSelfTest(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(220):     mpu6050SetGyroZSelfTest(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(221):     mpu6050SetAccelXSelfTest(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(222):     mpu6050SetAccelYSelfTest(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(223):     mpu6050SetAccelZSelfTest(TRUE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(226):     mpu6050GetMotion6(&accelMpu.x, &accelMpu.y, &accelMpu.z, &gyroMpu.x, &gyroMpu.y, &gyroMpu.z);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(234):     mpu6050SetGyroXSelfTest(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(235):     mpu6050SetGyroYSelfTest(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(236):     mpu6050SetGyroZSelfTest(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(237):     mpu6050SetAccelXSelfTest(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(238):     mpu6050SetAccelYSelfTest(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(239):     mpu6050SetAccelZSelfTest(FALSE);
\bitcraze-crazyflie-firmware-26d661941c7e\hal\src\imu.c(283):   mpu6050GetMotion6(&accelMpu.x, &accelMpu.y, &accelMpu.z, &gyroMpu.x, &gyroMpu.y, &gyroMpu.z);
已找到 'mpu6050' 28 次。

似乎也不是很复杂,复位、初始化、校准,读取传感器数据……只需要对照着手册做一下填空题。
而且还没用到DMP——这也算是一个好消息吧。

使用特权

评论回复
89
张瑜明| | 2014-12-14 11:03 | 只看该作者
mohanwei 发表于 2014-12-13 22:41
我也想要啊……

这水好深的说。。。

使用特权

评论回复
90
mohanwei|  楼主 | 2014-12-14 16:06 | 只看该作者
张瑜明 发表于 2014-12-14 11:03
这水好深的说。。。

还真是挺深的,如果自己做,硬件、软件相关知识的筹备一般人从无到有得花个两年吧;如果是组装,建议搜一下“MWC”(还有很多QQ群可以交流),邮购成品飞控板、下载线、机架、电机、螺旋桨、电池、遥控器……自己摸索一下可能两天就能飞起来了。

使用特权

评论回复
91
张瑜明| | 2014-12-14 23:28 | 只看该作者
mohanwei 发表于 2014-12-14 16:06
还真是挺深的,如果自己做,硬件、软件相关知识的筹备一般人从无到有得花个两年吧;如果是组装,建议搜一 ...

看来最后还是要问老师。。悲剧

使用特权

评论回复
92
mohanwei|  楼主 | 2014-12-19 22:40 | 只看该作者
调试到MS5611,发现无法通信,原来是从地址搞错了,bit1应该是CSB的反码,需要改正:
//在我们的电路里,MS5611的CSB接地,bit1为CSB的反码,所以I2C从地址为1110 111x(x为读写标记):
#define MS5611_ReadAddr        0xEF //从地址+读标记
#define MS5611_WriteAddr    0xEE //从地址+写标记

使用特权

评论回复
93
kyzb001| | 2014-12-20 16:13 | 只看该作者
本帖最后由 kyzb001 于 2014-12-20 16:21 编辑

楼主,你有QQ群?  要不我建各QQ群,  我参照官方的自己画了一块, 正调着呢。遇到config_block这个东西来

1、这东西处理版本,通信设置之外。 就是做ACC修正  也就这个函数imuAccAlignToGravity.

  cosPitch = cos(configblockGetCalibPitch() * M_PI/180);
  sinPitch = sin(configblockGetCalibPitch() * M_PI/180);
  cosRoll = cos(configblockGetCalibRoll() * M_PI/180);
  sinRoll = sin(configblockGetCalibRoll() * M_PI/180);

不知道你知道,这几个是干嘛用的吗。  设置为0  可以?

使用特权

评论回复
94
kyzb001| | 2014-12-20 16:21 | 只看该作者


   

ZMVV9(O{)MMHU4G$}]KWD(S.jpg (401.89 KB )

ZMVV9(O{)MMHU4G$}]KWD(S.jpg

使用特权

评论回复
95
mohanwei|  楼主 | 2014-12-20 17:37 | 只看该作者
kyzb001 发表于 2014-12-20 16:13
楼主,你有QQ群?  要不我建各QQ群,  我参照官方的自己画了一块, 正调着呢。遇到config_block这个东西来
...

已有群。

你如果硬件不变,软件也是不需要改动的。甚至直接下载编译好的固件就可以——这样可以先排除硬件故障,后面再自己搭建工具链尝试优化和改进功能。
从configblock.c的源码看,如果没有在烧录固件时直接预置参数,那么上电后校验肯定失败,一旦失败,这份代码就会采取默认值,似乎默认值都是设为0……
configblockGetCalibPitch()//俯仰角校准值
configblockGetCalibRoll()//横滚角校准值

使用特权

评论回复
96
fengyefeng| | 2014-12-21 23:59 | 只看该作者
mohanwei 发表于 2014-12-11 13:40
你好,如果你熟悉软件,两三个小时就能画好;如果不熟悉,画好就熟悉了....呵呵 ...

软件只是个工具,熟是熟,不清楚原理是没法动手画的

使用特权

评论回复
97
mohanwei|  楼主 | 2014-12-22 14:21 | 只看该作者
fengyefeng 发表于 2014-12-21 23:59
软件只是个工具,熟是熟,不清楚原理是没法动手画的

原理是比较简单的吧,I2C/SPI接口挂几个传感器,IO口控制几个LED,PWM控制4个电机……
前面也有原理图

使用特权

评论回复
98
大秦正声| | 2014-12-22 14:30 | 只看该作者
很不错

使用特权

评论回复
99
qaz83| | 2014-12-28 12:35 | 只看该作者
这个可以有啊。mark

使用特权

评论回复
100
我爱你的吻123| | 2014-12-28 13:39 | 只看该作者
楼主要是花时间作出小四轴了出来了,不知道能不能开源。把全部的文件上传。这样对于后来者来说也是一个福利,鼓励一下后来者吧。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则