该文章基于<<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;
}
之后改写了网上的计步算法,实现了用这个传感器进行软件计步的功能,之后有空另起一文再谈吧。
网友评论