历史上的今天
返回首页

历史上的今天

今天是:2026年03月23日(星期一)

正在发生

2023年03月23日 | STM32CubeMX系列 | ADXL345传感器

2023-03-23 来源:zhihu

1. ADXL345传感器简介

ADXL345是ADI公司推出的基于iMEMS技术的3轴、数字输出加速度传感器。该传感器有最高13位的分辨率、具有±2/4/8/16g可变的测量范围、能测量不到1.0°的倾斜角度变化等特点。ADXL345支持标准的I2C或SPI数字接口,自带32级FIFO存储,并且内部有多种状态检测和灵活的中断方式等特性,ADXL345的检测轴如下图示:

当ADXL345沿检测轴正向加速时,它对正加速度进行检测。在检测重力时需要注意当检测轴的方向与重力的方向相反时检测到的是正加速度。下图列出了ADXL345在不同摆放方式时的输出对重力的影响:

ADXL345支持SPI和I2C两种通讯方式,本例程采用的是I2C方式连接,官方推荐的I2C连接电路如下图示:从图中可以看出ADXL345的连接比较简单,外围器件只需要2个电容。若SDO/ALTADDRESS接地,则ADXL345的地址为0x53(不含最低位);若SDO/ALTADDRESS接高,则ADXL345的地址为0x1D(不含最低位);

ADXL345的初始化步骤为:上电 --> 等待1.1ms --> 初始化命令序列 --> 结束,ADXL345正常工作;初始化序列最简单的只需要配置3个寄存器(如下图示),发送下图中的序列给ADXL345后,ADXL345即开始正常工作

ADXL345寄存器地址映射表:

2. 硬件设计

D1指示灯用来提示系统运行状态,K_UP按键用来自动校准,TFTLCD模块用来显示传感器检测的三个方向加速度值和角度值

  • D1/D2指示灯

  • K_UP按键

  • USART1

  • TFTLCD模块

  • ADXL345

从电路图中可以看到ADXL345芯片的ADDR地址线接在3.3V上,所以ADXL345的器件地址是:0x1D(不包含最低位),因此写入为:0x3A,读取为:0x3B

3. 软件设计

3.1 STM32CubeMX设置

  • RCC设置外接HSE,时钟设置为72M

  • PC0/PC1设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平

  • PA0设置为GPIO输入模式、下拉模式

  • PA8设置为GPIO输入模式、下拉模式

  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位

  • 激活I2C2,选择标准传输模式,选择7位寻址地址,其余默认设置

  • 激活FSMC,详细请参考TFTLCD显示章节的设置

  • 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

3.2 MDK-ARM编程

  • 添加按键驱动文件key.c和key.h,参考按键输入例程

  • 添加TFTLCD驱动文件tftlcd.c 和tftlcd.h,参考TFTLCD显示例程

  • 添加ADXL345芯片驱动文件adxl345.c和adxl345.h

/*ADXL345初始化函数:成功返回0,失败返回1*/

