ADXL345 三轴加速度数据SPI读取、多字节读取、DMA SPI读取和FIFO数据读取

ADXL345 三轴加速度数据SPI读取、多字节读取、DMA SPI读取和FIFO数据读取

1、简介及注意事项

  ADXL345传感器分辨率13,测量范围±16g(可选±2、±4、±8g),输出数据格式为16位补码,可通过SPI(三线或者四线)或者IIC接口读取。同时还支持32级的FIFO数据存储,满足快速读取数据的要求。

  1. 关于初始化
    一般初始化0x31,0x2D,0x2C,0x2F,0x38,0x2E,0x1E,0x1F,0x20这些寄存器即可。关于这些寄存器的说明,具体可以参考手册。
    需要注意的一点是:如果要使用中断进行数据读取,那么初始化之前对中断寄存器清零,所有其他功能初始化完之后,再设置中断使能。
   SpiWriteCmd(0x2E,0x00);       // 中断寄存器清零
   
   SpiWriteCmd(0x31,0x0B);       // 4线SPI 全分辨率  g加速度范围
   SpiWriteCmd(0x2D,0x08);       // 传感器测量模式
   SpiWriteCmd(0x2C,0x0E);       // 传感器传输数据速率1600HZ
    
   SpiWriteCmd(0x2F,0x03);       // 中断映射
   SpiWriteCmd(0x38,0x94);       // FIFO模式设置

   SpiWriteCmd(0x1E,0x00);       // X轴偏移量
   SpiWriteCmd(0x1F,0x00);       // Y轴偏移量
   SpiWriteCmd(0x20,0x00);       // Z轴偏移量
   
   SpiWriteCmd(0x2E,0x83);       //中断寄存器使能
  1. SPI时钟要求
    在设置读取速率的时候,要和SPI的时钟匹配起来,否则可能读到错误的数据,比如设置1600HZ,SPI时钟要大于2MHZ。SPI读取数据时钟最大5MHZ。
  2. SPI总线的理解
    SPI要读取一个数据,必须先写入一个数据。在写入数据的时候,时钟线才会启动。
  3. 读写以及多字节读取指令的区别
    在这里插入图片描述
    从上面可以看出,
    读的时候,地址的最高位为1;
    写的时候,地址的最高位为0;
    在进行多字节读取的时候,次高位为1,
    这样才可以多字节写和读;

2、SPI数据读取

话不多说,直接上代码,本文采用STMF407读取数据,SPI数据位8位,全双工,软件控制片选,高位在前(MB First),

SPI.h

#define ADS_SPI_PORT               GPIOB
#define ADS_SPI_CS_PIN             GPIO_Pin_12
#define ADS_SPI_SCK_PIN            GPIO_Pin_13
#define ADS_SPI_MISO_PIN           GPIO_Pin_14
#define ADS_SPI_MOSI_PIN           GPIO_Pin_15

#define ADS_SPI_CS_HIGH()          GPIO_SetBits(ADS_SPI_PORT, ADS_SPI_CS_PIN)
#define ADS_SPI_CS_LOW() 	       GPIO_ResetBits(ADS_SPI_PORT, ADS_SPI_CS_PIN)

SPI.c
unsigned char ADXL345RXBuff[250];     //DMA 接收缓存
unsigned char ADXL345TXBuff[10];      //DMA 发送缓存

// SPI IO口初始化
void Spi2IOInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  // Enable GPIOC clocks 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  // Connect SPI2 pins to AF5
  GPIO_PinAFConfig(ADS_SPI_PORT, GPIO_PinSource13, GPIO_AF_SPI2);  // SCK
  GPIO_PinAFConfig(ADS_SPI_PORT, GPIO_PinSource14, GPIO_AF_SPI2);  // MISO
  GPIO_PinAFConfig(ADS_SPI_PORT, GPIO_PinSource15, GPIO_AF_SPI2);  // MOSI
  
  // SPI SCK¡¢MOSI pin configuration
  GPIO_InitStructure.GPIO_Pin = ADS_SPI_SCK_PIN|ADS_SPI_MOSI_PIN|ADS_SPI_MISO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//GPIO_PuPd_DOWN;//GPIO_PuPd_UP;//GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_Init(ADS_SPI_PORT, &GPIO_InitStructure);
  
  //SPI2 NSS pin in output pushpull mode 
  GPIO_InitStructure.GPIO_Pin = ADS_SPI_CS_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  //GPIO_PuPd_NOPULL;
  GPIO_Init(ADS_SPI_PORT, &GPIO_InitStructure);
	
  ADS_SPI_CS_HIGH();  // cs default state is high
  ADS_SPI_CS_LOW(); 
  ADS_SPI_CS_HIGH(); 
}

