STM32:SPI驱动ADXL345

2019-06-13来源: 互联网关键字:STM32  SPI驱动  ADXL345

ADXL345为3轴数字加速度计。支持SPI或I2C访问。网上例子大多是I2C,这里使用4线SPI。


一、遇过的坑

调试过程花了几个小时,遇到一些小坑。


1.开始的时候,无论如何都无法读取芯片ID。这可是最基础的一步啊,SPI,I2C都试过。无奈之下,对照原理图与手册的管脚说明,发现Vs接到地了。其实这个管脚要接电源电压。老实说,一看名字还以为要接地,毕竟一般IC接地脚名字为Vss。让硬件工程师飞线修改。终于可以进行通信了。


2.发现数据跳动比较大。静止放置,也会出现很大的数据波动。看上去并不是噪声导致的。最后发现手册上对SPI速率与输出数据速率的相关性。重新修改SPI速率,输出数据终于稳定多了,再加上软件滤波,终于满足项目使用。


3.芯片手册推荐读取加速度数据时使用多字节连续读取,这样可确保数据完整性。我估计当CS被脚拉低后芯片就会禁止修改相关数据寄存器和FIFO的修改。不过手册对于多字节读取的时序图太粗略。



暂时没时间搞单次多字节读取。估计STM32的硬件SPI没有办法做到,以后有时间再研究。


二、代码

 


 

/******************ADXL345寄存器命令定义**********************/

#define DEVICE_ID           0X00        //获取器件ID,0XE5

#define THRESH_TAP          0X1D        //敲击阀值

#define OFSX                0X1E //x轴调整偏移值

#define OFSY                0X1F

#define OFSZ                0X20

#define DUR                 0X21

#define Latent              0X22

#define Window              0X23

#define THRESH_ACK          0X24

#define THRESH_INACT        0X25

#define TIME_INACT          0X26

#define ACT_INACT_CTL       0X27

#define THRESH_FF           0X28

#define TIME_FF             0X29

#define TAP_AXES            0X2A

#define ACT_TAP_STATUS      0X2B

#define BW_RATE             0X2C

#define POWER_CTL           0X2D

 

#define INT_ENABLE          0X2E

#define INT_MAP             0X2F

#define INT_SOURCE          0X30

#define DATA_FORMAT        0X31

#define DATA_X0            0X32

#define DATA_X1            0X33

#define DATA_Y0            0X34

#define DATA_Y1            0X35

#define DATA_Z0            0X36

#define DATA_Z1            0X37

#define FIFO_CTL            0X38

#define FIFO_STATUS         0X39

 

#define I_M_DEVID      ((uint8_t)0xE5) //器件ID=0XE5

 

/******************SPI管脚配置宏**********************/

#define ADXL345_SPIX                      SPI2

#define ADXL345_SPI_RCC                   RCC_APB1Periph_SPI2

 

#define ADXL345_SPI_SCK_PIN               GPIO_Pin_13

#define ADXL345_SPI_SCK_GPIO_PORT         GPIOB

#define ADXL345_SPI_SCK_GPIO_RCC          RCC_AHB1Periph_GPIOB

#define ADXL345_SPI_SCK_SOURCE            GPIO_PinSource13

#define ADXL345_SPI_SCK_AF                GPIO_AF_SPI2

 

#define ADXL345_SPI_MISO_PIN              GPIO_Pin_14

#define ADXL345_SPI_MISO_GPIO_PORT        GPIOB

#define ADXL345_SPI_MISO_GPIO_RCC         RCC_AHB1Periph_GPIOB

#define ADXL345_SPI_MISO_SOURCE           GPIO_PinSource14

#define ADXL345_SPI_MISO_AF               GPIO_AF_SPI2

 

#define ADXL345_SPI_MOSI_PIN              GPIO_Pin_15

#define ADXL345_SPI_MOSI_GPIO_PORT        GPIOB

#define ADXL345_SPI_MOSI_GPIO_RCC         RCC_AHB1Periph_GPIOB

#define ADXL345_SPI_MOSI_SOURCE           GPIO_PinSource15

#define ADXL345_SPI_MOSI_AF               GPIO_AF_SPI2

 

#define ADXL345_SPI_CS_PIN                GPIO_Pin_12

#define ADXL345_SPI_CS_GPIO_PORT          GPIOB

#define ADXL345_SPI_CS_GPIO_RCC           RCC_AHB1Periph_GPIOB

 

#define ADXL345_CS_LOW()       GPIO_ResetBits(ADXL345_SPI_CS_GPIO_PORT, ADXL345_SPI_CS_PIN)

#define ADXL345_CS_HIGH()      GPIO_SetBits(ADXL345_SPI_CS_GPIO_PORT, ADXL345_SPI_CS_PIN)

// SPI2 :PB12(cs) ,PB13(clk) ,PB14(miso)  ,PB15(mosi)

