注册 登录
查看: 618|回复: 3

kl26 mma8452

[复制链接]
发表于 2014-12-26 20:37:00 | 显示全部楼层 |阅读模式
为什么用 kl26 调试mma8452 收不到数据 用who_am_i 返回的 都是 -1
代码如下




void main(void)
{
    printf("\n\n\n***********三轴加速度测试************");
   //uart_init(UART0,9600);
    mma7455_init();

    while(1)
    {
        //注意:读取的结果需要校准的,否则不准的。
        //校准方法请看文档,此处仅讲解通信驱动
       printf("\n\nx:%d"
               ,(int8)mma7455_read_reg(MMA8452_WHO_AM_I)       //读取x轴参数
             //  ,(int8)mma7455_read_reg(MMA7455_YOUT8)       //读取y轴参数
              // ,(int8)mma7455_read_reg(MMA7455_ZOUT8)       //读取z轴参数
               );
          //printf("\n\nx:%d,y:%d,z:%d",(int8)mma7455_read_reg(MMA8452_WHO_AM_I));
        DELAY_MS(500);
    }
}

这是i2c.c
#include "common.h"
#include "MKL_port.h"
#include "MKL_i2c.h"

unsigned char MasterTransmission;
unsigned char SlaveID;

I2C_MemMapPtr I2CN[2] = {I2C0_BASE_PTR, I2C1_BASE_PTR}; //定义两个指针数组保存 I2CN 的地址


/*
*  把I2C通信的每个小步骤都用宏定义来实现,方便编写顶层函数
*  此宏定义参考飞思卡尔公司例程修改所得
*/
//启动信号
#define i2c_Start(I2Cn)             I2C_C1_REG(I2CN[I2Cn]) |= (I2C_C1_TX_MASK );I2C_C1_REG(I2CN[I2Cn]) |= ( I2C_C1_MST_MASK)     //MST 由0变1,产生起始信号,TX = 1 进入发送模式

//停止信号
#define i2c_Stop(I2Cn)              I2C_C1_REG(I2CN[I2Cn]) &= ~(I2C_C1_MST_MASK );I2C_C1_REG(I2CN[I2Cn]) &= ~(I2C_C1_TX_MASK) ;   //MST 由1变0,产生停止信号,TX = 0 进入接收模式

//重复启动
#define i2c_RepeatedStart(I2Cn)     I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_RSTA_MASK

//进入接收模式(应答,需要接收多个数据,接收最后一个字节前需要禁用应答i2c_DisableAck)
#define i2c_EnterRxMode(I2Cn)       I2C_C1_REG(I2CN[I2Cn]) &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK)  //

//进入接收模式(不应答,只接收一个字节)
#define i2c_PutinRxMode(I2Cn)       I2C_C1_REG(I2CN[I2Cn]) &= ~I2C_C1_TX_MASK;I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_TXAK_MASK

//禁用应答(接收最后一个字节)
#define i2c_DisableAck(I2Cn)        I2C_C1_REG(I2CN[I2Cn]) |= I2C_C1_TXAK_MASK

//等待 I2C_S
#define i2c_Wait(I2Cn)              while(( I2C_S_REG(I2CN[I2Cn]) & I2C_S_IICIF_MASK)==0) {} \
                                    I2C_S_REG(I2CN[I2Cn]) |= I2C_S_IICIF_MASK;

//判断是否应答了
#define i2c_IsAsk(I2Cn)             (( I2C_S_REG(I2CN[I2Cn])  & I2C_S_RXAK_MASK)==0 ? 1:0)

//写一个字节
#define i2c_write_byte(I2Cn,data)   (I2C_D_REG(I2CN[I2Cn]) = (data));