// SPI模式初始化
void SPI2Init(void)
{
  SPI_InitTypeDef  SPI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  SPI_I2S_DeInit(SPI2);
  //Enable the SPI periph 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
  Spi2IOInit();
  
  // SPI configuration
  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_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;  // SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI2, &SPI_InitStructure);

  // Enable the SPI2
  SPI_Cmd(SPI2, ENABLE);
}
// SPI写指令
void SpiWriteCmd(u8 cmd,u8 data)
{
  ADS_SPI_CS_LOW(); 
	
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = (cmd);
	while((SPI2->SR &0x0001)==0);
	SPI_I2S_ReceiveData(SPI2); 
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = (data);
	while((SPI2->SR &0x0001)==0);
	SPI_I2S_ReceiveData(SPI2); 

  ADS_SPI_CS_HIGH();
}
// SPI读指令
u8 SpiReadCmd(u8 cmd)
{
  ADS_SPI_CS_LOW(); 
  
	unsigned char returnvalue;
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = (cmd|0x80);
	while((SPI2->SR &0x0001)==0);
	returnvalue =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = (0x00);
	while((SPI2->SR &0x0001)==0);
	returnvalue =(unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus
	
  ADS_SPI_CS_HIGH();
	return(returnvalue);  
}

void ADXL345Init()
{
	u8 TempData;
	SPI2Init();
    TempData = SpiReadCmd(0x00);
	while(TempData!=0xE5)     //判断是否器件ID正确 验证SPI通信是否正常
	{
		SendData(&TempData,1);
	}
	SpiWriteCmd(0x2E,0x00);    
	
	SpiWriteCmd(0x31,0x0B);
	SpiWriteCmd(0x2D,0x08);
	SpiWriteCmd(0x2C,0x0E);
	SpiWriteCmd(0x2E,0x00);
	SpiWriteCmd(0x38,0x00);
	SpiWriteCmd(0x2F,0x00);
	
	SpiWriteCmd(0x1E,0x00);
	SpiWriteCmd(0x1F,0x00);
	SpiWriteCmd(0x20,0x00); 
}

void ReadADXL345Data()
{
  unsigned char StrBuff[50];
  short int Acc_X=0,Acc_Y=0,Acc_Z=0;
  unsigned char Buf[6];
 
  Buf[0]=SpiReadCmd(0x32);
  Buf[1]=SpiReadCmd(0x33);
  
  Buf[2]=SpiReadCmd(0x34);
  Buf[3]=SpiReadCmd(0x35);
  
  Buf[4]=SpiReadCmd(0x36);
  Buf[5]=SpiReadCmd(0x37);
  

  Acc_X = ((Buf[1]<<8|Buf[0]));
  Acc_Y = ((Buf[3]<<8|Buf[2]));
  Acc_Z = ((Buf[5]<<8|Buf[4]));
  
  
  sprintf(StrBuff,"X=%4.3f    m/s2   Y=%4.3f   m/s2   Z=%4.3f   m/s2 \r\n",Acc_X*3.9/1000*9.8,Acc_Y*3.9/1000*9.8,Acc_Z*3.9/1000*9.8);
  SendData(StrBuff,strlen(StrBuff));

读取加速度传感器结果,本文中将g转换成m/s2结果显示。
在这里插入图片描述

3、多字节读取

  多字节读取的方式和常规不同的就是:
  无需自己手动修改读取数据的地址,
  外部传感器自动修改地址并传输,
  多字节读取时序图如下:
在这里插入图片描述
  从上面可以看出,在发送0xF2之后,无论发送什么数据,都自动传回六个数据。
  有的好奇宝宝可能会问,为什么是0xF2呢?
  因为读指令最高位为1,次高位为多字节位,要置1,而寄存器的数据地址为0x32,这样或则可以得到0xF2

void ContinuousReadADXL345Data()
{
  unsigned char StrBuff[50];
  short int Acc_X=0,Acc_Y=0,Acc_Z=0;
  unsigned char Buf[6];
 

	ADS_SPI_CS_LOW(); 
  
	unsigned char returnvalue;
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = 0x32|0xC0;
	while((SPI2->SR &0x0001)==0);
	Buf[0] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus


    while((SPI2->SR &0x0002)==0);  
	SPI2->DR = 0x00;
	while((SPI2->SR &0x0001)==0);
	Buf[0] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus//	Buf[1] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2));

	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = 0x00;
	while((SPI2->SR &0x0001)==0);
	Buf[1] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus
	
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = 0x00;
	while((SPI2->SR &0x0001)==0);
	Buf[2] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus
	
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = 0x00;
	while((SPI2->SR &0x0001)==0);
	Buf[3] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus
	
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = 0x00;
	while((SPI2->SR &0x0001)==0);
	Buf[4] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus
	
	while((SPI2->SR &0x0002)==0);  
	SPI2->DR = 0x00;
	while((SPI2->SR &0x0001)==0);
	Buf[5] =  (unsigned char)(SPI_I2S_ReceiveData(SPI2)); // Return the Byte read from the SPI bus
	
    ADS_SPI_CS_HIGH();
	
    Acc_X = ((Buf[1]<<8|Buf[0]));
    Acc_Y = ((Buf[3]<<8|Buf[2]));
    Acc_Z = ((Buf[5]<<8|Buf[4]));
  
    sprintf(StrBuff,"X=%4.1f***Y=%4.1f***Z=%4.1f\r\n",Acc_X*3.9/1000*9.8,Acc_Y*3.9/1000*9.8,Acc_Z*3.9/1000*9.8);
    SendData(StrBuff,strlen(StrBuff));
}

  从上面可以看出,只需填写第一个寄存器的地址之后,后面的数据可以直接读取,无需再修改寄存器。

4、DMA 多字节读取

  使用DMA进行数据读取,在这里我使用数据更新中断去读取数据。
  设置INT1数据更新中断使能,触发外中断去开始DMA数据数据传输。

void SPI2Init(void)
{
  SPI_InitTypeDef  SPI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  SPI_I2S_DeInit(SPI2);
  //Enable the SPI periph 
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
  Spi2IOInit();
  
  // SPI configuration
  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_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;  // SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI2, &SPI_InitStructure);

  // Enable the SPI2
  SPI_Cmd(SPI2, ENABLE);
	
	
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
  NVIC_Init(&NVIC_InitStructure);

  MyDMAInit();   
  EXTIX_Init();     
}

void MyDMAInit()
{
  DMA_InitTypeDef  DMA_InitStructure;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA时钟
  DMA_DeInit(DMA1_Stream3);  //SPI_RX
	
  /* DMA Stream 3 */
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;  //
  DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)(&(SPI2->DR));·
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)(&ADXL345RXBuff[0]);//
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//
  DMA_InitStructure.DMA_BufferSize = FIFO_COUNT*7;//
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//
	
  DMA_Init(DMA1_Stream3, &DMA_InitStructure);//³õʼ»¯DMA Stream
  SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Rx,ENABLE);
  DMA_ITConfig(DMA1_Stream3, DMA_IT_TC, ENABLE);
  DMA_Cmd(DMA1_Stream3, DISABLE);
	
  DMA_DeInit(DMA1_Stream4);  //SPI_TX
	  /* DMA Stream 4*/
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;  //
  DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)(&(SPI2->DR));//
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)(&ADXL345TXBuff[0]);//DMA
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//
  DMA_InitStructure.DMA_BufferSize = 7;//
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//
	
  DMA_Init(DMA1_Stream4, &DMA_InitStructure);//
  SPI_I2S_DMACmd(SPI2,SPI_I2S_DMAReq_Tx,ENABLE);
  //  DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);
}

