外设驱动库开发笔记22:ADXL345三轴数字加速度计驱动

移动设备的广泛应用增加对移动过程中各种参数的检测需求。ADXL345三轴数字加速度计可以用来检测加速度、进而测量倾斜角度等。在这一篇中,我们将讨论ADXL345三轴数字加速度计驱动程序的设计与实现。

1、功能概述

ADXL345是一款小而薄的超低功耗3轴加速度计,分辨率高(13),测量范围达±16 g。数字输出数据为16位二进制补码格式,可通过SPI(3线或4线)I2C数字接口访问。采用SPI通讯接口时,最大SPI时钟速度为5 MHz,时序方案按照时钟极性(CPOL)= 1、时钟相位(CPHA)= 1执行。采用I2C通讯接口时,ALT ADDRESS引脚处于高电平,器件的7I2C地址是0x1D,随后为R / W位。这转化为0x3A写入,0x3B读取。通过ALT ADDRESS引脚(引脚12)接地,可以选择备用I2C地址0x53(随后为R / W)。这转化为0xA6写入,0xA7读取。引脚定义及封装如下:

ADXL345非常适合移动设备应用。它可以在倾斜检测应用中测量静态重力加速度,还可以测量运动或冲击导致的动态加速度。其高分辨率(3.9 mg/LSB),能够测量不到1.0°的倾斜角度变化。

该器件提供多种特殊检测功能。活动和非活动检测功能通过比较任意轴上的加速度与用户设置的阈值来检测有无运动发生。敲击检测功能可以检测任意方向的单振和双振动作。自由落体检测功能可以检测器件是否正在掉落。这些功能可以独立映射到两个中断输出引脚中的一个。正在申请专利的集成式存储器管理系统采用一个32级先进先出(FIFO)缓冲器,可用于存储数据,从而将主机处理器负荷降至最低,并降低整体系统功耗。

低功耗模式支持基于运动的智能电源管理,从而以极低的功耗进行阈值感测和运动加速度测量。

ADXL345是一款完整的3轴加速度测量系统,可选择的测量范围有±2 g±4 g±8 g±16 g。既能测量运动或冲击导致的动态加速度,也能测量静止加速度,例如重力加速度,使得器件可作为倾斜传感器使用。

2、驱动设计与实现

我们对ADXL345驱动设计与其它设备一样。我们先抽象对象类型并考虑对对象的初始化和操作。

2.1、对象定义

基于对象的操作至少要包括3方面内容:对象的定义,对象的初值以及对象的操作。接下来我们就从这里个方面入手设计并实现ADXL345的驱动。

2.1.1、抽象对象类型

对于ADXL345也同时支持SPI接口通讯和I2C接口通讯。所以我们在抽象ADXL345对象类型时将接口类型作为属性以区别不同的特性。在使用I2C时,设备有地址以区别不同的设备,所以我们将I2C设备地址也定义为属性。而使用SPI时,没有设备地址但有片选信号,我们将对片选的操作定义为对象的操作函数。

/*定义ADXL345三轴数据结构*/
typedef struct Adxl345Object {uint8_t devAddress;uint8_t devID;Adxl345PortType port;int16_t incidence_X;int16_t incidence_Y;int16_t incidence_Z;float incidence_Xf;float incidence_Yf;float incidence_Zf;void (*ReadBytes)(struct Adxl345Object *adxl,uint8_t regAdd,uint8_t *rData,uint16_t rSize);  //读ADXL345寄存器操作void (*WriteBytes)(struct Adxl345Object *adxl,uint8_t regAdd,uint8_t *wData,uint16_t wSize);//写ADXL345寄存器操作void (*ChipSelect)(Adxl345CSType en);    //使用SPI接口时,片选操作void (*Delayus)(volatile uint32_t nTime);      /*实现us延时操作*/
}Adxl345ObjectType;

2.1.2、对象初始化函数

一个对象必须赋初值方可使用,所以我们还需要一个初始化函数来对对象初始化。初始化函数除了为对象属性赋初始值和给操作指定函数指针外,还需要检测参数的合法性以及对硬件设备做必要的配置。基于此我们设计ADXL345的初始化函数如下:

