nRF51822 学习笔记(五)IIC 驱动加速度传感器BMA253

本篇博客主要用于记录我使用 nRF51822 采用 IIC 方式驱动 加速度传感器 BMA253 的过程。其中的方法也适用于驱动BMA2x2系列芯片。其中若有解释错误的地方,欢迎广大博友指出。文末的参考链接贴出了部分我学习过程中参考的博客,大家也可以查看阅读一下,因为本篇博客篇幅有限,内容写得也不够全面。

一、了解BMA253

BMA253是一个三轴,low-g传感器,主要用于消费电子产品中。它可以测量3个相互垂直的加速度的值。 

BMA253的LGA的封装(12 pin)和SPI/IIC 的接口方式有利于进行项目开发。 

BMA253提供的VDDIO工作的范围:1.2V ~3.6V 。 

BMA253提供两种供电方式:Vdd直接供电给内部模块 或者 Vddio单独给外部接口供电。

BMA253有六种不同的电源模式,一种 normal mode 和五种低功耗模式:

deep-suspend mode,suspend mode,standby mode,low-power mode1low-power mode2

详细的BMA253的资料可以在立创商城上下载数据手册下来看

博客【传感器】BMA253 数字、三轴加速度传感器写得不错也可以看看。


二、nRF51822硬件IIC TWI(two wire interface)

因为绘制原理图时 BMA253 采用的就是IIC通信方式,所以就得捣鼓一下nRF51822的硬件IIC了。因为nRF51系列提供了丰富的样例,所以如果我们在首次学习的时候选择了正确的样例来学习,那么会事半功倍。我就是最开始没有找到合适的样例,学习起来就特别慢,所以这里我建议大家直接下载官方样例 twi_sensor_pca10028 来进行学习开发与移植。具体的样例下载方法可以参考我同系列的笔记三中有详细说明。

1、IIC通信基本知识

I2C通信需要两条线:SDA,SCL。I2C通信设备有两种角色:master和slave,一般用户开发程序都是开发master端,然后去读写作为slave的外设,比如:eeprom,flash,sensor,display device。

在通信过程中,要注意两组特殊控制信号: 

start :scl为高电平时,sda由高电平变为低电平。 
           stop: scl为高电平时,sda由低电平变为高电平。

         (注意在通信过程中,SCL始终由master控制,这句话在做模拟I2C的时候就显得意义非凡了)

           具体的IIC通信时序可以参考BMA253数据手册上提供的,博客nRF52832之硬件I2C中把IIC通信过程也讲解的很透彻了。

2、nRF51822 TWI总线特性

             兼容I2C协议
             时钟频率有100k,250k,400k可以选择
             支持时钟扩展
             支持简易DMA

3、twi_sensor 样例代码分析

首先我们从主函数开始看起,主函数里面代码也很简单。串口初始化部分这里就不提了,这里使用串口主要是为了方便观看通信过程的数据。

twi_sensor 示例代码演示了如何通过IIC接口与accelorometer(MMA7660FC)通信来。数据从加速度计收集并由UART发送。

/* TWI instance. */
static const nrf_drv_twi_t m_twi_mma_7660 = NRF_DRV_TWI_INSTANCE(0);

int main(void)
{
    uart_config();
    int a = __GNUC__, c = __GNUC_PATCHLEVEL__;
    printf("\n\rTWI sensor example\r\n");
    twi_init();
    MMA7660_set_mode(); 
    
    uint8_t reg = 0;
    ret_code_t err_code;
    
    while(true)
    {
        nrf_delay_ms(100);
        /* Start transaction with a slave with the specified address. */
        do
        {
            __WFE();
        }while(m_xfer_done == false);
        err_code = nrf_drv_twi_tx(&m_twi_mma_7660, MMA7660_ADDR, &reg, sizeof(reg), true);
        APP_ERROR_CHECK(err_code);
        m_xfer_done = false;
    }
}


void twi_init (void)
{
    ret_code_t err_code;
    
    const nrf_drv_twi_config_t twi_mma_7660_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH
    };
    
    err_code = nrf_drv_twi_init(&m_twi_mma_7660, &twi_mma_7660_config, twi_handler, NULL);
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_twi_enable(&m_twi_mma_7660);
}

twi_init()函数中包含了对SCL、SDA引脚端口的初始化,我们可以根据自己的实际电路修改这里的引脚配置。然后就是IIC的时钟频率和中断等级的配置。