void EXTIX_Init()
{
  NVIC_InitTypeDef   NVIC_InitStructure;
  EXTI_InitTypeDef   EXTI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//GPIO_PuPd_DOWN;//GPIO_PuPd_UP;//GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
	
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource8);//
	
  EXTI_InitStructure.EXTI_Line = EXTI_Line8;//LINE8
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;//
  EXTI_Init(&EXTI_InitStructure);//
	
  NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;//
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//
  NVIC_Init(&NVIC_InitStructure);
}

u8 ExtiFlag=0;     // 数据更新中断标志位
void EXTI9_5_IRQHandler()
{
	if(EXTI_GetITStatus(EXTI_Line8))
	{
		   
	    DMA_Cmd(DMA1_Stream3, DISABLE); 
	    DMA_Cmd(DMA1_Stream4, DISABLE); 
		u8 TempData = SpiReadCmd(0x30);
		if((TempData&0x80))
		     ExtiFlag=1;
		EXTI_ClearITPendingBit(EXTI_Line8);
	}
}

void SPIDMAReadADXL345Data()
{
	int pro=0;
	ADS_SPI_CS_LOW(); 
	
	DMA_Cmd(DMA1_Stream3, ENABLE);
	ADXL345TXBuff[0]=0xF2;
	
	ADXL345TXBuff[1]=0x00;
	ADXL345TXBuff[2]=0x00;
	ADXL345TXBuff[3]=0x00;
	ADXL345TXBuff[4]=0x00;
	ADXL345TXBuff[5]=0x00;
	ADXL345TXBuff[6]=0x00;
	
	DMA_Cmd(DMA1_Stream4, DISABLE); 
	DMA_SetCurrDataCounter(DMA1_Stream4,7);          
    DMA_Cmd(DMA1_Stream4, ENABLE);
	
	while(DMA_GetFlagStatus(DMA1_Stream4, DMA_FLAG_TCIF4) == RESET)
	{
		 pro=DMA_GetCurrDataCounter(DMA1_Stream4);
	}
	DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_TCIF4);
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY)==SET);       //需要等待SPI总线传输完成最后一个字节,否则Z轴数据存在问题。
	
	ADS_SPI_CS_HIGH();
	ExtiFlag=0;
}