/*对ADXL345进行初始化配置*/
void Adxl345Initialization(Adxl345ObjectType *adxl,uint8_t devAdd,Adxl345PortType port,Adxl345ReadBytesType read,Adxl345WriteBytesType write,Adxl345ChipSelectType cs,Adxl345DelayType delay)
{uint8_t devID=0;uint8_t setValue=0;if((adxl==NULL)||(read==NULL)||(write=NULL)||(delay==NULL)){return;}if(port==SPI){if(cs==NULL){return;}adxl->ChipSelect=cs;adxl->devAddress=0x00;}else{if((devAdd==0xA6)||(devAdd==0x3A)){adxl->devAddress=devAdd;}else if((devAdd==0x53)||(devAdd==0x1D)){adxl->devAddress=(devAdd<<1);}else{adxl->devAddress=0x00;}adxl->ChipSelect=NULL;}adxl->port=port;adxl->devID=0xE5;adxl->incidence_X=0;adxl->incidence_Xf=0.0;adxl->incidence_Y=0;adxl->incidence_Yf=0.0;adxl->incidence_Z=0;adxl->incidence_Zf=0.0;adxl->ReadBytes=read;adxl->WriteBytes=write;adxl->Delayus=delay;/*读取设备ID,在每次操作前读一次*/devID=Adxl345ReadRegister(adxl,REG_DEVID);if(adxl->devID!=devID){return;}adxl->Delayus(300);/*配置数据格式*/setValue = 0x2B;Adxl345WriteRegister(adxl,REG_DATA_FORMAT,setValue);adxl->Delayus(50);/*配置数据速率及功率模式*/setValue = 0x0A;Adxl345WriteRegister(adxl,REG_BW_RATE,setValue);adxl->Delayus(50);/*配置电源特性*/setValue = 0x28;Adxl345WriteRegister(adxl,REG_POWER_CTL,setValue);adxl->Delayus(50);/*配置中断使能*/setValue = 0;Adxl345WriteRegister(adxl,REG_INT_ENABLE,setValue);adxl->Delayus(50);/*配置X轴偏移*/Adxl345WriteRegister(adxl,REG_OFSX,setValue);adxl->Delayus(50);/*配置Y轴偏移*/Adxl345WriteRegister(adxl,REG_OFSY,setValue);adxl->Delayus(50);/*配置Z轴偏移*/Adxl345WriteRegister(adxl,REG_OFSZ,setValue);adxl->Delayus(500);
}

2.2、对象操作

我们定义一个对象的目的是操作这个对象,这也是驱动程序的主要内容。接下来我们就来实现对ADXL345对象的操作函数。

2.2.1、写数据操作

ADXL345对象的写操作因为使用的接口不同其数据帧格式也会有不同。使用SPI接口时,其数据帧格式如下:

而使用I2C接口时,可以同时写多个寄存器,其数据帧格式如下:

根据上述的数据帧格式和时序图我们可以编写写ADXL345的寄存器函数:

/* 写ADXL345的寄存器 */
static void Adxl345WriteRegister(Adxl345ObjectType *adxl,uint8_t regAdd,uint8_t wData)
{if(adxl->port==SPI){adxl->ChipSelect(ADXL345CS_Enable);adxl->Delayus(50);adxl->WriteBytes(adxl,regAdd,&wData,1);adxl->Delayus(50);adxl->ChipSelect(ADXL345CS_Disable);}else{adxl->WriteBytes(adxl,regAdd,&wData,1);}
}

2.2.2、读数据操作

ADXL345对象的读操作也同样在使用不同的接口时拥有不同的数据帧结构。使用SPI接口时,其数据帧格式如下:

而在使用I2C接口时,可以实现一个或多个寄存器的读操作,其数据帧格式如下:

根据以上的数据帧格式和时序图我们可以开发读取ADXL345的寄存器操作函数:

/* 读取ADXL345的寄存器 */
static uint8_t Adxl345ReadRegister(Adxl345ObjectType *adxl,uint8_t regAdd)
{uint8_t regValue=0;if(adxl->port==SPI){adxl->ChipSelect(ADXL345CS_Enable);adxl->Delayus(50);adxl->ReadBytes(adxl,regAdd,&regValue,1);adxl->Delayus(50);adxl->ChipSelect(ADXL345CS_Disable);}else{adxl->ReadBytes(adxl,regAdd,&regValue,1);}return regValue;
}