再调用 nrf_drv_twi_init()对TWI实例进行初始化,传入的第一个参数是TWI实例结构体、第二个是参数配置数组地址、第三个参数是中断回调函数入口,第四个参数传递给事件处理程序的上下文。

其中第一个参数定义是:NRF_DRV_TWI_INSTANCE(0) 中传入的数字0表示当前使用的TWI0,nRF51822中有两个TWI总线可以使用,若是我们要使用TWI1,则需要定义TWI实例=NRF_DRV_TWI_INSTANCE(1),并且找到 nrf_drv_config.h 开启TWI1

#define TWI1_ENABLED 0  //0 表示关闭  1表示开启

最后调用nrf_drv_twi_enable() 使能当前TWI实例,若有需要我们可以调用 nrf_drv_twi_disable()函数禁用TWI。


紧接着示例代码开始设置MMA7660的运行模式,通过代码注释可以得知,我们需要将MMA7660的模式寄存器置1才能使能该传感器。这里调用了nRF51中TWI通信提供给我们的API接口函数 nrf_drv_twi_tx()将运行模式值(也就是1)写入模式寄存器。

查看nrf_drv_twi_tx()函数功能描述:发送数据给TWI slave 。传入五个参数,分别是TWI实例结构体、slave设备地址、传送的数据缓存指针、数据长度、停止位标识(true表示没有停止位、false表示有停止位)

因此这里设置MMA7660模式的过程是:通过TWI 总线先将模式寄存器地址写入slave 设备,然后将数据(1)写入该寄存器,最后写入停止位表示通信结束。 

/**
 * @brief Function for setting active mode on MMA7660 accelerometer.
 */
void MMA7660_set_mode(void)
{
    ret_code_t err_code;
    /* Writing to MMA7660_REG_MODE "1" enables the accelerometer. */
    uint8_t reg[2] = {MMA7660_REG_MODE, ACTIVE_MODE};

    err_code = nrf_drv_twi_tx(&m_twi_mma_7660, MMA7660_ADDR, reg, sizeof(reg), false);  
    APP_ERROR_CHECK(err_code);
    
    while(m_set_mode_done == false);
}

nrf_drv_twi_tx()函数对应的函数是 nrf_drv_twi_rx()函数功能是从TWI slave设备读取数据。传入四个参数,分别是TWI实例结构体、slave设备地址、存储读取数据的接受缓存指针、接受数据的长度。

从while(1)之前的代码可以得出,我们要通过TWI驱动IIC设备,需要的操作首先就是IIC引脚的初始化及TWI功能的使能,紧接着就是使能连接的IIC设备,准备工作做好了之后,就可以进行数据传输了。

while(1)循环中不断给slave设备发送数据,从而触发TWI事件中断(即不断触发调用twi_handler函数),在这个事件中断中再处理接收数据的相关操作。


三、nRF51822+BMA2x2

通过对样例代码的分析我大概知道了如何使用nRF51822的TWI来驱动IIC设备,然后我就着手开始将示例代码中的MMA7660替换成我所使用的BMA253加速度传感器。

1、BMA2x2的IIC通信初始化

阅读BMA253的数据手册可以得知,BMA253的模式寄存器为0x00,正常模式normal_mode值为0。因此在设置好IIC通信引脚端口后,将BMA253的模式寄存器通过nrf_drv_twi_tx()接口函数写入0,在示例代码的基础上我们就可以得到一组从传感器上获取的数据。不过这不是我所需要的,我需要的是从BMA253传感器上读取到X、Y、Z三个方向的加速度值。

还好我找到了BMA2x2系列的驱动代码(BMA2x2_driver)。将驱动代码下载下来之后,只需要将bma2x2.c bma2x2.h添加到自己的工程目录下即可,文件中的bma2x2_support.c文件主要是提供了使用BMA2x2系列传感器的样例代码,其中包括IICSPI两种通信模式。

通过阅读bma2x2_support.c中的data_readout_template()读取传感器数据的示例函数可以得知,这里我们初始化IIC通信条件下的BMA253需要几个操作

I2C_routine();//这个函数主要是初始化bma2x2结构体的参数

com_rslt = bma2x2_init(&bma2x2);//初始化总线读取和总线写入功能分配芯片ID和器件地址芯片ID读取寄存器

