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協議版本

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章