/*!
*  @brief      I2C初始化,设置波特率
*  @param      I2Cn_e      I2C模块(I2C0、I2C1)
*  @param      baud        期待的波特率
*  @return                 实际的波特率
*  @since      v5.0
*  Sample usage:       i2c_init(I2C0,400*1000);     // 初始化I2C0,期待的波特率为400k
*/
uint32 i2c_init(I2Cn_e i2cn, uint32 baud)
{
    uint32 sclk;
    uint8 mult;
    uint16 scldiv;

    //查表 ICR 对应的  SCL_divider
    const uint16 ICR_2_SCL_divider[0x40]  =
    {
        20, 22, 24, 26, 28, 30, 34, 40, 28, 32, 36, 40, 44, 48, 56, 68,
        48, 56, 64, 72, 80, 88, 104, 128, 80, 96, 112, 128, 144, 160, 192, 240,
        160, 192, 224, 256, 288, 320, 384, 480, 320, 384, 448, 512, 576, 640, 768, 960,
        640, 768, 896, 1024, 1152, 1280, 1536, 1920, 1280, 1536, 1792, 2048, 2304, 2560, 3072, 3840
    };

    //需要从 ICR_2_SCL_divider 里找到 与最佳分频系数scldiv最相近的 分频系数
    uint8 icr, n = 0x40;
    uint16 min_Dvalue = ~0, Dvalue;


    if(i2cn == I2C0)
    {
        /* 开启时钟 */
#if (defined(MK60DZ10) || defined(MKL26Z4) )
        SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK;           //开启 I2C0时钟
#elif defined( MK60F15)
        SIM_SCGC4 |= SIM_SCGC4_IIC0_MASK;           //开启 I2C0时钟
#endif

        sclk =  bus_clk_khz * 1000;

        /* 配置 I2C0功能的 GPIO 接口 */
        if((I2C0_SCL_PIN == PTB0) || (I2C0_SCL_PIN == PTB2) || (I2C0_SCL_PIN == PTC8)  )
            port_init (I2C0_SCL_PIN, ALT2 | PULLUP );
        else if(I2C0_SCL_PIN == PTE19)
            port_init (I2C0_SCL_PIN, ALT4 | PULLUP );
        else if(I2C0_SCL_PIN == PTE24)
            port_init (I2C0_SCL_PIN, ALT5 | PULLUP );
        else
            ASSERT(0);                              //上诉条件都不满足,直接断言失败了,设置管脚有误?

        if ((I2C0_SDA_PIN == PTB1) ||  (I2C0_SDA_PIN == PTB3) || (I2C0_SDA_PIN == PTC9) )
            port_init (I2C0_SDA_PIN, ALT2 | PULLUP );
        else if(I2C0_SDA_PIN == PTE18)
            port_init (I2C0_SDA_PIN, ALT4 | PULLUP );
        else if(I2C0_SDA_PIN == PTE25)
            port_init (I2C0_SDA_PIN, ALT5 | PULLUP );
        else
            ASSERT(0);                              //上诉条件都不满足,直接断言失败了,设置管脚有误?
    }
    else
    {
        /* 开启时钟 */
#if (defined(MK60DZ10) || defined(MKL26Z4) )
        SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;           //开启 I2C1时钟
#elif defined(MK60F15)
        SIM_SCGC4 |= SIM_SCGC4_IIC1_MASK;           //开启 I2C1时钟
#endif

        sclk =  core_clk_khz * 1000;

        /* 配置 I2C1功能的 GPIO 接口 */
        if(I2C1_SCL_PIN == PTE1)
            port_init (I2C1_SCL_PIN, ALT6 | PULLUP );
        else if((I2C1_SCL_PIN == PTA3) || (I2C1_SCL_PIN == PTC1) || (I2C1_SCL_PIN == PTC10)  )
            port_init (I2C1_SCL_PIN, ALT2 | PULLUP );
        else
            ASSERT(0);                          //上诉条件都不满足,直接断言失败了,设置管脚有误?

        if(I2C1_SDA_PIN == PTE0)
            port_init (I2C1_SDA_PIN, ALT6 | PULLUP );
        else if ((I2C1_SDA_PIN == PTA4) || (I2C1_SDA_PIN == PTC2) || (I2C1_SDA_PIN == PTC11)  )
            port_init (I2C1_SDA_PIN, ALT2 | PULLUP );
        else
            ASSERT(0);                          //上诉条件都不满足,直接断言失败了,设置管脚有误?
    }

    /* 设置频率 */
    //I2C baud rate = I2C module clock speed (Hz)/(mul × SCL divider)

    // I2C baud rate = bus speed (Hz)/(mul × SCL divider)  即这里 50MHz/(1 ×128)=390.625kHz
    // SDA hold time = bus period (s) × mul × SDA hold value
    // SCL start hold time = bus period (s) × mul × SCL start hold value
    // SCL stop hold time = bus period (s) × mul × SCL stop hold value

    if(sclk <= 24*1000*1000)mult = 0;         //bus 一分频
    else  if(sclk <=  48*1000*1000)mult = 1;  //bus 二分频
    else      mult = 2;                       //bus 四分频

    scldiv =  sclk / ( (1<< mult ) * baud );  //最佳的分频系数

    while(n)                                            //循环里逐个扫描,找出最接近的 分频系数
    {
        n--;
        Dvalue = abs(scldiv - ICR_2_SCL_divider[n]);
        if(Dvalue == 0)
        {
            icr = n;
            break;                                      //退出while循环
        }

        if(Dvalue < min_Dvalue)
        {
            icr = n;
            min_Dvalue = Dvalue;
        }
    }

#if 1
    I2C_F_REG(I2CN[i2cn])  = ( 0                        // I2C Frequency Divider register (I2Cx_F)  I2C分频寄存器   I2C最大波特率为 400k
                               | I2C_F_MULT(mult)        // 乘数因子 mul = MULT + 1
                               | I2C_F_ICR(icr)          // 时钟速率 = ICR_2_SCL_divider[ICR] ,查表获得 ICR 与 SCL_divider 映射关系
                             );
#else
    I2C_F_REG(I2CN[i2cn]) =  0x14;
#endif

    /* 使能 IIC1 */
    I2C_C1_REG(I2CN[i2cn]) = ( 0
                               | I2C_C1_IICEN_MASK       //使能I2C
                               //| I2C_C1_TXAK_MASK
                               //| I2C_C1_IICIE_MASK       //使能中断
                             );

    return ( scldiv / ( (1<<mult ) * ICR_2_SCL_divider[icr])  );
}