com_rslt += bma2x2_set_power_mode(BMA2x2_MODE_NORMAL);//设置bma2x2的运行模式

不过这些只是BMA253软件方面的初始化,在这些初始化步骤之前还需要再加上对硬件IIC端口的初始化,也就是twi_sensor示例代码中的twi_init()函数的操作。

然后我将support.c中关于IIC读写的函数和定义全部都复制过来,代码编译通过,下载运行,原以为就能够读取数据,但是结果是什么也没有。然后我再反过来查看代码,原来是忘记在函数BMA2x2_I2C_bus_write()BMA2x2_I2C_bus_read()中添加相关的读写操作了。

我们已经清楚了如何使用nRF51822的TWI对slave设备进行读写操作,但是不同的芯片的IIC通信的读写时序可能不同,所以这里我们一定要阅读BMA253的数据手册呀,一定要阅读数据手册呀!

2、BMA253的IIC写时序

查看数据手册上给出的IIC写时序如下

从时序图中可以看出,我们如果要给slave写数据的话,需要先写slave地址,然后是待写入数据寄存器的地址,再接着才是写入的数据,最后是停止位。需要注意的是这里的slave_addr是7位的从设备地址,最低位的读写位不需要你管, 观察上图可以知道这里的slvave address是0x18。后面的RW位为0表示写,因此写从设备代码如下:

s8 BMA2x2_I2C_bus_write(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
	//BMA253 IIC写时序
	//先写从机设备地址---->待写入数据的寄存器地址---->数据....---->停止位
	s32 iError = BMA2x2_INIT_VALUE;
	u8 array[I2C_BUFFER_LEN];
	u8 stringpos = BMA2x2_INIT_VALUE;

	array[BMA2x2_INIT_VALUE] = reg_addr;//待写入数据的寄存器地址
	for (stringpos = BMA2x2_INIT_VALUE; stringpos < cnt; stringpos++) {
		array[stringpos + BMA2x2_BUS_READ_WRITE_ARRAY_INDEX] =
		*(reg_data + stringpos);
	}
	m_xfer_done = false;
	iError = nrf_drv_twi_tx(&m_twi_bma253,dev_addr,array,cnt+1,false);//停止位
	APP_ERROR_CHECK(iError);
	while(m_xfer_done == false);
	return (s8)iError;
}

3、BMA253 IIC 读时序

查看数据手册上给出的IIC读时序如下:

 这里的读从设备的时序跟平时见到的可能不太一样,这里需要首先将slave地址和待读取数据的寄存器地址写入slave从设备(时序图上RW位为0表示写)。注意后面没有停止位

然后紧接着再进行读取数据的操作,此时读取数据就只需要知道slave从设备地址即可,数据读取完成之后再加上停止位,表示本次通信结束。

因此读时序代码如下:

s8 BMA2x2_I2C_bus_read(u8 dev_addr, u8 reg_addr, u8 *reg_data, u8 cnt)
{
	//注意BMA253 IIC读时序
	//先发从机设备地址-->再发寄存器地址--->无停止位
	//再发从机设备地址-->读数据.......---->读取完成停止
	s32 iError = BMA2x2_INIT_VALUE;
    m_xfer_done = false;
	iError = nrf_drv_twi_tx(&m_twi_bma253,dev_addr,&reg_addr,1,true);//没有停止位
	APP_ERROR_CHECK(iError);
	while(m_xfer_done == false);
	
	m_xfer_done = false;
	iError = nrf_drv_twi_rx(&m_twi_bma253,dev_addr,reg_data,cnt);
	APP_ERROR_CHECK(iError);
	while(m_xfer_done == false);
	return (s8)iError;
}

将读写操作的代码都添加完整之后,再调用BMA2x2驱动代码中提供的读取xyz方向的加速度接口函数,就可以得出加速度数据。然后再根据我们选用的量程进行单位的转换或者是相关算法的计算,就能得到我们想要的数据。bma2x2.c中给我们提供了很多接口函数。


参考链接

BMA2x2_driver

nRF51822--TWI(硬件IIC)

Nordic 系列芯片讲解五(Nordic sdk中nrf_drv_twi的使用)

nrf52832用IIC驱动陀螺仪MPU6050

nRF52832之硬件I2C

【传感器】BMA253 数字、三轴加速度传感器

 

 

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微芯供氧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值