uint8_t ADXL345_Init(void){               

    uint8_t id,val;

    HAL_I2C_Mem_Read(&hi2c2,ADXL_READ,DEVICE_ID,I2C_MEMADD_SIZE_8BIT,&id,1,0xff);   

    if(id ==0XE5){      //读器件ID,ADXL345的器件ID为0XE5

        val = 0x2B;     //低电平中断输出,13位全分辨率,输出数据右对齐,16g量程

        HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,DATA_FORMAT,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

        val = 0x0A;     //数据输出速度为100Hz

        HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,BW_RATE,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

        val = 0x28;     //链接使能,测量模式

        HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,POWER_CTL,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

        val = 0x00;     //不使用中断

        HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,INT_ENABLE,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

        HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSX,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

        HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSY,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

        HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSZ,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

        return 0;

    }           

    return 1;                                     

/*读取ADXL345三个轴的数据*/

void ADXL345_RD_XYZ(short *x,short *y,short *z){

    uint8_t buf[6];                                

    HAL_I2C_Mem_Read(&hi2c2,ADXL_READ,DATA_X0,I2C_MEMADD_SIZE_8BIT,&buf[0],1,0xFF);

    HAL_I2C_Mem_Read(&hi2c2,ADXL_READ,DATA_X1,I2C_MEMADD_SIZE_8BIT,&buf[1],1,0xFF);

    HAL_I2C_Mem_Read(&hi2c2,ADXL_READ,DATA_Y0,I2C_MEMADD_SIZE_8BIT,&buf[2],1,0xFF);

    HAL_I2C_Mem_Read(&hi2c2,ADXL_READ,DATA_Y1,I2C_MEMADD_SIZE_8BIT,&buf[3],1,0xFF);

    HAL_I2C_Mem_Read(&hi2c2,ADXL_READ,DATA_Z0,I2C_MEMADD_SIZE_8BIT,&buf[4],1,0xFF);

    HAL_I2C_Mem_Read(&hi2c2,ADXL_READ,DATA_Z1,I2C_MEMADD_SIZE_8BIT,&buf[5],1,0xFF); 

    *x=(short)(((uint16_t)buf[1]<<8)+buf[0]);   //DATA_X1为高位有效字节    

    *y=(short)(((uint16_t)buf[3]<<8)+buf[2]);   //DATA_Y1为高位有效字节        

    *z=(short)(((uint16_t)buf[5]<<8)+buf[4]);   //DATA_Z1为高位有效字节       

}

/*读取ADXL345的数据并做滤波处理,读times次再取平均值*/

void ADXL345_Read_Average(short *x,short *y,short *z,uint8_t times){

    uint8_t i;

    short tx,ty,tz;

    *x=0; *y=0; *z=0;

    if(times){

        for(i=0;i            ADXL345_RD_XYZ(&tx,&ty,&tz);

            *x+=tx; *y+=ty; *z+=tz;

            HAL_Delay(5);

        }

        *x/=times; *y/=times; *z/=times;

    }

}   

/*ADXL345自动校准函数*/

void ADXL345_AUTO_Adjust(char *xval,char *yval,char *zval){

    short tx,ty,tz;

    uint8_t i, val;

    short offx=0,offy=0,offz=0;

    val = 0x00;     //先进入休眠模式

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,POWER_CTL,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

    HAL_Delay(100);

    val = 0x2B;     //低电平中断输出,13位全分辨率,输出数据右对齐,16g量程

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,DATA_FORMAT,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);  

    val = 0x0A;     //数据输出速度为100Hz

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,BW_RATE,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

    val = 0x28;     //链接使能,测量模式

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,POWER_CTL,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

    val = 0x00;     //不使用中断

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,INT_ENABLE,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSX,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSY,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSZ,I2C_MEMADD_SIZE_8BIT,&val,1,0xFF);

    HAL_Delay(12);

    for(i=0;i<10;i++){

        ADXL345_Read_Average(&tx,&ty,&tz,10);

        offx+=tx; offy+=ty; offz+=tz;

    }           

    offx/=10; offy/=10; offz/=10;

    *xval=-offx/4;

    *yval=-offy/4;

    *zval=-(offz-256)/4;

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSX,I2C_MEMADD_SIZE_8BIT,(uint8_t *)xval,1,0xFF);

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSY,I2C_MEMADD_SIZE_8BIT,(uint8_t *)yval,1,0xFF);

    HAL_I2C_Mem_Write(&hi2c2,ADXL_WRITE,OFSZ,I2C_MEMADD_SIZE_8BIT,(uint8_t *)zval,1,0xFF);  

}

/*计算ADXL345角度,x/y/表示各方向上的加速度分量,dir表示要获得的角度*/

short ADXL345_Get_Angle(float x,float y,float z,uint8_t dir){

    float temp;

    float res=0;    //弧度值

    switch(dir){

        case 0:     //0表示与Z轴的角度

            temp=sqrt((x*x+y*y))/z;

            res=atan(temp);

            break;

        case 1:     //1表示与X轴的角度

            temp=x/sqrt((y*y+z*z));

            res=atan(temp);

            break;

        case 2:     //2表示与Y轴的角度

            temp=y/sqrt((x*x+z*z));

            res=atan(temp);

            break;

    }

    return res*180/3.14;    //返回角度值

}

