美文网首页
BMA250驱动编写

BMA250驱动编写

作者: lissettecarlr | 来源:发表于2019-12-19 09:55 被阅读0次

该文章基于<<BMA250三轴加速度传感器(部分翻译)>>,所以主要以编写代码为主,不阐述其他内容

1 前言

这里讲一下关于传感器驱动在不同硬件的区别吧,首先对于这类读写寄存器的设备而言,不同单片机的区别仅仅在于读写函数,而写哪些寄存器进行配置,读哪些寄存器得到想要数据是完全相同的。所以编写这类驱动本应该是留好接口函数,比如在初始化的时候将读写或者其他需要的函数传入其中,然后简单的调用get-set等函数进行操作即可的,but。。。本人比较懒,这个传感器仅仅在一个历史阶段使用了一下下,没有封装起来。

2 STM32F103-裸跑

2.1前置工具函数

需要引入头文件

#include "stm32f10x_spi.h"
#include "stm32f10x.h"

引脚关系

// PA4 CS    ->CSB
// PA5 SCK   ->SCL
// PA6 MISO  ->SD0
// PA7 MOSI  ->SDA

片选函数

void CS_ENABLE()
{   
    GPIO_ResetBits(GPIOA,GPIO_Pin_4);
    delay_us(10);
}

void CS_DISABLE()
{
    GPIO_SetBits(GPIOA,GPIO_Pin_4);
    delay_us(10);
}

SPI初始化

void SPI_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef  SPI_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    
  // Configure SPI1 pins: SCK, MISO and MOSI ---------------------------------
  // Confugure SCK and MOSI pins as Alternate Function Push Pull
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //CS
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    CS_DISABLE();
    
  // Confugure MISO pin as Input Floating
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
    
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //0
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//0-
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_Init(SPI1, &SPI_InitStructure);
    
    SPI_Cmd(SPI1, ENABLE);
}

SPI读写函数

void BMA250_WriteByte(u8 addr,u8 data)
{       
        CS_ENABLE();
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}
    SPI_I2S_SendData(SPI1, addr);
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){}
        SPI_I2S_ReceiveData(SPI1);
    
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}
    SPI_I2S_SendData(SPI1, data);
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){}
        SPI_I2S_ReceiveData(SPI1);
        CS_DISABLE();
}
//读一个地址
u8 BMA250_ReadByte(u8 addr) 
{
      u8 RxData = 0;
    CS_ENABLE();
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}
    SPI_I2S_SendData(SPI1, 0x80|addr);
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){}
    RxData = SPI_I2S_ReceiveData(SPI1);
    
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}
    SPI_I2S_SendData(SPI1, 0);
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){}
    RxData = SPI_I2S_ReceiveData(SPI1);
        CS_DISABLE();
    return (u8)RxData;
}

2.2 传感器驱动部分

可以利用读写函数进行一些额外配置,或者判断是否和传感器建立了连接

u8 BMA250_Init()
{
    SPI_init();
    BMA250_WriteByte(PMU_RANGE, ACC_RANGE_2G);
    id=BMA250_ReadByte(BGW_CHIPID);
    return id;
}

该传感器有一些其他功能模式,这里只读取加速度,下列加速度读取直接调用了库函数

//读取加速度传感器的值 
void BMA250_ReadAcc(s16 *pX,s16 *pY,s16 *pZ)
{
    s8 dataout[6]={0,0,0,0,0,0};
    u8 i=0;
    CS_ENABLE();
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}
    SPI_I2S_SendData(SPI1, 0x80|ACCD_X_LSB);//register addr,读之前最高位要置1

    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){}
  SPI_I2S_ReceiveData(SPI1);
    
    for(i = 0; i<6; i++)
  {
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, 0);
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    dataout[i] = SPI_I2S_ReceiveData(SPI1);
  }
    CS_DISABLE();
    
    *pX = ( (((u8)dataout[0]) >> 6) | ((s16)(dataout[1]) << 2) );
    *pY = ( (((u8)dataout[2]) >> 6) | ((s16)(dataout[3]) << 2) );
    *pZ = ( (((u8)dataout[4]) >> 6) | ((s16)(dataout[5]) << 2) );
}

使用

主函数调用BMA250_Init后,不断在while中BMA250_ReadAcc读取就行,当然,传感器本身有个采集周期的,可配置。

3 CC1310-contiki