/*!
*  @brief      I2C通信结束后需要调用的函数函数
*  @since      v5.0
*  @note       如果通信失败,可尝试增大此延时值,确认是否延时导致的
*/
void Pause(void)
{
    volatile uint16 n = 300;     //注意,这个数据太小,会导致读取错误。

    while(n--)
    {
        asm("nop");
    }
}

/*!
*  @brief      读取I2C设备指定地址寄存器的数据
*  @param      I2Cn_e        I2C模块(I2C0、I2C1)
*  @param      SlaveID     从机地址(7位地址)
*  @param      reg         从机寄存器地址
*  @return                 读取的寄存器值
*  @since      v5.0
*  Sample usage:       uint8 value = i2c_read_reg(I2C0, 0x1D, 1);
*/
uint8 i2c_read_reg(I2Cn_e i2cn, uint8 SlaveID, uint8 reg)
{

    //先写入寄存器地址,再读取数据,因此此过程是 I2C 的复合格式,改变数据方向时需要重新启动
    uint8 result;

    ASSERT((SlaveID & 0x80) == 0);                      //断言,我们要求的7位地址的值仅仅是7bit,不是通信时要求的高7位
    //有些手册,给出的7位地址指的是8bit里的高7位
    //有些手册,给出的7位地址指的是7bit
    //请自行确认,可以尝试是否通信正常来确认

    i2c_Start(i2cn);                                    //发送启动信号

    i2c_write_byte(i2cn, ( SlaveID << 1 ) | MWSR);      //发送从机地址和写位
    i2c_Wait(i2cn);

    i2c_write_byte(i2cn, reg);                          //发送从机里的寄存器地址
    i2c_Wait(i2cn);

    i2c_RepeatedStart(i2cn);                            //复合格式,发送重新启动信号

    i2c_write_byte(i2cn, ( SlaveID << 1) | MRSW );      //发送从机地址和读位
    i2c_Wait(i2cn);

    //i2c_EnterRxMode(i2cn) ;
    i2c_PutinRxMode(i2cn);                              //进入接收模式(不应答,只接收一个字节)


    result = I2C_D_REG(I2CN[i2cn]);                     //虚假读取一次,启动接收数据
    i2c_Wait(i2cn);                                     //等待接收完成

    i2c_Stop(i2cn);                                     //发送停止信号

    result = I2C_D_REG(I2CN[i2cn]);                     //读取数据

    Pause();                                            //必须延时一下,否则出错

    return result;
}


/*!
*  @brief      写入一个字节数据到I2C设备指定寄存器地址
*  @param      I2Cn_e        I2C模块(I2C0、I2C1)
*  @param      SlaveID     从机地址(7位地址)
*  @param      reg         从机寄存器地址
*  @param      Data        数据
*  @since      v5.0
*  Sample usage:       i2c_write_reg(I2C0, 0x1D, 1,2);     //向从机0x1D 的寄存器 1 写入数据 2
*/