static void  _spi_init(void)

{

    GPIO_InitTypeDef  GPIO_InitStructure;

    SPI_InitTypeDef  SPI_InitStructure;

 

    RCC_AHB1PeriphClockCmd(ADXL345_SPI_SCK_GPIO_RCC|ADXL345_SPI_CS_GPIO_RCC, ENABLE);//使能GPIO时钟

    RCC_APB1PeriphClockCmd(ADXL345_SPI_RCC, ENABLE);//使能SPI时钟

 

    //sck miso mosi初始化设置

    GPIO_InitStructure.GPIO_Pin = ADXL345_SPI_SCK_PIN| ADXL345_SPI_MISO_PIN | ADXL345_SPI_MOSI_PIN ;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;   //复用功能

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 

    GPIO_Init(ADXL345_SPI_SCK_GPIO_PORT, &GPIO_InitStructure); 

 

    GPIO_PinAFConfig(ADXL345_SPI_SCK_GPIO_PORT,  ADXL345_SPI_SCK_SOURCE,  ADXL345_SPI_SCK_AF);  //复用配置

    GPIO_PinAFConfig(ADXL345_SPI_MISO_GPIO_PORT, ADXL345_SPI_MISO_SOURCE, ADXL345_SPI_MISO_AF); //复用配置

    GPIO_PinAFConfig(ADXL345_SPI_MOSI_GPIO_PORT, ADXL345_SPI_MOSI_SOURCE, ADXL345_SPI_MOSI_AF); //复用配置

    

    //cs初始化设置

    GPIO_InitStructure.GPIO_Pin = ADXL345_SPI_CS_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

    GPIO_Init(ADXL345_SPI_CS_GPIO_PORT, &GPIO_InitStructure);//初始化

    ADXL345_CS_HIGH();

 

    RCC_APB2PeriphResetCmd(ADXL345_SPI_RCC, ENABLE); //复位SPI

    RCC_APB2PeriphResetCmd(ADXL345_SPI_RCC, DISABLE); //停止复位SPI

    //spi配置

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工

    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;        //设置SPI工作模式:设置为主SPI

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;        //设置SPI的数据大小:SPI发送接收16位帧结构

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;        //串行同步时钟的空闲状态为高电平

    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;    //串行同步时钟的第二个跳变沿(上升或下降)数据被采样

    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;        //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;        //定义波特率预分频的值:波特率预分频值 84M/psc

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;    //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始

    SPI_InitStructure.SPI_CRCPolynomial = 7;    //CRC值计算的多项式

    SPI_Init(ADXL345_SPIX, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

 

    SPI_Cmd(ADXL345_SPIX, ENABLE); //使能SPI外设

}

/***********************************全局函数***********************************/

 

//读取三个方向的加速度

void memsdrv_ReadXYZ(int16_t *x, int16_t *y, int16_t *z)

{

    uint8_t BUF[6];

 

    BUF[0] = ADXL345_read_byte(0x32);

    BUF[1] = ADXL345_read_byte(0x33);

 

    BUF[2] = ADXL345_read_byte(0x34);

    BUF[3] = ADXL345_read_byte(0x35);

 

    BUF[4] = ADXL345_read_byte(0x36);

    BUF[5] = ADXL345_read_byte(0x37);

 

    *x = ((u16)BUF[1] << 8) + BUF[0];

    *y = ((u16)BUF[3] << 8) + BUF[2];

    *z = ((u16)BUF[5] << 8) + BUF[4];

 

}

//初始化ADXL345.

//返回值:0,初始化成功;其他值,初始化失败.

u8  memsdrv_Init(void)

{

    _spi_init();

    //_exit_init();

    delay_ms(500);

    if( ADXL345_read_byte( DEVICE_ID ) == I_M_DEVID )

    {

ADXL345_write_byte(DATA_FORMAT, 0X0b); //BIT6:SPI4线模式(默认);BIT5:中断电平0/1(高/

[1] [2]

关键字:STM32  SPI驱动  ADXL345

编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic464492.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32 CDC HOST初步调试
下一篇:IAR环境下STM32F103ZET6+IAP方案的实现

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

第38章 I2S—音频播放与录音输入—零死角玩转STM32-F429系列

本章参考资料:《STM32F4xx 中文参考手册》、《STM32F4xx规格书》、库帮助文档《stm32f4xx_dsp_stdperiph_lib_um.chm》及《I2S BUS》。若对I2S通讯协议不了解,可先阅读《I2S BUS》文档的内容学习。关于音频编译码器WM8978,请参考其规格书《WM8978_v4.5》来了解。38.1 I2S简介Inter-IC Sount Bus(I2S)是飞利浦半导体公司(现为恩智浦半导体公司)针对数字音频设备之间的音频数据传输而制定的一种总线标准。在飞利浦公司的I2S标准中,既规定了硬件接口规范,也规定了数字音频数据的格式。38.1.1 数字音频技术现实生活中的声音是通过一定介质传播
发表于 2019-09-19
第38章 I2S—音频播放与录音输入—零死角玩转STM32-F429系列

第50章 读写内部FLASH—零死角玩转STM32-F429系列

本章参考资料:《STM32F4xx 中文参考手册》、《STM32F4xx规格书》、库说明文档《stm32f4xx_dsp_stdperiph_lib_um.chm》。50.1 STM32的内部FLASH简介在STM32芯片内部有一个FLASH存储器,它主要用于存储代码,我们在电脑上编写好应用程序后,使用下载器把编译后的代码文件烧录到该内部FLASH中,由于FLASH存储器的内容在掉电后不会丢失,芯片重新上电复位后,内核可从内部FLASH中加载代码并运行,见图 501。图 501 STM32的内部框架图除了使用外部的工具(如下载器)读写内部FLASH外,STM32芯片在运行的时候,也能对自身的内部FLASH进行读写
发表于 2019-09-19
第50章 读写内部FLASH—零死角玩转STM32-F429系列

第49章 在SRAM中调试代码—零死角玩转STM32-F429系列

本章参考资料:《STM32F4xx 中文参考手册》、《STM32F4xx规格书》、《Cortex-M3权威指南》、《Cortex-M4 Technical Reference Manual》(跟M3大部分是相同的,读英文不习惯可先参考《Cortex-M3权威指南》)。学习本章时,配合《STM32F4xx 中文参考手册》"存储器和总线结构"及"嵌入式FLASH接口"章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。49.1 在RAM中调试代码一般情况下,我们在MDK中编写工程应用后,调试时都是把程序下载到芯片的内部FLASH运行测试的,代码的CODE及RW-data的内容被写入
发表于 2019-09-19
第49章 在SRAM中调试代码—零死角玩转STM32-F429系列

第48章 MDK的编译过程及文件类型全解—零死角玩转STM32-F429

本章参考资料:MDK的帮助手册《ARM Development Tools》,点击MDK界面的"help->uVision Help"菜单可打开该文件。关于ELF文件格式,参考配套资料里的《ELF文件格式》文件。在本章中讲解了非常多的文件类型,学习时请跟着教程的节奏,打开实际工程中的文件来了解。相信您已经非常熟练地使用MDK创建应用程序了,平时使用MDK编写源代码,然后编译生成机器码,再把机器码下载到STM32芯片上运行,但是这个编译、下载的过程MDK究竟做了什么工作?它编译后生成的各种文件又有什么作用?本章节将对这些过程进行讲解,了解编译及下载过程有助于理解芯片的工作原理,这些知识对制作IAP
发表于 2019-09-19
第48章 MDK的编译过程及文件类型全解—零死角玩转STM32-F429

第47章 QR-Decoder-OV5640二维码识别—零死角玩转STM32-F429系列

本章参考资料:《STM32F4xx 中文参考手册》、《STM32F4xx规格书》、库帮助文档《stm32f4xx_dsp_stdperiph_lib_um.chm》。关于开发板配套的OV5640摄像头参数可查阅《ov5640datasheet》配套资料获知。STM32F4芯片具有浮点运算单元,适合对图像信息使用DSP进行基本的图像处理,其处理速度比传统的8、16位机快得多,而且它还具有与摄像头通讯的专用DCMI接口,所以使用它驱动摄像头采集图像信息并进行基本的加工处理非常适合。本章讲解如何使用二维码识别库进行二维码的识别。47.1 二维码简介二维码,又称二维条码或二维条形码,二维条码是用某种特定的几何图形按一定规律在平面(二维方向
发表于 2019-09-19
第47章 QR-Decoder-OV5640二维码识别—零死角玩转STM32-F429系列

第44章 MPU6050传感器—姿态检测—零死角玩转STM32-F429系列

本章参考数据:《STM32F4xx参考手册》、《STM32F4xx规格书》、库说明文档《stm32f4xx_dsp_stdperiph_lib_um.chm》。关于MPU6050的参考资料:《MPU-60X0寄存器》、《MPU6050数据手册》以及官方驱动《motion_driver_6.12》。本章讲解的内容跨领域的知识较多,若您感兴趣,请自行查阅各方面的资料,对比学习。44.1 姿态检测1.    基本认识在飞行器中,飞行姿态是非常重要的参数,见图 441,以飞机自身的中心建立坐标系,当飞机绕坐标轴旋转的时候,会分别影响偏航角、横滚角及俯仰角。图 441 表示飞机姿态的偏航角、横滚角及俯仰角假如我们知道飞机
发表于 2019-09-19
第44章 MPU6050传感器—姿态检测—零死角玩转STM32-F429系列

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved