MMC5603地磁传感器调试日志

/******************************************************************************/
/*开发平台:Keil uVision5                                                                      */
/*开发语言:C语言                                                                                 */
/*作者:jerseyceo                                                                                  */     
/*实现功能:地磁传感器的应用(指南针)                                            */
/******************************************************************************/
第一步:nrf52832开发板与MMC5603地磁传感器硬件连接

注:MMC5603NJ可以从单个1.62V到3.6 v供应。下面的电路连接图说明了电源连接选项。

MMC5603地磁传感器调试日志

          nrf52832                          MMC5603
引脚:    VDD               —>              VDD
引脚:    GND               —>              GND
引脚:    SCL                —>              SCL
引脚:    SDA                —>              SDA

NOTE:焊接引脚连接上电后,使用万用表测量传感器VDD与GND引脚两端电压,检测传感器是否处于正常工作电压范围,以便进行接下来的keil编程调试与开发。

第二步:学习并掌握硬件TWI(I2C)通信原理,使用I2C通信协议配置传感器工作参数。

1.库函数的应用

MMC5603地磁传感器调试日志

                                                        图1:TWI应用步骤

1.1.定义TWI驱动程序实例

/* TWI instance ID,ID和外设编号对应,0:TWI0   1:TWI1*/
#define TWI_INSTANCE_ID     0

/* TWI instance. 定义TWI驱动程序实例,使用TWI0:外设0*/
static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);

/* 从机设备地址0x60=0x30<<1(TWI硬件自动完成读写位)*/
#define MMC5603_7BITI2C_ADDRESS        0x30

 

1.2.初始化TWI

初始化实例:err_code = nrf_drv_twi_init(&m_twi, &twi_mmc5603_config, twi_handler, NULL);

1.2.1.初始化TWI函数原型:

ret_code_t nrf_drv_twi_init(nrf_drv_twi_t const *        p_instance,
                                           nrf_drv_twi_config_t const * p_config,
                                           nrf_drv_twi_evt_handler_t    event_handler,
                                           void *                       p_context)

p_instance:指向驱动程序实例结构体

p_config:指向初始化配置结构体

event_handler:事件句柄,如果设置为NULL,则使能TWI阻塞模式

p_context:指向传递给事件句柄的context

 

1.2.2.初始化配置结构体(nrf_drv_twi_config_t) :

const nrf_drv_twi_config_t twi_mmc5603_config = {
       .scl                      = ARDUINO_SCL_PIN,                 //定义TWI SCL 引脚
       .sda                    = ARDUINO_SDA_PIN,                 //定义TWI SDA 引脚
       .frequency           = NRF_DRV_TWI_FREQ_100K,  //TWI 工作频率
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,    //TWI优先级
       .clear_bus_init     = false };

1.2.3.TWI事件句柄(nrf_drv_twi_evt_handler_t) :(TWI工作于非阻塞模式)

//TWI传输完成标志,false表示传输未完成

static volatile bool m_xfer_done = false;

void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{

    //判断TWI事件类型
    switch (p_event->type)
    {

        //传输事件完成
        case NRF_DRV_TWI_EVT_DONE:

           //功能代码
            if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX)
            {
             //此处可对传输事件完成后,打印读取数据日志信息。
            }
            m_xfer_done = true;//置位传输完成标志
            break;


       case  NRF_DRV_TWI_EVT_ADDRESS_NACK:   //< Error event: NACK received after sending the address.
       case  NRF_DRV_TWI_EVT_DATA_NACK :   //< Error event: NACK received after sending a data byte. 
        default:
            break;
    }
}

1.2.4.使能TWI(nrf_drv_twi_enable):初始化完成后,使能TWI才能进行数据传输

__STATIC_INLINE
void nrf_drv_twi_enable(nrf_drv_twi_t const * p_instance)
{
    if (NRF_DRV_TWI_USE_TWIM)
    {
        nrfx_twim_enable(&p_instance->u.twim);
    }
    else if (NRF_DRV_TWI_USE_TWI)
    {
        nrfx_twi_enable(&p_instance->u.twi);
    }
}

1.2.5.数据传输

数据发送:向TWI从机发送数据

实例:err_code_tx = nrf_drv_twi_tx(&m_twi, i2c_add, &reg_add, 1, false);

ret_code_t  nrf_drv_twi_tx(

                          nrf_drv_twi_t const * p_instance,//指向TWI驱动程序实例结构体
                          uint8_t               address,//指定的从机地址(7位LSB)
                          uint8_t const *       p_data,//指向传输数据缓存(传感器内部寄存器/写入寄存器的命令)
                          uint8_t               length,//发送的字节数
                          bool                  no_stop)//如果置位,成功传输后不会生成停止条件(下次传输中可重复启动)

数据接收:从TWI从机读取数据

实例:ret_code_t err_code_rx = nrf_drv_twi_rx(&m_twi, i2c_add, data, sizeof(data));

ret_code_t nrf_drv_twi_rx(

                          nrf_drv_twi_t const * p_instance,//指向TWI驱动程序实例结构体
                          uint8_t               address,//指定的从机地址(7位LSB)
                          uint8_t *             p_data,//指向接收数据缓存
                          uint8_t               length)//读取的字节数

2.MMC5603地磁传感器原始数据读取(TWI0非阻塞)程序调试

2.1.MMC5603 I2C 时序

       MMC5603 数据传输的时序如下图所示,首先产生起始条件,紧跟着发送7位地址 + 读

写位(0=写,1=读),之后发送传输的数据,最后产生停止条件。

MMC5603地磁传感器调试日志

                                              图2:MMC5603 数据传输时序

*_*:根据 MMC5603 数据传输时序图,对照MMC5603的寄存器表,编写“写MMC5603寄存器”

和“读MMC5603寄存器”的函数。在编写读/写函数是,需要注意的是:

(1)因为时序要求写操作后产生停止条件,因此调用nrf_drv_twi_tx()函数时,参数“no_stop”必

须为false,及产生停止条件。

(2)配置TWI的工作模式是非阻塞模式,是异步的,所以调用nrf_drv_twi_tx()函数后,要等待

TWI传输完成,代码中通过查询m_xfer_done标志判断TWI传输是否完成。

2.2.写MMC5603寄存器函数

/*@brief I2C write register */
int MMC5603_Write_Reg(unsigned char i2c_add, unsigned char reg_add, unsigned char cmd)
{
    /* i2c_add is the 7-bit i2c address of the sensor
     * reg_add is the register address to write
     * cmd is the value that need to be written to the register
     * I2C operating successfully, return 1, otherwise return 0;
     */
    m_xfer_done = false;
//TWI传输完成标志位设置为 false,表示传输未完成
   
    ret_code_t err_code_tx;
/*指示TWI硬件驱动API调用过程的成功或失败*/
    uint8_t reg[2]={reg_add,cmd};/*等待写入的寄存器地址,要写入的命名*/ 
    err_code_tx = nrf_drv_twi_tx(&m_twi, i2c_add, reg, sizeof(reg), false);/*写入数据*/
    APP_ERROR_CHECK(err_code_tx);/*检查写入过程成功或失败*/
        
   while (m_xfer_done == false);
/*一直等待TWI总线传输完成,直到m_xfer_done置为true,跳出函数,结束写操作*/

 return 1;
}

2.3.单字节读MMC5603寄存器函数

/*@brief I2C read register.*/
int MMC5603_Read_Reg(unsigned char i2c_add, unsigned char reg_add, unsigned char *data)
{
    /* i2c_add is the 7-bit i2c address of the sensor
     * reg_add is the register address to read
     * data is the first address of the buffer that need to store the register value
     * I2C operating successfully, return 1, otherwise return 0;    
     */

//先写寄存器,确定要读取的(只读)从机寄存器,此处不需要(无法)向目标寄存器写命令;

//再读寄存器,从slave目标(只读)寄存器读取数据到指定数据缓存区;

/* 步骤一: 写寄存器

    m_xfer_done = false;//TWI传输完成标志位设置为 false,表示传输未完成
    
    ret_code_t err_code_tx; /*
指示TWI硬件驱动API调用过程中发送数据接口函数调用的成功或失败*/
    err_code_tx = nrf_drv_twi_tx(&m_twi, i2c_add, &reg_add, 1, false);
//发送要读取的目标寄存器地址,长度为1字节
    APP_ERROR_CHECK(err_code_tx);/*检查写入过程的成功或失败*/
    
    while (m_xfer_done == false);
/*一直等待TWI总线传输完成,直到m_xfer_done置为true,跳出函数,结束写操作*/

 

/* 步骤一: 读寄存器
    m_xfer_done = false;
//TWI传输完成标志位设置为 false,表示传输未完
    /* 从指定地址读取一个字节*/
    ret_code_t err_code_rx = nrf_drv_twi_rx(&m_twi, i2c_add, data, sizeof(data));
//将从指定寄存器读取的数据(一个字节)存入指针data指向的缓存区。
    APP_ERROR_CHECK(err_code_rx);/*检查读取过程的成功或失败*/

    while (m_xfer_done == false);/*一直等待TWI总线传输完成,直到m_xfer_done置为true,跳出函数,结束读操作*/

 return 1;
}

2.4.多字节读MMC5603寄存器函数

int MMC5603_MultiRead_Reg(unsigned char i2c_add, unsigned char reg_add, int bytesNumber, unsigned char *dataBuffer)
{
    /* i2c_add is the 7-bit i2c address of the sensor
     * reg_add is the first register address to read
     * num is the number of the register to read    
     * data is the first address of the buffer that need to store the register value
     * I2C operating successfully, return 1, otherwise return 0;    
     */

//先写寄存器,确定要读取的(只读)从机寄存器,此处不需要(无法)向目标寄存器写命令;

//再读寄存器,从slave目标(只读)寄存器读取数据到指定数据缓存区;

/* 步骤一: 写寄存器

    m_xfer_done = false;//TWI传输完成标志位设置为 false,表示传输未完成
    
    ret_code_t err_code_tx; /*
指示TWI硬件驱动API调用过程中发送数据接口函数调用的成功或失败*/
    err_code_tx = nrf_drv_twi_tx(&m_twi, i2c_add, &reg_add, 1, true);
//发送要读取的目标寄存器地址,长度为1字节,将no_stop置为true,表示连续写多个寄存器,写完一个寄存器后不停止。
    APP_ERROR_CHECK(err_code_tx);/*检查写入过程的成功或失败*/
    
    while (m_xfer_done == false);
/*一直等待TWI总线传输完成,直到m_xfer_done置为true,跳出函数,结束写操作*/

 

/* 步骤一: 读寄存器
    m_xfer_done = false;
//TWI传输完成标志位设置为 false,表示传输未完成
    /* 从指定地址读取一个字节*/
    ret_code_t err_code_rx = nrf_drv_twi_rx(&m_twi, i2c_add, data, sizeof(data));
//将从指定寄存器读取的数据(多个字节)存入指针data指向的缓存区。读取时寄存器地址自增,读取的数据依次不断改变,存入指针data指向的缓存区。
    APP_ERROR_CHECK(err_code_rx);/*检查读取过程的成功或失败*/

    while (m_xfer_done == false);/*一直等待TWI总线传输完成,直到m_xfer_done置为true,跳出函数,结束读操作*/

 return 1;
}