void i2c_write_reg(I2Cn_e i2cn, uint8 SlaveID, uint8 reg, uint8 Data)
{

    i2c_Start(i2cn);                                    //发送启动信号

    i2c_write_byte(i2cn, ( SlaveID << 1 ) | MWSR);      //发送从机地址和写位
    i2c_Wait(i2cn);
    if(i2c_IsAsk(i2cn) == 0) return;                  //没有应答

    i2c_write_byte(i2cn, reg);                         //发送从机里的寄存器地址
    i2c_Wait(i2cn);

    i2c_write_byte(i2cn, Data);                         //发送需要写入的数据
    i2c_Wait(i2cn);

    i2c_Stop(i2cn);

    Pause();                                            //延时太短的话,可能写出错
}

这是mma7455.h的  地址已改成 mma8452
#ifndef __VCAN_MMA7455_H__
#define __VCAN_MMA7455_H__


#define     MMA7455_DEVICE          I2C1        //定义MMA7455 所用的接口 为 I2C0

#define     MMA7455_ADRESS          (0x1C)      /*MMA7455_Device Address*/
#define     MMA8452_WHO_AM_I   0x0D

//函数声明
extern void  mma7455_init(void);                        //初始化MMA7455
extern void  mma7455_write_reg(uint8 reg, uint8 Data);  //写MMA7455寄存器
extern uint8 mma7455_read_reg(uint8 reg);               //读MMA7455寄存器
#endif  //__VCAN_MMA7455_H__





这是mma7455.c

#include "common.h"
#include "MKL_port.h"
#include "MKL_i2c.h"
#include "VCAN_MMA7455.h"

//宏定义调用底层的I2C接口
#define MMA7455_OPEN(baud)      i2c_init(MMA7455_DEVICE,baud)
#define MMA7455_WR(reg,value)   i2c_write_reg(MMA7455_DEVICE,MMA7455_ADRESS,reg,value)  //mma7455 写寄存器
#define MMA7455_RD(reg)         i2c_read_reg(MMA7455_DEVICE,MMA7455_ADRESS,reg)             //mma7455 读寄存器

/*!
*  @brief      MMA7455初始化,进入 2g 量程测试模式
*  @since      v5.0
*  Sample usage:            mma7455_init();    //初始化 MMA7455
*/
void mma7455_init(void)
{
    MMA7455_OPEN(400 * 1000);           //初始化mma7455接口,设置波特率 400k

//    /*MMA进入 2g 量程测试模式*/
//    MMA7455_WR(MMA7455_MCTL, 0x05);    //mma8452似乎没有此寄存器

//   /*DRDY标置位,等待测试完毕*/
//    while(!(MMA7455_RD(MMA7455_STATUS) & 0x01));

}


/*!
*  @brief      MMA7455写寄存器
*  @param      reg         寄存器
*  @param      dat         需要写入的数据的寄存器地址
*  @since      v5.0
*  Sample usage:       mma7455_write_reg(MMA7455_XOFFL,0);   // 写寄存器 MMA7455_XOFFL 为 0
*/
void mma7455_write_reg(uint8 reg, uint8 Data)
{
    MMA7455_WR(reg, Data);
}

/*!
*  @brief      MMA7455读寄存器
*  @param      reg         寄存器
*  @param      dat         需要读取数据的寄存器地址
*  @since      v5.0
*  Sample usage:       uint8 data = mma7455_read_reg(MMA7455_XOFFL);    // 读寄存器 MMA7455_XOFFL
*/
uint8 mma7455_read_reg(uint8 reg)
{
    return MMA7455_RD(reg);
}


回复

使用道具 举报

 楼主| 发表于 2014-12-26 20:38:34 | 显示全部楼层
本人新手  弄了几天没弄好 求999999
回复 支持 反对

使用道具 举报

发表于 2014-12-26 20:38:50 | 显示全部楼层
硬件I2C ,老是出现这问题。

调一下波特率,不行的话,示波器看看时序正不正确。
回复 支持 反对

使用道具 举报

发表于 2014-12-26 20:39:40 | 显示全部楼层
实在不行,就用软件I2C 咯。这个硬件I2C,我当时也调了很久,这个I2C行了,换了另外一个又不行。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回列表 返回顶部