2.2.3、测量数据输出

我们操作ADXL345对象的目的当然是获取我们想要的数据。最基本的,我们开发从ADXL345获取3个坐标数据。

/*读取数据值,分辨率(3.9 mg/LSB)*/
void GetValueFromAdxl345(Adxl345ObjectType *adxl)
{uint8_t devID = 0;uint8_t dataTemp[6];/*读取设备ID,在每次操作前读一次*/devID=Adxl345ReadRegister(adxl,REG_DEVID);if(adxl->devID!=devID){return;}adxl->Delayus(200);/*读取三轴数据值*/Adxl345ReadMultiReg(adxl,REG_DATAX0,dataTemp,6);/*数据解析*/adxl->incidence_X = (int16_t)(dataTemp[0] + ((uint16_t)dataTemp[1] << 8));adxl->incidence_Y = (int16_t)(dataTemp[2] + ((uint16_t)dataTemp[3] << 8));adxl->incidence_Z = (int16_t)(dataTemp[4] + ((uint16_t)dataTemp[5] << 8));adxl->incidence_Xf = (float)(adxl->incidence_X * 0.0039);adxl->incidence_Yf = (float)(adxl->incidence_Y * 0.0039);adxl->incidence_Zf = (float)(adxl->incidence_Z * 0.0039);
}

3、驱动的使用

完成了驱动的设计开发,我们还要使用驱动实现ADXL345的应用。与其它外设一样,我们也按照实际项目的使用流程来验证之。

3.1、声明并初始化对象

首先我们使用前面定义的Adxl345ObjectType类型声明一个ADXL345对象变量。如:Adxl345ObjectType adxl345

声明对象变量后还需要调用Adxl345Initialization初始化函数对ADXL345对象变量进行初始化。当然在调用初始化函数前需要考虑传入的参数。特别是几个函数指针需要实现响应的函数。需要实现的函数类型如下:

typedef void (*Adxl345ReadBytesType)(struct Adxl345Object *adxluint8_t regAdduint8_t *rDatauint16_t rSize);    //ADXL345寄存器操作

typedef void (*Adxl345WriteBytesType)(struct Adxl345Object *adxluint8_t regAdduint8_t *wDatauint16_t wSize);//ADXL345寄存器操作

typedef void (*Adxl345ChipSelectType)(Adxl345CSType en);       //使用SPI接口时,片选操作

typedef void (*Adxl345DelayType)(volatile uint32_t nTime);      /*实现us延时操作*/

定义这几个函数后,就可以将器函数指针作为实参传递给初始化函数。调用如下:

Adxl345Initialization(&adxl345devAddportreadwritecsdelay);

其中adxl345为需要初始化的ADXL345对象。devAdd为使用I2C通讯时的设备地址,使用SPI时无用。port为通讯端口的类型,SPI或者I2Cread读操作函数指针,是对硬件层的封装。write为写操作函数指针,是对硬件层的封装。cs为使用SPI接口时,片选操作函数指针。delay为延时函数的指针。

3.2、基于对象进行操作

对象初始化完成后就可进行相应的操作。ADXL345的操作比较简单就是调用GetValueFromAdxl345函数获取我们需要的数据。具体的调用样式如下:

GetValueFromAdxl345(&adxl345);

这个使用比较简单,因为我们在初始化时将数据格式、数据速率及功率模式、电源特性、中断使能、各轴的数据偏移量等都按我们的需要在初始化时作了配置。如果需要不同配置则需要做相应的修改。

4、应用总结

在我们的应用中,我们将其设置为全分辨率,±16g的测量范围,读取数据与预期一致。

使用I2C接口时,设备地址使用7位输入或8位输入都没问题,地址一共有4种可能。其他的都为非法地址,在地址输入不符合要求时,会被默认初始化为广播地址。

在使用SPI接口时,如果是通过软件操作片选信号则需要实现操作函数并将函数指针传递给初始化函数。如果硬件上采取永久选中的形式则可将NULL作为参数传入。

欢迎关注:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外设驱动库开发笔记23:AT24Cxx外部存储器驱动