该程序和上文不是一个时间段编写的,共同部分也是有些差异,但功能都是一样的,这里使用的是IIC通信

3.1前置工具函数

由于使用了操作系统,所以一些外设初始化就不用自己写了
头文件

#include "ti-lib.h"
#include "board-i2c.h"

读写函数

static bool sensor_common_write_reg(uint8_t addr, uint8_t *buf, uint8_t len)
{
  uint8_t buffer[32];
  uint8_t i;
  uint8_t *p = buffer;
  /* Copy address and data to local buffer for burst write */
  *p++ = addr;
  for(i = 0; i < len; i++) {
    *p++ = *buf++;
  }     
  len++;
  /* Send data */
  return board_i2c_write(buffer, len);
}

static bool sensor_common_read_reg(uint8_t addr, uint8_t *buf, uint8_t len)
{
  return board_i2c_write_read(&addr, 1, buf, len);
}

3.2传感器驱动部分

传感器初始化

void BMA250_init()
{
    uint8_t bGRange = RANGE_USE;   // g Range;
    uint8_t bBwd = BWD_USER;       //64ms采集一次
    uint8_t bMode = 0;                                                          
    board_i2c_select(0, BMA250_Addr);
    sensor_common_write_reg(BMP_GRANGE,&bGRange,1);
    sensor_common_write_reg(BMP_BWD, &bBwd, 1);
    //退出睡眠模式,并且不使能低功耗模式
    sensor_common_write_reg(BMP_PM,&bMode,1);
}

输出加速度原始值

void BMA250_get_original_acclerometer(short *ax,short *ay,short *az)
{
    uint8_t buffer[6];
    uint16_t buf[3];
    board_i2c_select(0, BMA250_Addr);
    sensor_common_read_reg(BMP_ACC_X_LSB,buffer,6);
    //board_i2c_select(BOARD_I2C_INTERFACE_0, 0);
    
    //x
    buf[0] = ((uint16_t)buffer[1]) << 8;
    buf[0] = buf[0] | buffer[0];
    buf[0] = buf[0] >> 6;

    //正负
    if( buf[0] > 512){
      buf[0] <<= 6;
      buf[0]   = ~ buf[0];
      buf[0]   =  buf[0] + 1;
      buf[0] >>= 6;
      buf[0] = -buf[0];
     }
    // y
    buf[1] = ((uint16_t)buffer[3]) << 8;
    buf[1] = buf[1] | buffer[2];
    buf[1] = buf[1] >> 6;

    // 0 - 512 为正数  512 -1024为负数
    if( buf[1] > 512){
     buf[1] <<= 6;
     buf[1]   = ~ buf[1];
     buf[1]   =  buf[1] + 1;
     buf[1] >>= 6;
     buf[1] = -buf[1];
    }

    // z
    buf[2] = ((uint16_t)buffer[5])<< 8;
    buf[2] = buf[2] | buffer[4];
    buf[2] = buf[2] >> 6;

    if( buf[2] > 512){
     buf[2] <<= 6;
     buf[2]   = ~ buf[2];
     buf[2]   =  buf[2] + 1;
     buf[2] >>= 6;
     buf[2] = -buf[2];
    }

    *ax = buf[0];
    *ay = buf[1];
    *az = buf[2];
}

输出加速度值,单位mg

void BMA250_get_acc_acclerometer(float *ax,float *ay,float *az)
{
    uint8_t buffer[6];
    uint16_t buf[3];
    board_i2c_select(0, BMA250_Addr);
    sensor_common_read_reg(BMP_ACC_X_LSB,buffer,6);
    //board_i2c_select(BOARD_I2C_INTERFACE_0, 0);
    
    //x
    buf[0] = ((uint16_t)buffer[1]) << 8;
    buf[0] = buf[0] | buffer[0];
    buf[0] = buf[0] >> 6;

    //符号位判断
     if( buf[0] > 512){ 
      buf[0] <<= 6;
      buf[0]   = ~ buf[0];
      buf[0]   =  buf[0] + 1;
      buf[0] >>= 6;
      *ax = (float)buf[0] * RANGE_RESOLUTION;
      *ax = -(*ax);
     }
     else{
         *ax = (float)buf[0] * RANGE_RESOLUTION;
     }
    // y
    buf[1] = ((uint16_t)buffer[3]) << 8;
    buf[1] = buf[1] | buffer[2];
    buf[1] = buf[1] >> 6;
    
     if( buf[1] > 512){
     buf[1] <<= 6;
     buf[1]   = ~ buf[1];
     buf[1]   =  buf[1] + 1;
     buf[1] >>= 6;
     *ay = (float)buf[1] * RANGE_RESOLUTION;
     *ay = -(*ay);
    }
    else
    {
        *ay = (float)buf[1] * RANGE_RESOLUTION;
    }

    // z
    buf[2] = ((uint16_t)buffer[5])<< 8;
    buf[2] = buf[2] | buffer[4];
    buf[2] = buf[2] >> 6;

    if( buf[2] > 512){
     buf[2] <<= 6;
     buf[2]   = ~ buf[2];
     buf[2]   =  buf[2] + 1;
     buf[2] >>= 6;

     *az = -((float)buf[2] *RANGE_RESOLUTION);
    }
    else
    {
        *az = (float)buf[2] * RANGE_RESOLUTION;
    }
}