u8 DMAReadFlag = 0;                   // DMA接收数据完成中断标志位
void DMA1_Stream3_IRQHandler()
{
	if (DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3) != RESET)
   {
      DMA_ClearFlag(DMA1_Stream3, DMA_IT_TCIF3);
	  DMAReadFlag=1;
	  DMA_Cmd(DMA1_Stream3, DISABLE);
   }
}

void ReadDMAData()
{

	short int Acc_X=0,Acc_Y=0,Acc_Z=0;
	unsigned char StrBuff[50];
	
	if(ExtiFlag==1)                       //数据更新中断,则开始DMA读取数据
	{
		SPIDMAReadADXL345Data();
	}
	if(DMAReadFlag)                        //读取数据完成之后,则开始计算三轴并显示
	{
	  Acc_X = ((ADXL345RXBuff[2]<<8|ADXL345RXBuff[1]));
      Acc_Y = ((ADXL345RXBuff[4]<<8|ADXL345RXBuff[3]));
      Acc_Z = ((ADXL345RXBuff[6]<<8|ADXL345RXBuff[5]));
  
      sprintf(StrBuff,"X=%4.3f    Y=%4.3f     Z=%4.3f\r\n",Acc_X*3.9/1000*9.8,Acc_Y*3.9/1000*9.8,Acc_Z*3.9/1000*9.8);
      SendData(StrBuff,strlen(StrBuff));
	  DMAReadFlag=0;
	}
}

5、DMA FIFO数据读取

  FIFO模式共分为三种,FIFO模式,流模式和触发模式一般使用前两种,FIFO模式存满缓存区之后则不再继续填充数据,而流模式则继续回覆盖之前已存在的数据。
  FIFO最大缓存32级数据,即32个三轴数据,总共32*6=192个数据。FIFO可设置存满一定字节后触发中断,中断为水印中断(Watermark 奇怪的名字)。存满之后继续填充缓存器,直到存满32级缓存。所以不需要完全存满再去读取数据,那样时效性不高,可设置16级之后就读取数据,这样类似于半中断,效率更高。
  这个FIFO唯一一点不好的地方我觉得是,FIFO数据不是一次性读出,而是多次通过寄存器去读取意思就是FIFO数据的读取地址就是0x32-0x37,读完之后,FIFO缓存就往寄存器里填充缓存的数据,然后再去读,直到填充完。
  使用水印中断来触发外中断去读取FIFO数据。