在我们的应用开发过程中&#xff0c;经常会使用到外部的EEPROM外部存储器来保存一些参数和配置数据等。而比较常用的就是AT24Cxx系列产品&#xff0c;这一节我们来开发用于操作AT24Cxx系列产品的驱动。 1、功能概述 AT24Cxx系列EEPROM包括从1Kbit到2Mbit的各种容量。AT24Cxx系…

外设驱动库开发笔记24:FM24xxx系列FRAM存储器驱动

虽然说使用EEPROM保存参数很有效&#xff0c;但操作及使用次数均有一下限制。当我们的一些参数需要不定时修改或存储时&#xff0c;使用FRAM就更为方便一点。这一节我们就来设计并实现FM24xxx系列FRAM的驱动。 1、功能概述 我们首先说一下铁电随机存取存储器&#xff0c;F-RA…

外设驱动库开发笔记25:FM25xxx FRAM存储器驱动

在我们的项目中&#xff0c;时常会有参数或数据需要保存。铁电存储器的优良性能和操作方便常常被我们选用。FM25xxx FRAM存储器就是我们经常使用到的一系列铁电存储器&#xff0c;这一篇我们将讨论FM25xxx FRAM存储器的驱动设计、实现及使用。 1、功能概述 FM25xxx FRAM存储器…

步进电机驱动技术1:基于TMC2660的步进电机驱动

步进电机的应用非常广泛&#xff0c;在各种设备中经常会遇到&#xff0c;而步进电机的驱动则是使用步进电机必不可少的部分&#xff0c;可以有多种方式来实现步进电机的驱动&#xff0c;在这里我们来考虑一下基于TMC2660驱动芯片的步进电机驱动。 1、功能概述 TMC2660是德国T…

外设驱动库开发笔记26:nRF24L01无线通讯驱动

现在无线在我们的生活中无处不在。而我们开发的物联网产品也大量使用无线通讯。在这一篇文章中&#xff0c;我们将讨论nRF24L01无线通讯模块驱动程序的开发与实现。 1、功能概述 nRF24L01是一款工作在2.4~2.5GHz世界通用ISM 频段的单片无线收发器芯片无线收发器包括&#xff…

外设驱动库开发笔记27:ESP8266无线通讯驱动

我们的物联网产品所使用的平台都支持无线通讯&#xff0c;而且无线通讯本身更的成本较低&#xff0c;受到大家的欢迎。在本篇文章中&#xff0c;我们将详细讨论并实现ESP8266无线通讯模块的驱动。 1、功能概述 ESP8266是由乐鑫公司出品的一款物联网芯片&#xff0c;因为价格较…

外设驱动库开发笔记28:W5500以太网控制器

以太网通讯是一种被广泛使用的数据通讯方式。在嵌入式应用中也经常使用&#xff0c;但协议栈的实现并不是一件容易的事。不过有些以太网控制器就带有协议栈&#xff0c;如W5500。在本篇中我们将讨论如何设计并实现W5500以太网控制器的驱动。 1、功能概述 W5500是WIZnet开发的…

外设驱动库开发笔记29:DS17887实时时钟驱动

一些时候&#xff0c;在我们的嵌入式产品中需要记录时间&#xff0c;所以我们就需要获取时钟&#xff0c;当然实现的方式多种多样&#xff0c;有的MCU本身就有这一功能&#xff0c;不过精度较低。当我们的应用要求较高时就需要使用专门的实时时钟芯片&#xff0c;如DS17887。在…

外设驱动库开发笔记30:宇电AI-BUS通讯驱动

嵌入式系统通常都会与外部设备进行通讯&#xff0c;这就涉及到通讯协议的问题。这些通讯协议有的是标准协议有的厂家自定义的协议&#xff0c;如宇电的AI-BUS。在本篇中&#xff0c;我们将讨论AI-BUS的驱动&#xff0c;以便于与宇电设备的通讯。 1、功能概述 宇电的设备使用基…

步进电机驱动技术3:基于ULN2003的步进电机驱动

在我们的项目中&#xff0c;经常使用到低电压小功率的步进电机&#xff0c;此类步进电机若采用驱动器控制不断成本高也过于复杂&#xff0c;我们可以直接使用场效应管或者达林顿管来实现对其的驱动。在本篇中&#xff0c;我们就来讨论一下基于ULN2003A达林顿管实现对步进电机的…

通讯接口应用笔记2:MAX3160实现多协议通讯