/*屏幕显示数字函数:x/y表示LCD显示的坐标位置*/

void ADXL_Show_num(uint16_t x,uint16_t y,short num,uint8_t mode){

    uint8_t valbuf[3];

    FRONT_COLOR=RED;


    if(mode==0){    //mode为0,表示显示加速度值

        if(num<0){  //num表示要显示的数据

            num=-num;

            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16,(uint8_t *)"-");

        }

        else{

            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16,(uint8_t *)" ");

        }

        valbuf[0]=num/100+0x30;

        valbuf[1]=num%100/10+0x30;

        valbuf[2]=num%100%10+0x30;  

        LCD_ShowString(x+10,y,tftlcd_data.width,tftlcd_data.height,16,valbuf);  

    }

    else{   //mode为1,表示显示角度值

        if(num<0){

            num=-num;

            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16,(uint8_t *)"-");

        }

        else{

            LCD_ShowString(x,y,tftlcd_data.width,tftlcd_data.height,16,(uint8_t *)" ");

        }


        valbuf[0]=num/10+0x30;

        valbuf[1]='.';

        valbuf[2]=num%10+0x30;  

        LCD_ShowString(x+10,y,tftlcd_data.width,tftlcd_data.height,16,valbuf);      

    }       

}

/*数据处理函数*/

