ADXL345 三軸加速度數據SPI讀取、多字節讀取、DMA SPI讀取和FIFO數據讀取
1、簡介及注意事項
ADXL345傳感器分辨率13位,測量範圍±16g(可選±2、±4、±8g),輸出數據格式爲16位補碼,可通過SPI(三線或者四線)或者IIC接口讀取。同時還支持32級的FIFO數據存儲,滿足快速讀取數據的要求。
- 關於初始化
一般初始化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); //中斷寄存器使能
- SPI時鐘要求
在設置讀取速率的時候,要和SPI的時鐘匹配起來,否則可能讀到錯誤的數據,比如設置1600HZ,SPI時鐘要大於2MHZ。SPI讀取數據時鐘最大5MHZ。 - SPI總線的理解
SPI要讀取一個數據,必須先寫入一個數據。在寫入數據的時候,時鐘線纔會啓動。 - 讀寫以及多字節讀取指令的區別
從上面可以看出,
讀的時候,地址的最高位爲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協議版本