在一些应用需求中&#xff0c;我们需要对外部提供串行通讯端口&#xff0c;但这些端口所通讯的目标设备各有不同&#xff0c;接口协议也有RS232以及RS485和RS422多种。面对这种情况&#xff0c;我们当然可以同时设计多个串口以适应不同需要&#xff0c;但无疑对硬件资源是一种浪…

电机速度曲线规划1:梯形速度曲线设计与实现

电机驱动是很常见的应用&#xff0c;在很多系统中我们都会碰到需要改变电机的速度以实现相应的控制功能&#xff0c;这就涉及到电机速度曲线规划的问题。在这篇中我们就来简单讨论一下电机的梯形曲线规划的问题。 1、基本原理 梯形速度曲线控制算法是工业控制领域应用最为广泛…

文件系统应用笔记之一:FatFS在STM32F4上的移植

在实现如U盘文件读写&#xff0c;SD卡的文件读写等工作时&#xff0c;我们往往需要一个文件系统来支持我们的工作。特别在一些MCU应用中&#xff0c;文件系统的加入能明显改善系统交互的友好性。在这一篇中&#xff0c;我们就来讨论FatFS文件系统在STM32F4上的移植和应用。 1、…

通讯接口应用笔记3:使用W5500实现Modbus TCP服务器

前面我们设计实现了W5500的驱动程序&#xff0c;也讲解了驱动的使用方式。在最近一次的项目应用中&#xff0c;正好有一个使用W5500实现TCP通讯的需求&#xff0c;所以我们就使用该驱动程序轻松实现。这一篇中我们就来说一说基于我们W5500通讯驱动程序实现TCP通讯的过程。 1、…

电机速度曲线规划2:S形速度曲线设计与实现

电机驱动是很常见的应用&#xff0c;在很多系统中我们都会碰到需要改变电机的速度以实现相应的控制功能&#xff0c;这就涉及到电机速度曲线规划的问题。在这篇中我们就来简单讨论一下电机的S型曲线规划的问题。 1、基本原理 S型速度曲线控制算法是工业控制领域另一种常用的加…

USB应用开发笔记之一:STM32上实现USB主机读写U盘

在项目应用中&#xff0c;经常会有对外交换数据的需求。USB接口读写U盘无疑是一种颇为方便的选择。在这一篇中&#xff0c;我们就来讨论如何在STM32上实现USB主机读写U盘文件的方法。 1、应用概述 在我们的产品上有这样一个需求&#xff0c;希望通过大容量的U盘存取数据。我们…

Modbus协议栈综合实例设计

自我们开源了我们的Modbus协议栈之后&#xff0c;就一直有朋友来信说希望提供示例。这次我们整理了几个例子以供参考。 1、应用实例规划 在这次的实例中&#xff0c;我们使用的目标板拥有一个以太网接口、一个RS232串行接口和一个RS485串行接口&#xff0c;所以我们规划实现&a…

ThreadX应用开发笔记之二:移植ThreadX到STM32H7平台

前面我们将ThreadX成功移植到了STM32F4平台&#xff0c;但这只是我们的部分应用。我们希望将ThreadX的优势发挥到我们的更多应用中&#xff0c;所以在这一篇中我们就来实现将ThreadX移植到STM32H7平台中。 1、前期准备 在开始将ThreadX移植到STM32H7平台之前&#xff0c;我们需…

外设驱动库开发笔记31:S-Modlue远红外气体传感器驱动

在气体分析类产品中&#xff0c;我们经常会用到远红外气体传感器。我们就在碳氢类气体成分分析中使用了S-Modlue远红外气体传感器。接下来&#xff0c;我们将讨论S-Modlue远红外气体传感器驱动的设计与实现。 1、功能概述 S-MODULE EVO 使用非分散红外检测技术NDIR&#xff0c…

外设驱动库开发笔记32:HLPM025K3 PM2.5传感器驱动

现在人们对大气环境及室内环境都比较关注。PM2.5在生活中也是常见的词汇。在有些产品中就要求检测PM2.5的数值。检测PM2.5的手段多种多样&#xff0c;在要求不高时我们通常可以采用激光模块。在这一篇中&#xff0c;我们将讨论HLPM025K3 PM2.5传感器驱动的设计与实现。 1、功能…