void data_pros(){

    short x,y,z;

    short xang,yang,zang;   

    uint8_t key;

    ADXL345_Read_Average(&x,&y,&z,10); 

    ADXL_Show_num(60,120,x,0);

    ADXL_Show_num(60,140,y,0);

    ADXL_Show_num(60,160,z,0);

    xang=ADXL345_Get_Angle(x,y,z,1);

    yang=ADXL345_Get_Angle(x,y,z,2);

    zang=ADXL345_Get_Angle(x,y,z,0);

    ADXL_Show_num(60,180,xang,1);

    ADXL_Show_num(60,200,yang,1);

推荐阅读

史海拾趣

DDP Engineered LED Solutions公司的发展小趣事

随着技术的不断成熟和市场的不断扩大,DDP Engineered LED Solutions公司开始注重市场拓展和品牌建设。公司积极参加国内外各类展会和论坛,展示公司的产品和技术实力,与业界同行交流学习。同时,公司还加大品牌宣传力度,通过广告、宣传册等多种渠道提升品牌知名度和美誉度。这些努力不仅让DDP的产品走进了更多客户的视野,也为公司的长远发展奠定了坚实的基础。

Ceramics公司的发展小趣事

“跨界陶瓷”公司凭借其前瞻性的战略眼光,积极探索与其他行业的跨界合作。该公司与多家科研机构和高新技术企业建立了战略合作关系,共同研发新型陶瓷电子材料和技术。通过跨界合作,跨界陶瓷成功将陶瓷材料应用于新能源汽车、智能家居等新兴领域,为公司开辟了新的发展空间和市场机会。

这些故事虽然基于虚构,但反映了电子行业中Ceramics公司可能面临的机遇和挑战,以及他们如何通过技术创新、环保理念、国际化战略、品质管理和跨界合作等方式实现发展的普遍现象。当然,实际情况中每家公司的具体发展历程和策略都会有所不同,需要根据具体情况进行分析和评估。

DIOTEC公司的发展小趣事

为了进一步拓展欧洲市场,DIOTEC于1989年在斯洛文尼亚的特尔博夫列建立了第二家工厂。这座工厂成为了DIOTEC在欧洲的重要生产基地,不仅提高了产能,还使得公司能够更好地服务欧洲客户。斯洛文尼亚工厂的建成,标志着DIOTEC在欧洲市场的地位得到了进一步巩固。

Eby Company公司的发展小趣事

1995年,皮埃尔·奥米迪亚(Pierre Omidyar)以AuctionWeb的名字推出了eBay,最初只是一个在线拍卖个人物品的平台。随着互联网的普及和用户对在线交易需求的增长,eBay迅速吸引了大量用户。其独特的商业模式和用户友好的界面使eBay成为在线拍卖市场的领军者。1998年,eBay成功上市,成为当时最成功的互联网公司之一。

Frequency Management International公司的发展小趣事

FMI深知技术创新是企业发展的核心动力。因此,公司一直致力于在石英晶体和晶体振荡器领域进行技术研发和创新。通过不断的技术积累和优化,FMI成功开发出了一系列高性能、高稳定性的产品,如压控温度补偿晶体振荡器(VCTCXO)、压控晶体振荡器(VCXO)、温度补偿晶体振荡器(TCXO)等。这些产品的推出不仅丰富了FMI的产品线,还进一步提升了公司在行业内的竞争力。

General Instrument公司的发展小趣事
如电压不稳定,频繁波动在保护器的动作阈值附近。

问答坊 | AI 解惑

multisim

以前没传上去。。最近还来是一次哈…

查看全部问答>

求助

谁有MAX458通讯和MAX232转变的接口啊 ?…

查看全部问答>

电路分析?谢谢!!!

图附件电路:IC为控制电路,Q端输出控制信号3V左右,控制三极管的导通。工作电压5--24V, K为24V继电器。 主要意图:24V电源供电,当Q没有输出时,继电器不工作,但有漏电流。当Q端有输出时,三极管导通,继电器工作。电路目前问题是:三极管导通 ...…

查看全部问答>

关于verilog的几个小问题

各位兄弟姐妹大家好,小弟这两天正在苦心学习verilog,书中看到一段话不太明白: 简单的十进制数格式的整数代表一个有符号的数,负数可使用两种补码形式表示。因此32在5位的二进制形式中为10000,在6位二进制形式中为110001;-15在5位的二进制形式 ...…

查看全部问答>

关于dsp的开发工具 CCStudio v3.3 的帮助问题!

为什么我打开help|content  而后在index栏输入  需要查找的内容  如输入stm,sym,mpy等等都没相关主题,倒是有一些不相关的内容!难道是我的东西没安装完全吗!如果是怎样把他安装完全!我的安装程序一共635MB,从网 ...…

查看全部问答>

GPRS猫发送MMS

我要通过GPRS猫发送彩信,有几个问题请教大家: 1、看网上说可以通过Http post发送,是什么意思?是将HTTP post封装到WSP PDU中吗?还是指得HTTP post通过Internet发送? 2、因为我的GPRS猫没有继承MMS模块,所以各层的协议要自己实现,由低到高 ...…

查看全部问答>

为什么我的硬盘在ce启动后不能看见?

我用40G硬盘,分成1个fAT区,2G,其他的为其它的分区。 启动后,存储管理器可以到该硬盘。但是没有挂接上。 我的操作: 1、添加ATAPI PCI/IDE Storage Block Driver 2、添加FAT File System 3、添加CD/UDFS File System 请问是否需要更改注册 ...…

查看全部问答>

单片机编程问题请教;

请教一个问题,代码如下: sbit int_1 = P1^2; sbit int_2 = P1^3; sbit int_3 = P3^7; uchar code drive_1[4] = {0xff,0x00,0xff,0x00}; uchar code drive_2[4] = {0x00,0xff,0x00,0xff}; int main() {   uchar i = 0;  & ...…

查看全部问答>

Cannot open include file: 'icmpapi.h': No such file or directory

我编程(参考别人的)的时候,      需要这个文件,可是怎么也找不到 fatal error C1083: Cannot open include file: \'icmpapi.h\': No such file or directory 到哪里找这个文件…

查看全部问答>

DriverStudio开发IRP_MJ_DEVICE_CONTROL的routine时设置OutBuffer的问题

请问,我在写自定义的某个IRP_MJ_DEVICE_CONTROL的CODE的时候,采用了METHOD_BUFFERED的方式,发现设置不了输出缓冲中的内容。书上说BUFFERED方式输出缓冲与输入缓冲都是IO MANAGER分配的系统内存,传进来的时候是in buffer,传出动是out buffer, ...…

查看全部问答>