下列函数是和读取加速度无关功能,本人那时候想使用传感器的单击功能来用作计步,但是失败了,可用来参考参数配置吧

//计步初始化
void step_init()
{
// uint8_t val=0;
   uint8_t config;
   board_i2c_select(0, BMA250_Addr);
   //使能单次震荡响应
   sensor_common_read_reg(BMP_ISR1,&config,1);
   //printf("enable old %d",config);
   config |= (1<<5);
   //printf("enable  %d",config);
   sensor_common_write_reg(BMP_ISR1,&config,1);
   //设定阀值 范围0-31 //对应1 LSB
   sensor_common_read_reg(0x2B,&config,1);
   //printf("max old %d",config);
   config &= 0XE0;
   config |= BMA250_STEP_MAX;
   //printf("enable %d",config);
   sensor_common_write_reg(0x2B,&config,1);
   //设定各种判定时间
   sensor_common_read_reg(0x2A,&config,1);
   //printf("time old %d",config);
   config |= BMA250_QUIET_SHOCK; 
   //printf("enable %d",config);
   sensor_common_write_reg(0x2A,&config,1);
}

uint8_t read_step_int()
{
   uint8_t flag;
   sensor_common_read_reg(0x09,&flag,1);
   flag &= 0x20;

   flag = flag>>5;
   return flag;
}

之后改写了网上的计步算法,实现了用这个传感器进行软件计步的功能,之后有空另起一文再谈吧。

相关文章

  • BMA250驱动编写

    该文章基于< >,所以主要以编写代码为主,不阐述其他内容 1 前言 这里讲一下关于传感器驱动在不同硬件的区别吧,首...

  • Linux 设备驱动之 hello 驱动

    Linux 设备驱动之 hello 驱动 首先编写一个简单的 hello 驱动, drv_hello.c 编写应用...

  • Linux设备驱动程序学习----7.用户空间编写驱动程序

    用户空间编写驱动程序 更多内容请参考Linux设备驱动程序学习----目录 用户空间编写驱动程序   相对于内核空...

  • 添加驱动模块

    目录[隐藏]1 [编写linux驱动程序]1.1 一、编写驱动核心程序1.2 二、配置Kconfig1.3 三、配...

  • 保龄球编程读后感

    测试驱动编程: 1.测试驱动编程:在编写功能之前先编写测试代码,然后只编写使测试通过的功能代码, 通过测试来驱...

  • PCI设备驱动(一)

    首先要明确两个概念:Linux内核 PCI设备驱动和设备本身驱动两部分。工作中所谓的编写设备驱动,其实就是编写设备...

  • android 自定义驱动(第一篇:驱动)

    简介 案例内容:我们不会为真实的硬件设备编写内核驱动程序,这里为了方便描述Android系统编写内核驱动程序的过程...

  • 编写事件驱动模型

    Nodejs本身是基于事件驱动的,这个都知道。如果你看过Nodejs events模块,应该很了解Nodejs是如...

  • Node.js事件驱动机制

    使用事件驱动机制编写事件处理代码

  • python 自动化测试五种模型

    python 自动化测试五种模型,线性、模块化驱动模型、数据驱动模型、关键字驱动模型、行为驱动模型 通过录制或编写...

网友评论

      本文标题:BMA250驱动编写

      本文链接:https://www.haomeiwen.com/subject/zbtehqtx.html