void ADXL345Init()
{
	u8 TempData;
	SPI2Init();
    TempData = SpiReadCmd(0x00);
	while(TempData!=0xE5)
	{
		SendData(&TempData,1);
	}
	SpiWriteCmd(0x2E,0x00);       
	
	SpiWriteCmd(0x31,0x0B);      
	SpiWriteCmd(0x2D,0x08);      
	SpiWriteCmd(0x2C,0x0E);      
	 
	SpiWriteCmd(0x2F,0x03);       
	SpiWriteCmd(0x38,0x9F);       // 设置FIFO模式   10011111   32条目  流模式   只保存最新数据

	SpiWriteCmd(0x1E,0x00);      
	SpiWriteCmd(0x1F,0x00);       
	SpiWriteCmd(0x20,0x00);      
	
	SpiWriteCmd(0x2E,0x83);       //设置INT2 为水印中断
	
    ADXL345TXBuff[0]=0xF2;        //DMA 发送缓存
    ADXL345TXBuff[1]=0x00;
	ADXL345TXBuff[2]=0x00;
	ADXL345TXBuff[3]=0x00;
	ADXL345TXBuff[4]=0x00;
	ADXL345TXBuff[5]=0x00;
	ADXL345TXBuff[6]=0x00;
}

u8 ExtiFlag=0;
void EXTI9_5_IRQHandler()
{
	if(EXTI_GetITStatus(EXTI_Line8))
	{
		DMA_Cmd(DMA1_Stream3, DISABLE); 
		DMA_Cmd(DMA1_Stream4, DISABLE); 
		u8 TempData = SpiReadCmd(0x30);    //读取中断标志位   确定中断产生
		if((TempData&0x02))
		     ExtiFlag=1;
		EXTI_ClearITPendingBit(EXTI_Line8);
	}
}


void SPIDMAReadADXL345Data()
{

	u8 i=0;
	DMA_Cmd(DMA1_Stream3, ENABLE);
	
	for(i=0;i<FIFO_COUNT;i++)       //FIFO_COUNT  代表触发FIFO缓存个数
	{
		ADS_SPI_CS_LOW(); 
		
		DMA_Cmd(DMA1_Stream4, DISABLE); 
		DMA_SetCurrDataCounter(DMA1_Stream4,7);          /
		DMA_Cmd(DMA1_Stream4, ENABLE);
		
		while(DMA_GetFlagStatus(DMA1_Stream4, DMA_FLAG_TCIF4) == RESET)
		{
			 DMA_GetCurrDataCounter(DMA1_Stream4);//
		}
		DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_TCIF4);
		while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY)==SET);
	
	    ADS_SPI_CS_HIGH();
		
  }
	
   ExtiFlag=0;
}

u8 DMAReadFlag = 0;
void DMA1_Stream3_IRQHandler()
{
	if (DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3) != RESET)
   {
       DMA_ClearFlag(DMA1_Stream3, DMA_IT_TCIF3);
	   DMAReadFlag=1;
	   DMA_Cmd(DMA1_Stream3, DISABLE);
    }
}

void ReadDMAData()
{
	short int Acc_X=0,Acc_Y=0,Acc_Z=0;
	unsigned char StrBuff[50];
	unsigned char C=10;    
	if(ExtiFlag==1)     
	{
		SPIDMAReadADXL345Data();      
	}
	if(DMAReadFlag)                 
	{
	  Acc_X = ((ADXL345RXBuff[7*C+2]<<8|ADXL345RXBuff[7*C+1]));
      Acc_Y = ((ADXL345RXBuff[7*C+4]<<8|ADXL345RXBuff[7*C+3]));
      Acc_Z = ((ADXL345RXBuff[7*C+6]<<8|ADXL345RXBuff[7*C+5]));
  
      sprintf((char *)StrBuff,"X=%4.3f    Y=%4.3f     Z=%4.3f\r\n",Acc_X*3.9/1000*9.8,Acc_Y*3.9/1000*9.8,Acc_Z*3.9/1000*9.8);
      SendData(StrBuff,strlen((char *)StrBuff));
      DMAReadFlag=0;
	}
}

  最后楼主分享一个完整的代码,使用STM32F407读取ADXL345三轴加速度传感器数据,keil工程。
下载链接:
工程文件 SPI协议版本
工程文件 SPI+DMA协议版本

如有雷同,纯属我抄你,有问题可以直接联系邮箱,在个人资料里面。
  • 22
    点赞
  • 121
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张一西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值