581 lines
29 KiB
C
581 lines
29 KiB
C
#include "stm32f4xx.h" // Device header
|
||
#include "stm32f4xx_conf.h"
|
||
#include "Warming.h"
|
||
#include "Delay.h"
|
||
|
||
/*
|
||
*SPI模式选择:
|
||
*
|
||
*CPOL(时钟极性):
|
||
* 0/Low-空闲状态时,SCK=0
|
||
* 1/High-空闲状态时,SCK=1
|
||
*CPHA(时钟相位):
|
||
* 0/1Edge-SCK第一个边沿移入数据,第二个边沿移出数据
|
||
* 1/2Edge-SCK第一个边沿移出数据,第二个边沿移入数据
|
||
*
|
||
*模式0:CPOL=0,CPHA=0
|
||
*模式1:CPOL=0,CPHA=1
|
||
*模式2:CPOL=1,CPHA=0
|
||
*模式3:CPOL=1,CPHA=1
|
||
*/
|
||
|
||
//加速度计寄存器
|
||
#define BMI088_ACC_CHIP_ID 0x00//加速度计Who Am I寄存器
|
||
#define BMI088_ACC_PWR_CTRL 0x7D//加速度计电源控制寄存器
|
||
#define BMI088_ACC_PWR_CONF 0x7C//加速度计电源配置寄存器
|
||
#define BMI088_ACC_CONF 0x40//加速度计配置寄存器
|
||
#define BMI088_ACC_RANGE 0x41//加速度计范围设置寄存器
|
||
#define BMI088_INT1_IO_CONF 0x53//加速度计配置INT1输入输出引脚寄存器
|
||
#define BMI088_INT1_INT2_MAP_DATA 0x58//加速度计映射数据就绪中断到INT1/INT2寄存器
|
||
#define BMI088_ACC_SOFTRESET 0x7E//加速度计软件重启寄存器
|
||
#define BMI088_ACC_AccelDataStart 0x12//加速度计数据寄存器首地址
|
||
#define BMI088_ACC_TEMP_MSB 0x22//加速度计温度寄存器高八位
|
||
#define BMI088_ACC_TEMP_LSB 0x23//加速度计温度寄存器低三位
|
||
|
||
//陀螺仪寄存器
|
||
#define BMI088_GYRO_CHIP_ID 0x00//陀螺仪Who Am I寄存器
|
||
#define BMI088_GYRO_RANGE 0x0F//陀螺仪范围设置寄存器
|
||
#define BMI088_GYRO_BANDWIDTH 0x10//陀螺仪带宽寄存器
|
||
#define BMI088_GYRO_LPM1 0x11//陀螺仪主电源模式选择寄存器
|
||
#define BMI088_GYRO_INT_CTRL 0x15//陀螺仪中断控制寄存器
|
||
#define BMI088_INT3_INT4_IO_CONF 0x16//陀螺仪配置中断输入输出引脚寄存器
|
||
#define BMI088_INT3_INT4_IO_MAP 0x18//陀螺仪映射数据就绪中断到INT3/INT4寄存器
|
||
#define BMI088_GYRO_SOFTRESET 0x14//陀螺仪软件重启寄存器
|
||
#define BMI088_GYRO_GyroDataStart 0x02//陀螺仪数据寄存器首地址
|
||
|
||
#define BMI088_ACC_Address 0x1E//加速度计地址
|
||
#define BMI088_GYRO_Address 0x0F//陀螺仪地址
|
||
|
||
|
||
#define BMI088_CS_Accel(x) GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(x))//写加速度计的片选引脚
|
||
#define BMI088_CS_Gyro(x) GPIO_WriteBit(GPIOB,GPIO_Pin_0,(BitAction)(x))//写陀螺仪的片选引脚
|
||
|
||
#define BMI088_Accel_Start() BMI088_CS_Accel(0)//BMI088加速度计硬件SPI数据交换开始(拉低BMI088_CS_Accel完成片选)
|
||
#define BMI088_Accel_Stop() BMI088_CS_Accel(1)//BMI088加速度计硬件SPI数据交换结束(拉高BMI088_CS_Accel结束片选)
|
||
#define BMI088_Gyro_Start() BMI088_CS_Gyro(0)//BMI088陀螺仪硬件SPI数据交换开始(拉低BMI088_CS_Gyro完成片选)
|
||
#define BMI088_Gyro_Stop() BMI088_CS_Gyro(1)//BMI088陀螺仪硬件SPI数据交换结束(拉高BMI088_CS_Gyro结束片选)
|
||
|
||
|
||
uint8_t BMI088_SPI_DMASend[8],BMI088_SPI_DMAReceive[8];//BMI088的SPI发送DMA存储器数组,BMI088的SPI接收DMA存储器数组
|
||
uint8_t BMI088_FirstDMA_Flag=2,BMI088_DMAAccGyroSelect;//BMI088的DMA首次启动标志位(0-已经首次启动,1-准备首次启动,2-等待首次启动),BMI088的DMA处于加速度计数据接收还是陀螺仪数据接收的状态选择(1-加速度计数据接收,2-陀螺仪数据接收)
|
||
uint8_t BMI088_DataStartFlag;//BMI088开始接收数据标志位
|
||
|
||
int16_t BMI088_RawAccelData[3],BMI088_RawGyroData[3],BMI088_RawTemperatureData;//BMI088的三轴加速度原始数据,三轴角速度原始数据和温度原始数据
|
||
float BMI088_Accel[3],BMI088_Gyro[3],BMI088_Temperature;//BMI088的三轴加速度数据,三轴角速度数据和温度
|
||
|
||
/*
|
||
*函数简介:BMI088专用微秒级延时
|
||
*参数说明:延时时长,单位us
|
||
*返回类型:无
|
||
*备注:参数范围:0~4294967295
|
||
*/
|
||
void BMI088_Delay_us(uint32_t us)
|
||
{
|
||
uint32_t temp;
|
||
SysTick->LOAD=us*21; //时间加载,我们要延时n倍的us, 1us是一个fac_ua周期,所以总共要延时的周期值为二者相乘最后送到Load中。
|
||
SysTick->VAL=0x00; //清空计数器
|
||
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启使能位 开始倒数
|
||
do temp=SysTick->CTRL;
|
||
while((temp&0x01) && !(temp&(1<<16))); //用来判断 systick 定时器是否还处于开启状态,然后在等待时间到达,也就是数到0的时候,此时第十六位设置为1
|
||
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器使能位
|
||
SysTick->VAL=0x00; //清空计数器
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088加速度计写寄存器
|
||
*参数说明:8bits寄存器地址
|
||
*参数说明:8bits寄存器写入数据
|
||
*返回类型:无
|
||
*备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
|
||
*备注:BMI088的寄存器地址的最高位bit需要为0(即&0x7F),以实现写寄存器
|
||
*/
|
||
void BMI088_SPI_AccelWriteRegister(uint8_t RegAddress,uint8_t Data)
|
||
{
|
||
BMI088_Accel_Start();//开始
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,RegAddress & 0x7F);//将地址(写数据)放入发送缓冲区
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,Data);//SPI发送数据(放入发送缓冲区,实现连续数据流)
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
|
||
SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(接收数据)移位完成
|
||
SPI_I2S_ReceiveData(SPI1);//SPI接收数据,清除接收数据和标志位
|
||
|
||
BMI088_Accel_Stop();//结束
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088加速度计读寄存器
|
||
*参数说明:8bits寄存器地址
|
||
*返回类型:8bits寄存器读出数据
|
||
*备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
|
||
*备注:BMI088的寄存器地址的最高位bit需要为1(即|0x80),以实现读寄存器
|
||
*备注:加速度计读取寄存器时(包括连续读取和非连续读取),第一个读出数据是乱码,从第二个开始才是有效数据
|
||
*/
|
||
uint8_t BMI088_SPI_AccelReadRegister(uint8_t RegAddress)
|
||
{
|
||
BMI088_Accel_Start();//开始
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,RegAddress | 0x80);//将地址(读数据)放入发送缓冲区
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,0x00);//SPI发送数据(放入发送缓冲区,实现连续数据流)
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
|
||
SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,0x00);//SPI发送数据(放入发送缓冲区,实现连续数据流)
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(地址数据)移位完成
|
||
SPI_I2S_ReceiveData(SPI1);//此回传数据为乱码,故读取当前接收缓冲区以清除接收数据和标志位
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第三个数据(接收数据)移位完成
|
||
BMI088_Accel_Stop();//结束
|
||
|
||
return SPI_I2S_ReceiveData(SPI1);//SPI接收数据
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088陀螺仪写寄存器
|
||
*参数说明:8bits寄存器地址
|
||
*参数说明:8bits寄存器写入数据
|
||
*返回类型:无
|
||
*备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
|
||
*备注:BMI088的寄存器地址的最高位bit需要为0(即&0x7F),以实现写寄存器
|
||
*/
|
||
void BMI088_SPI_GyroWriteRegister(uint8_t RegAddress,uint8_t Data)
|
||
{
|
||
BMI088_Gyro_Start();//开始
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,RegAddress & 0x7F);//将地址(写数据)放入发送缓冲区
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,Data);//SPI发送数据(放入发送缓冲区,实现连续数据流)
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
|
||
SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(接收数据)移位完成
|
||
SPI_I2S_ReceiveData(SPI1);//SPI接收数据,清除接收数据和标志位
|
||
|
||
BMI088_Gyro_Stop();//结束
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088陀螺仪读寄存器
|
||
*参数说明:8bits寄存器地址
|
||
*返回类型:8bits寄存器读出数据
|
||
*备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
|
||
*备注:BMI088的寄存器地址的最高位bit需要为1(即|0x80),以实现读寄存器
|
||
*/
|
||
uint8_t BMI088_SPI_GyroReadRegister(uint8_t RegAddress)
|
||
{
|
||
BMI088_Gyro_Start();//开始
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,RegAddress | 0x80);//将地址(读数据)放入发送缓冲区
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
|
||
SPI_I2S_SendData(SPI1,0x00);//SPI发送数据(放入发送缓冲区,实现连续数据流)
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
|
||
SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
|
||
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(接收数据)移位完成
|
||
BMI088_Gyro_Stop();//结束
|
||
|
||
return SPI_I2S_ReceiveData(SPI1);//SPI接收数据
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088初始化
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:使用SPI1,SPI模式3(CPOL=1,CPHA=1),波特率5.25MHz
|
||
*备注:规定SPI1_CLK为PB3,SPI1_MISO为PB4,SPI1_MOSI为PA7,CS1_Accel为PA4(加速度计片选引脚),CS1_Gyro为PB0(陀螺仪片选引脚)
|
||
*备注:规定INT1_Accel为PC4,INT1_Gyro为PC5,分别连接芯片的INT1和INT3,配置为数据就绪中断(下降沿)
|
||
*备注:采用SPI收发DMA节约CPU资源(SPI1发送DMA为DMA2数据流3通道3,SPI1接收DMA为DMA2数据流2通道3)
|
||
*备注:在初始化中对寄存器进行了配置,最关键配置为加速度量程±3g,角速度量程±2000°/s
|
||
*备注:配置寄存器时会对加速度计和陀螺仪进行软重启,加速度计耗时1ms,陀螺仪耗时30ms,同时软重启之后第一次读写有bug,数据会错误
|
||
*备注:加速度计软重启之后需要重新上电,需要配置BMI088_ACC_PWR_CTRL和BMI088_ACC_PWR_CONF两个寄存器,每次配置需要等待一段时间,测试得到250us足矣,共耗时500us,保险起见采用300us,共耗时600us
|
||
*备注:保险起见在每一次配置寄存器之后加入300us的延时,共计3.6ms
|
||
*备注:初始化时会检查加速度计和陀螺仪的ID,ID错误会进行报警,并且程序会卡死不断的进行检测,具体报警现象见Warming.h
|
||
*/
|
||
void BMI088_Init(void)
|
||
{
|
||
/*===============配置时钟===============*/
|
||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
|
||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
|
||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
|
||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//开启时钟
|
||
|
||
/*===============配置GPIO===============*/
|
||
GPIO_InitTypeDef GPIO_InitStructure;
|
||
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
|
||
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
|
||
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//默认上拉
|
||
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
|
||
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
|
||
GPIO_Init(GPIOA,&GPIO_InitStructure);//配置CS1_Accel(加速度计片选引脚)
|
||
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
|
||
GPIO_Init(GPIOB,&GPIO_InitStructure);//配置CS1_Gyro(陀螺仪片选引脚)
|
||
|
||
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//复用推挽
|
||
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3 | GPIO_Pin_4;
|
||
GPIO_Init(GPIOB,&GPIO_InitStructure);//配置SPI1_CLK和SPI1_MISO
|
||
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
|
||
GPIO_Init(GPIOA,&GPIO_InitStructure);//配置SPI1_MOSI
|
||
|
||
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;//上拉输入
|
||
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;
|
||
GPIO_Init(GPIOC,&GPIO_InitStructure);//配置INT1_Accel和INT1_Gyro(加速度计和陀螺仪的中断线)
|
||
|
||
GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_SPI1);//开启PA7的SPI1复用模式
|
||
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1);//开启PB3的SPI1复用模式
|
||
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1);//开启PB4的SPI1复用模式
|
||
|
||
/*===============配置SPI和SPI收发DMA===============*/
|
||
SPI_InitTypeDef SPI_InitStructure;
|
||
SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//主机模式
|
||
SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//双线全双工
|
||
SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//8位数据帧
|
||
SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;//高位先行
|
||
SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_8;//波特率预分频系数8,SCK频率为PCLK/分频系数,即Freq_SCK=42MHz/8=5.25MHz
|
||
SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;//CPOL=1
|
||
SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;//第二个边沿开始采样,即CPHA=1
|
||
SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;//软件NSS模式
|
||
SPI_InitStructure.SPI_CRCPolynomial=10;//CRC检测,不懂
|
||
SPI_Init(SPI1,&SPI_InitStructure);
|
||
|
||
DMA_InitTypeDef DMA_InitStructure;
|
||
DMA_InitStructure.DMA_Channel=DMA_Channel_3;//选择DMA通道3
|
||
DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//普通模式(非自动重装)
|
||
DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral;//转运方向为存储器到外设
|
||
DMA_InitStructure.DMA_BufferSize=8;//数据传输量为8字节
|
||
DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh;//最高优先级
|
||
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&(SPI1->DR);//外设地址(SPI1的DR数据接收寄存器)
|
||
DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//外设突发单次传输
|
||
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设数据长度为1字节(8bits)
|
||
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不自增
|
||
DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)BMI088_SPI_DMASend;//存储器地址(BMI088的SPI发送DMA存储器数组)
|
||
DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;//存储器突发单次传输
|
||
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//存储器数据长度为1字节(8bits)
|
||
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器地址自增
|
||
DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//不使用FIFO模式
|
||
DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOStatus_1QuarterFull;//设置FIFO阈值为1/4(不使用FIFO模式时,此位无意义)
|
||
DMA_Init(DMA2_Stream3,&DMA_InitStructure);//初始化数据流3(SPI1发送DMA)
|
||
|
||
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//转运方向为外设到存储器
|
||
DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)BMI088_SPI_DMAReceive;//存储器地址(BMI088的SPI接收DMA存储器数组)
|
||
DMA_Init(DMA2_Stream2,&DMA_InitStructure);//初始化数据流2(SPI1接收DMA)
|
||
|
||
SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);//使能SPI1的发送DMA搬运
|
||
SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);//使能SPI1的接收DMA搬运
|
||
|
||
BMI088_CS_Accel(1);//复位CS1_Accel(加速度计片选引脚)
|
||
BMI088_CS_Gyro(1);//复位CS1_Gyro(陀螺仪片选引脚)
|
||
|
||
/*===============配置外部中断和SPI1接收DMA传输完成中断===============*/
|
||
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource4);//配置PC4与中断线的映射关系
|
||
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource5);//配置PC5与中断线的映射关系
|
||
|
||
EXTI_InitTypeDef EXTI_InitStructure;
|
||
EXTI_InitStructure.EXTI_Line=EXTI_Line4;//配置中断线4
|
||
EXTI_InitStructure.EXTI_LineCmd=ENABLE;//使能中断线
|
||
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//配置为外部中断模式
|
||
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//选择下降沿触发
|
||
EXTI_Init(&EXTI_InitStructure);//初始化EXTI
|
||
EXTI_InitStructure.EXTI_Line=EXTI_Line5;//配置中断线5
|
||
EXTI_Init(&EXTI_InitStructure);//初始化EXTI
|
||
|
||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择NVIC分组为2
|
||
|
||
NVIC_InitTypeDef NVIC_InitStructure;
|
||
NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn;//配置NVIC通道4
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能NVIC通道
|
||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
|
||
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
|
||
NVIC_Init(&NVIC_InitStructure);//初始化NVIC
|
||
NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;//配置NVIC通道9_5
|
||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
|
||
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
|
||
NVIC_Init(&NVIC_InitStructure);//初始化NVIC
|
||
|
||
DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);//打通SPI1到NVIC的接收传输完成中断通道
|
||
|
||
NVIC_InitStructure.NVIC_IRQChannel=DMA2_Stream2_IRQn;//选择SPI1接收DMA传输完成中断通道
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中断通道
|
||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级为1
|
||
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级为1
|
||
NVIC_Init(&NVIC_InitStructure);//初始化SPI1接收DMA传输完成中断的NVIC
|
||
|
||
/*===============使能===============*/
|
||
DMA_Cmd(DMA2_Stream3,DISABLE);//失能DMA2的数据流3(SPI1发送DMA)
|
||
DMA_Cmd(DMA2_Stream2,DISABLE);//失能DMA2的数据流2(SPI1接收DMA)
|
||
SPI_Cmd(SPI1,ENABLE);//使能SPI1
|
||
|
||
/*===============检测加速度计和陀螺仪ID并配置寄存器===============*/
|
||
while(1)
|
||
{
|
||
if(BMI088_SPI_AccelReadRegister(BMI088_ACC_CHIP_ID)==BMI088_ACC_Address && BMI088_SPI_GyroReadRegister(BMI088_GYRO_CHIP_ID)==BMI088_GYRO_Address)//设备连接正常,加速度计和陀螺仪Who Am I正确
|
||
{
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//关闭NVIC通道
|
||
NVIC_Init(&NVIC_InitStructure);//初始化NVIC
|
||
|
||
BMI088_SPI_AccelWriteRegister(BMI088_ACC_SOFTRESET,0xB6);BMI088_Delay_us(1000);//加速度计软重启,耗时1ms
|
||
BMI088_SPI_GyroWriteRegister(BMI088_GYRO_SOFTRESET,0xB6);BMI088_Delay_us(30000);//陀螺仪软重启,耗时30ms
|
||
|
||
BMI088_SPI_AccelReadRegister(BMI088_ACC_CHIP_ID);//再次读取ID,促使从机BMI088的SPI重新开始工作(软重启之后第一次读写有bug)
|
||
BMI088_SPI_GyroReadRegister(BMI088_GYRO_CHIP_ID);
|
||
|
||
BMI088_SPI_AccelWriteRegister(BMI088_ACC_PWR_CTRL,0x04);BMI088_Delay_us(300);//打开加速度计
|
||
BMI088_SPI_AccelWriteRegister(BMI088_ACC_PWR_CONF,0x00);BMI088_Delay_us(300);//加速度计正常工作(不挂起)
|
||
BMI088_SPI_AccelWriteRegister(BMI088_ACC_CONF,0xAB);BMI088_Delay_us(300);//配置加速度计正常低通滤波带宽,800Hz输出
|
||
BMI088_SPI_AccelWriteRegister(BMI088_ACC_RANGE,0x00);BMI088_Delay_us(300);//配置加速度计量程±3g
|
||
BMI088_SPI_AccelWriteRegister(BMI088_INT1_IO_CONF,0x08);BMI088_Delay_us(300);//配置加速度计INT1推挽输出,低电平有效(下降沿)
|
||
BMI088_SPI_AccelWriteRegister(BMI088_INT1_INT2_MAP_DATA,0x04);BMI088_Delay_us(300);//配置INT1中断映射为数据就绪中断
|
||
|
||
BMI088_SPI_GyroWriteRegister(BMI088_GYRO_RANGE,0x00);BMI088_Delay_us(300);//配置陀螺仪量程±2000°/s
|
||
BMI088_SPI_GyroWriteRegister(BMI088_GYRO_BANDWIDTH,0x82);BMI088_Delay_us(300);//配置陀螺仪滤波器带宽116Hz,1000Hz输出(写此寄存器,写入数据最高位需要为1)
|
||
BMI088_SPI_GyroWriteRegister(BMI088_GYRO_LPM1,0x00);BMI088_Delay_us(300);//配置陀螺仪主电源模式为正常模式
|
||
BMI088_SPI_GyroWriteRegister(BMI088_GYRO_INT_CTRL,0x80);BMI088_Delay_us(300);//使能陀螺仪数据就绪中断
|
||
BMI088_SPI_GyroWriteRegister(BMI088_INT3_INT4_IO_CONF,0x00);BMI088_Delay_us(300);//配置陀螺仪INT3推挽输出,低电平有效(下降沿)
|
||
BMI088_SPI_GyroWriteRegister(BMI088_INT3_INT4_IO_MAP,0x01);BMI088_Delay_us(300);//配置INT3中断映射为数据就绪中断
|
||
|
||
BMI088_FirstDMA_Flag=1;//准备首次启动DMA
|
||
break;
|
||
}
|
||
else//设备异常
|
||
{
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd=DISABLE;//关闭NVIC通道
|
||
NVIC_Init(&NVIC_InitStructure);//初始化NVIC
|
||
Warming_BMI088LinkError();//BMI088连接异常报警
|
||
Delay_ms(25);
|
||
}
|
||
}
|
||
|
||
while(BMI088_DataStartFlag==0);//等待数据开始接收
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088处理加速度计数据
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:本函数用于SPI接收DMA传输完成之后,数据来源为BMI088的SPI接收DMA存储器数组BMI088_SPI_DMAReceive
|
||
*备注:加速度a(m2/s)=a_raw(g)*9.8=(a_raw/32768*Range)*9.8
|
||
* =(a_raw/32768*3)*9.8
|
||
* =a_raw*0.0008974358974
|
||
*/
|
||
void BMI088_ProcessAccelData(void)
|
||
{
|
||
BMI088_RawAccelData[0]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[3]<<8|BMI088_SPI_DMAReceive[2]);//拼接为原始数据
|
||
BMI088_RawAccelData[1]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[5]<<8|BMI088_SPI_DMAReceive[4]);
|
||
BMI088_RawAccelData[2]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[7]<<8|BMI088_SPI_DMAReceive[6]);
|
||
|
||
BMI088_Accel[0]=BMI088_RawAccelData[0]*0.0008974358974f;
|
||
BMI088_Accel[1]=BMI088_RawAccelData[1]*0.0008974358974f;
|
||
BMI088_Accel[2]=BMI088_RawAccelData[2]*0.0008974358974f;
|
||
// BMI088_Accel[0]=BMI088_RawAccelData[0]/32768.0f*9.8f*3.0f;
|
||
// BMI088_Accel[1]=BMI088_RawAccelData[1]/32768.0f*9.8f*3.0f;
|
||
// BMI088_Accel[2]=BMI088_RawAccelData[2]/32768.0f*9.8f*3.0f;
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088处理温度数据
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:本函数用于SPI接收DMA传输完成之后,数据来源为BMI088的SPI接收DMA存储器数组BMI088_SPI_DMAReceive
|
||
*备注:温度t(℃)=t_raw*0.125+23
|
||
*备注:温度数据是11bits数据
|
||
*/
|
||
void BMI088_ProcessTemperatureData(void)
|
||
{
|
||
uint16_t unsignedTemperatureData=((uint16_t)BMI088_SPI_DMAReceive[2]<<3) | (BMI088_SPI_DMAReceive[3]>>5);//拼接为原始数据
|
||
|
||
if(unsignedTemperatureData>1023)BMI088_RawTemperatureData=unsignedTemperatureData-2048;//对11bits数据进行正负数处理
|
||
else BMI088_RawTemperatureData=unsignedTemperatureData;
|
||
|
||
BMI088_Temperature=BMI088_RawTemperatureData*0.125f+23.0f;
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088处理陀螺仪数据
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:本函数用于SPI接收DMA传输完成之后,数据来源为BMI088的SPI接收DMA存储器数组BMI088_SPI_DMAReceive
|
||
*备注:角速度w(rad/s)=w_raw(°/s)/180*Π=(w_raw/32768*Range)/180*Π
|
||
* =(w_raw/32768*2000)/180*Π
|
||
* =w_raw*0.00106526443603169529841533860381
|
||
*/
|
||
void BMI088_ProcessGyroData(void)
|
||
{
|
||
BMI088_RawGyroData[0]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[2]<<8|BMI088_SPI_DMAReceive[1]);//拼接为原始数据
|
||
BMI088_RawGyroData[1]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[4]<<8|BMI088_SPI_DMAReceive[3]);
|
||
BMI088_RawGyroData[2]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[6]<<8|BMI088_SPI_DMAReceive[5]);
|
||
|
||
BMI088_Gyro[0]=BMI088_RawGyroData[0]*0.00106526443603169529841533860381f;
|
||
BMI088_Gyro[1]=BMI088_RawGyroData[1]*0.00106526443603169529841533860381f;
|
||
BMI088_Gyro[2]=BMI088_RawGyroData[2]*0.00106526443603169529841533860381f;
|
||
// BMI088_Gyro[0]=BMI088_RawGyroData[0]/32768.0f*2000.0f/180.0f*3.141592653589793238462643383279f;
|
||
// BMI088_Gyro[1]=BMI088_RawGyroData[1]/32768.0f*2000.0f/180.0f*3.141592653589793238462643383279f;
|
||
|
||
// BMI088_Gyro[2]=BMI088_RawGyroData[2]/32768.0f*2000.0f/180.0f*3.141592653589793238462643383279f;
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088检测并关闭DMA
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:用在外部中断中用来等待SPI传输结束后配合BMI088_OpenDMA函数重新启动DMA
|
||
*/
|
||
void BMI088_CheckAndCloseDMA(void)
|
||
{
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY)==SET);//等待总线空闲
|
||
while(DMA_GetFlagStatus(DMA2_Stream3,DMA_FLAG_TCIF3)==RESET);//判断发送完成
|
||
DMA_ClearFlag(DMA2_Stream3,DMA_FLAG_TCIF3);//清除发送完成标志位
|
||
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY)==SET);//等待总线空闲
|
||
DMA_Cmd(DMA2_Stream3,DISABLE);//失能DMA2的数据流2
|
||
DMA_Cmd(DMA2_Stream2,DISABLE);//失能DMA2的数据流3
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088开启DMA
|
||
*参数说明:DMA传输数据个数
|
||
*返回类型:无
|
||
*备注:SPI收发DMA开启后会立刻开始发送接收,请在使用函数前配置BMI088的SPI发送DMA存储器数组BMI088_SPI_DMASend
|
||
*/
|
||
void BMI088_OpenDMA(uint8_t DMA_BufferSize)
|
||
{
|
||
while(DMA_GetCmdStatus(DMA2_Stream2)!=DISABLE);//检测DMA2的数据流2为可配置状态
|
||
DMA_SetCurrDataCounter(DMA2_Stream2,DMA_BufferSize);//恢复传输计数器的值
|
||
DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA2的数据流2
|
||
while(DMA_GetCmdStatus(DMA2_Stream3)!=DISABLE);//检测DMA2的数据流3为可配置状态
|
||
DMA_SetCurrDataCounter(DMA2_Stream3,DMA_BufferSize);//恢复传输计数器的值
|
||
DMA_Cmd(DMA2_Stream3,ENABLE);//使能DMA2的数据流3
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088加速度计外部中断中断函数
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:在中断函数中启动DMA收发以实现减少CPU负担
|
||
*/
|
||
void EXTI4_IRQHandler(void)
|
||
{
|
||
if(EXTI_GetITStatus(EXTI_Line4)==SET)//检测BMI088加速度计外部中断触发(即检测EXTI通道4中断触发)
|
||
{
|
||
EXTI_ClearITPendingBit(EXTI_Line4);//清除标志位
|
||
|
||
if(BMI088_FirstDMA_Flag==0)//非第一次启动DMA
|
||
{
|
||
BMI088_CheckAndCloseDMA();//关闭DMA准备配置
|
||
|
||
BMI088_Accel_Start();//片选加速度计
|
||
BMI088_DMAAccGyroSelect=1;//DMA为加速度计数据接收
|
||
BMI088_SPI_DMASend[0]=BMI088_ACC_AccelDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
|
||
|
||
BMI088_OpenDMA(8);//开启DMA转运8个数据
|
||
}
|
||
else if(BMI088_FirstDMA_Flag==1)//第一次启动DMA
|
||
{
|
||
BMI088_FirstDMA_Flag=0;
|
||
|
||
BMI088_Accel_Start();//片选加速度计
|
||
BMI088_DMAAccGyroSelect=1;//DMA为加速度计数据接收
|
||
BMI088_SPI_DMASend[0]=BMI088_ACC_AccelDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
|
||
|
||
DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA2的数据流2
|
||
DMA_Cmd(DMA2_Stream3,ENABLE);//使能DMA2的数据流3
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
*函数简介:BMI088陀螺仪外部中断中断函数
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:在中断函数中启动DMA收发以实现减少CPU负担
|
||
*备注:第一次DMA转运8个数据,从第二次DMA开始转运7个数据
|
||
*/
|
||
void EXTI9_5_IRQHandler(void)
|
||
{
|
||
if(EXTI_GetITStatus(EXTI_Line5)==SET)//检测BMI088陀螺仪外部中断触发(即检测EXTI通道5中断触发)
|
||
{
|
||
EXTI_ClearITPendingBit(EXTI_Line5);//清除标志位
|
||
|
||
if(BMI088_FirstDMA_Flag==0)//非第一次启动DMA
|
||
{
|
||
BMI088_CheckAndCloseDMA();//关闭DMA准备配置
|
||
|
||
BMI088_Gyro_Start();//片选陀螺仪
|
||
BMI088_DMAAccGyroSelect=2;//DMA为陀螺仪数据接收
|
||
BMI088_SPI_DMASend[0]=BMI088_GYRO_GyroDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
|
||
|
||
BMI088_OpenDMA(7);//开启DMA转运7个数据
|
||
}
|
||
else if(BMI088_FirstDMA_Flag==1)//第一次启动DMA
|
||
{
|
||
BMI088_FirstDMA_Flag=0;
|
||
|
||
BMI088_Gyro_Start();//片选陀螺仪
|
||
BMI088_DMAAccGyroSelect=2;//DMA为陀螺仪数据接收
|
||
BMI088_SPI_DMASend[0]=BMI088_GYRO_GyroDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
|
||
|
||
DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA2的数据流2
|
||
DMA_Cmd(DMA2_Stream3,ENABLE);//使能DMA2的数据流3
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
*函数简介:SPI1接收DMA传输完成中断中断函数
|
||
*参数说明:无
|
||
*返回类型:无
|
||
*备注:在此函数中会处理接收数据获取BMI088的三轴加速度数据,三轴角速度数据和温度
|
||
*备注:在此函数中如果接收的是加速度计数据会再开启一个DMA去接收温度数据
|
||
*/
|
||
void DMA2_Stream2_IRQHandler(void)
|
||
{
|
||
if(DMA_GetITStatus(DMA2_Stream2,DMA_IT_TCIF2)==SET)//检测SPI1接收DMA传输完成中断触发
|
||
{
|
||
static uint8_t BMI088_ReceiveTEMPFlag=0;//BMI088的DMA接收温度数据标志位(0-未在接收温度数据,1-正在接收温度数据)
|
||
BMI088_DataStartFlag=1;//数据开始接收
|
||
DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);//清除标志位
|
||
|
||
if(BMI088_ReceiveTEMPFlag==1)//正在接收温度数据
|
||
{
|
||
BMI088_Accel_Stop();//结束加速度计片选
|
||
BMI088_ProcessTemperatureData();//处理温度数据
|
||
BMI088_ReceiveTEMPFlag=0;
|
||
}
|
||
else//接收加速度或角速度数据
|
||
{
|
||
if(BMI088_DMAAccGyroSelect==1)//接收加速度计数据
|
||
{
|
||
BMI088_Accel_Stop();//结束加速度计片选
|
||
BMI088_ProcessAccelData();//处理加速度数据
|
||
|
||
BMI088_ReceiveTEMPFlag=1;//开始接收温度数据
|
||
BMI088_CheckAndCloseDMA();//关闭DMA准备配置
|
||
|
||
BMI088_Accel_Start();//片选加速度计
|
||
BMI088_SPI_DMASend[0]=BMI088_ACC_TEMP_MSB | 0x80;//配置SPI的发送数据的地址(读数据)
|
||
|
||
BMI088_OpenDMA(4);//开启DMA转运4个数据
|
||
}
|
||
else if(BMI088_DMAAccGyroSelect==2)//接收陀螺仪数据
|
||
{
|
||
BMI088_Gyro_Stop();//结束陀螺仪片选
|
||
BMI088_ProcessGyroData();//处理陀螺仪数据
|
||
}
|
||
}
|
||
}
|
||
}
|