目录
前言
还记得刚学习单片机,内心兴奋像打开了新世界大门,一股脑买了很多电子垃圾,其中MPU6500就是其中一个。回头看接触单片机也算1年了,现在每天除了完成工作任务能力并没有长进,真是愧对之前的一腔热血,故今日从新学习。
一、MPU6500通讯方式
1.I2C通讯
根据手册说明MPU6500支持最大400KHz波特率I2C通讯,但这次重点学习SPI操作方式,后续再对I2C进行学习,未完待续……
2.SPI通讯
手册中介绍了2种SPI通讯方式,普通SPI操作方式最大支持1MHz波特率通讯,另有中断SPI通讯最高通讯速率可以高达20M,目前仅对普通模式进行学习。目前手里图便宜买的开发板,硬件SPI为引出只能使用软件模拟SPI通讯,软件模拟SPI通讯极限速度在1MHz左右(目前基于F407测试)。
SPI读取和写入操作在16个或更多时钟周期(两个或更多字节)中完成,这个第一个字节包含SPI地址,随后的字节包含SPI数据。第一个第一个字节的位包含读/写位,并指示读(1)或写(0)操作。以下7位包含寄存器地址。在多字节读/写的情况下,数据是两个或多个字节:
二、MPU6500定义
1.引脚
我们这里使用的SPI通讯:
Pin_23:SCL/SCLK(SPI_CLK)
Pin_24:SDA/SDI(SPI_MOSI)
Pin_22:nCS(SPI_CS)
Pin_9-11:AOD/SDO(SPI_MISO)
接线如下图(魔性涂鸦):
2.框架
这里留意FSYNC引脚,未使用要连接GND,反正手册这么写,后续验证:
3.寄存器
MPU6500寄存器总Map表如下图:
以下列举一些重要寄存器:
- 陀螺仪偏移寄存器:
注意XYZ的大小端,不知道官方为啥这样设计,目前看来挺反常理;
- 采样率寄存器:
这里可以理解为寄存器刷新速率,可能芯片内部是一定采样率,但是外部串行寄存器刷新速率需要配置,该寄存器需要配合CONGIG寄存器一起使用;
- 配置寄存器
感觉FIFO_MODE最重要吧,这里感觉允许数据覆盖可能更符合大多数使用场景;
先写道这里TODO……
三、驱动
1.模拟SPI
由于图便宜买的开发板实在垃圾,各种通讯口均未引出,故只能使用GPIO模拟SPI通讯,经测试波特率700Khz左右,只需要定义以下GPIO口即可使用,方便多路同时使用,详见以下代码,水平有限欢迎指点;
- 构造模拟SPI通讯口(ST_CLASS_SPIX stSpix)
- 初始化SPI
- 通讯函数
#include "SPIX.h"
bool SPIX_TransData(ST_CLASS_SPIX* stSpi,unsigned char* u8TxDataBuffer,unsigned short u16TxLength,unsigned char* u8RxDataBuffer,unsigned short u16RxLength);
bool SPIX_ReceiveData(ST_CLASS_SPIX* stSpi,unsigned char* u8DataBuffer,unsigned short u16Length);
bool SPIX_SendData(ST_CLASS_SPIX* stSpi,unsigned char* u8DataBuffer,unsigned short u16Length);
void SPIX_Ready(ST_CLASS_SPIX* stSpi);
unsigned char SPIX_WriteReadByte_Mode1(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData);
unsigned char SPIX_WriteReadByte_Mode2(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData);
unsigned char SPIX_WriteReadByte_Mode3(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData);
unsigned char SPIX_WriteReadByte_Mode4(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData);
unsigned char SPIX_WriteReadByte(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData);
/*********************************************************************
* 函数描述:初始化SPI
* 输入说明:
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
void SPIX_GpioInit(ST_CLASS_SPIX* stSpi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pins : SPIX_CLK_Pin*/
GPIO_InitStruct.Pin = stSpi->stSpiGpio_CLK.GPIO_Pin_x;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(stSpi->stSpiGpio_CLK.GPIOx, &GPIO_InitStruct);
/*Configure GPIO pins : SPIX_CS_Pin*/
GPIO_InitStruct.Pin = stSpi->stSpiGpio_CS.GPIO_Pin_x;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(stSpi->stSpiGpio_CS.GPIOx, &GPIO_InitStruct);
/*Configure GPIO pins : SPIX_MOSI_Pin */
GPIO_InitStruct.Pin = stSpi->stSpiGpio_MOSI.GPIO_Pin_x;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(stSpi->stSpiGpio_MOSI.GPIOx, &GPIO_InitStruct);
/*Configure GPIO pin : SPIX_MISO_Pin */
GPIO_InitStruct.Pin = stSpi->stSpiGpio_MISO.GPIO_Pin_x;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(stSpi->stSpiGpio_MISO.GPIOx,&GPIO_InitStruct);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_RESET);
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_RESET);
HAL_GPIO_WritePin(stSpi->stSpiGpio_CS.GPIOx,stSpi->stSpiGpio_CS.GPIO_Pin_x,GPIO_PIN_SET);
}
/*********************************************************************
* 函数描述:模拟SPI发送固定数据接收固定数据
* 输入说明:每次最大发送接收256Byte
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
bool SPIX_TransData(ST_CLASS_SPIX* stSpi,unsigned char* u8TxDataBuffer,unsigned short u16TxLength,unsigned char* u8RxDataBuffer,unsigned short u16RxLength)
{
bool blOutVal = true;
unsigned short u16Cnt;
unsigned char u8DataBuffer[256];
if((u16TxLength > 256) || (u16RxLength > 256))
{
blOutVal = false;
}
else
{
//传输准备
SPIX_Ready(stSpi);
//使能
HAL_GPIO_WritePin(stSpi->stSpiGpio_CS.GPIOx,stSpi->stSpiGpio_CS.GPIO_Pin_x,GPIO_PIN_RESET);
//发送数据
if(u16TxLength != 0)
{
//数据转存
memcpy(u8DataBuffer,u8TxDataBuffer,u16TxLength%256);
//发送
for(unsigned short u16Cnt = 0;u16Cnt < u16TxLength;u16Cnt ++)
{
SPIX_WriteReadByte(stSpi,u8DataBuffer[u16Cnt]);
}
}
if(u16RxLength != 0)
{
//接收
if(u8RxDataBuffer != NULL)
{
for(u16Cnt = 0;u16Cnt < u16RxLength;u16Cnt ++)
{
u8RxDataBuffer[u16Cnt] = SPIX_WriteReadByte(stSpi,0xFF);
}
}
else
{
blOutVal = false;
}
}
//失能
HAL_GPIO_WritePin(stSpi->stSpiGpio_CS.GPIOx,stSpi->stSpiGpio_CS.GPIO_Pin_x,GPIO_PIN_SET);
}
return blOutVal;
}
/*********************************************************************
* 函数描述:模拟SPI接收数据
* 输入说明:每次最大发送256Byte
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
bool SPIX_SendData(ST_CLASS_SPIX* stSpi,unsigned char* u8DataBuffer,unsigned short u16Length)
{
bool blOutVal = true;
unsigned char u8TxDataBuffer[256];
if(u16Length > 256)
{
blOutVal = false;
}
else
{
//数据转存
memcpy(u8TxDataBuffer,u8DataBuffer,u16Length%256);
//传输准备
SPIX_Ready(stSpi);
//使能
HAL_GPIO_WritePin(stSpi->stSpiGpio_CS.GPIOx,stSpi->stSpiGpio_CS.GPIO_Pin_x,GPIO_PIN_RESET);
//发送
for(unsigned short u16Cnt = 0;u16Cnt < u16Length;u16Cnt ++)
{
SPIX_WriteReadByte(stSpi,u8TxDataBuffer[u16Cnt]);
}
//失能
HAL_GPIO_WritePin(stSpi->stSpiGpio_CS.GPIOx,stSpi->stSpiGpio_CS.GPIO_Pin_x,GPIO_PIN_SET);
}
return blOutVal;
}
/*********************************************************************
* 函数描述:模拟SPI接收数据
* 输入说明:每次最大发送256Byte
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
bool SPIX_ReceiveData(ST_CLASS_SPIX* stSpi,unsigned char* u8DataBuffer,unsigned short u16Length)
{
bool blOutVal = true;
unsigned char* u8RxDataBuffer = u8DataBuffer;
if(u16Length > 256)
{
blOutVal = false;
}
else
{
//传输准备
SPIX_Ready(stSpi);
//使能
HAL_GPIO_WritePin(stSpi->stSpiGpio_CS.GPIOx,stSpi->stSpiGpio_CS.GPIO_Pin_x,GPIO_PIN_RESET);
//接收
for(unsigned short u16Cnt = 0;u16Cnt < u16Length;u16Cnt ++)
{
u8RxDataBuffer[u16Cnt] = SPIX_WriteReadByte(stSpi,0xFF);
}
//失能
HAL_GPIO_WritePin(stSpi->stSpiGpio_CS.GPIOx,stSpi->stSpiGpio_CS.GPIO_Pin_x,GPIO_PIN_SET);
}
return blOutVal;
}
/*********************************************************************
* 函数描述:模拟传输一个字节函数
* 输入说明:
* 输出说明:
* 创建日期:2023-07-29
*********************************************************************/
unsigned char SPIX_WriteReadByte(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData)
{
unsigned char u8ReadData = 0;
switch(stSpi->enSpiMode)
{
case SPIX_MODE_1:
{
u8ReadData = SPIX_WriteReadByte_Mode1(stSpi,u8WriteData);
}
break;
case SPIX_MODE_2:
{
u8ReadData = SPIX_WriteReadByte_Mode2(stSpi,u8WriteData);
}
break;
case SPIX_MODE_3:
{
u8ReadData = SPIX_WriteReadByte_Mode3(stSpi,u8WriteData);
}
break;
case SPIX_MODE_4:
{
u8ReadData = SPIX_WriteReadByte_Mode4(stSpi,u8WriteData);
}
break;
default:
{
u8ReadData = 0xFF;
}
break;
}
return u8ReadData;
}
/*********************************************************************
* 函数描述:模拟SPIReady
* 输入说明:复位CLK(在传输过程不去复位提高传输上限速率)
* 输出说明:
* 创建日期:2023-07-29
*********************************************************************/
void SPIX_Ready(ST_CLASS_SPIX* stSpi)
{
if((stSpi->enSpiMode == SPIX_MODE_1) || (stSpi->enSpiMode == SPIX_MODE_2))
{
//CLK空闲低电平
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_RESET);
}
else
{
//CLK空闲高电平
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_SET);
}
}
/*********************************************************************
* 函数描述:模拟SPI工作模式1(CPOL = 0 CPHA = 0)
* 输入说明:
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
unsigned char SPIX_WriteReadByte_Mode1(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData)
{
unsigned char u8ReadData=0;
unsigned char u8Cnt = 0;
for(u8Cnt = 0;u8Cnt < 8;u8Cnt ++)
{
//SPI是高位bit先传输
if(u8WriteData & 0x80)
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_RESET);
}
u8WriteData <<= 1;
//CLK上升沿(采样)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_SET);
u8ReadData <<= 1;
if(HAL_GPIO_ReadPin(stSpi->stSpiGpio_MISO.GPIOx,stSpi->stSpiGpio_MISO.GPIO_Pin_x))
{
u8ReadData += 1;
}
//CLK下降沿(触发)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_RESET);
}
return u8ReadData;
}
/*********************************************************************
* 函数描述:模拟SPI工作模式2(CPOL = 0 CPHA = 1)
* 输入说明:
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
unsigned char SPIX_WriteReadByte_Mode2(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData)
{
unsigned char u8ReadData=0;
unsigned char u8Cnt = 0;
for(u8Cnt = 0;u8Cnt < 8;u8Cnt ++)
{
//CLK上升沿(触发)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_SET);
//SPI是高位bit先传输
if(u8WriteData & 0x80)
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_RESET);
}
u8WriteData <<= 1;
//CLK下降沿(采样)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_RESET);
u8ReadData <<= 1;
if(HAL_GPIO_ReadPin(stSpi->stSpiGpio_MISO.GPIOx,stSpi->stSpiGpio_MISO.GPIO_Pin_x))
{
u8ReadData += 1;
}
}
return u8ReadData;
}
/*********************************************************************
* 函数描述:模拟SPI工作模式3(CPOL = 1 CPHA = 0)
* 输入说明:
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
unsigned char SPIX_WriteReadByte_Mode3(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData)
{
unsigned char u8ReadData=0;
unsigned char u8Cnt = 0;
for(u8Cnt = 0;u8Cnt < 8;u8Cnt ++)
{
//SPI是高位bit先传输
if(u8WriteData & 0x80)
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_RESET);
}
u8WriteData <<= 1;
//CLK下降沿(采样)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_RESET);
u8ReadData <<= 1;
if(HAL_GPIO_ReadPin(stSpi->stSpiGpio_MISO.GPIOx,stSpi->stSpiGpio_MISO.GPIO_Pin_x))
{
u8ReadData += 1;
}
//CLK上升沿(触发)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_SET);
}
return u8ReadData;
}
/*********************************************************************
* 函数描述:模拟SPI工作模式2(CPOL = 1 CPHA = 1)
* 输入说明:
* 输出说明:
* 创建日期:2023-07-27
*********************************************************************/
unsigned char SPIX_WriteReadByte_Mode4(ST_CLASS_SPIX* stSpi,unsigned char u8WriteData)
{
unsigned char u8ReadData=0;
unsigned char u8Cnt = 0;
for(u8Cnt = 0;u8Cnt < 8;u8Cnt ++)
{
//CLK下降沿(触发)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_RESET);
//SPI是高位bit先传输
if(u8WriteData & 0x80)
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(stSpi->stSpiGpio_MOSI.GPIOx,stSpi->stSpiGpio_MOSI.GPIO_Pin_x,GPIO_PIN_RESET);
}
u8WriteData <<= 1;
//CLK上升沿(采样)
HAL_GPIO_WritePin(stSpi->stSpiGpio_CLK.GPIOx,stSpi->stSpiGpio_CLK.GPIO_Pin_x,GPIO_PIN_SET);
u8ReadData <<= 1;
if(HAL_GPIO_ReadPin(stSpi->stSpiGpio_MISO.GPIOx,stSpi->stSpiGpio_MISO.GPIO_Pin_x))
{
u8ReadData += 1;
}
}
return u8ReadData;
}
#ifndef APP_SPIX_SPIX_H_
#define APP_SPIX_SPIX_H_
#include "main.h"
#define SPIX_MOSI_H HAL_GPIO_WritePin(SPIX_MOSI_GPIO_Port,SPIX_MOSI_Pin,GPIO_PIN_SET);
#define SPIX_MOSI_L HAL_GPIO_WritePin(SPIX_MOSI_GPIO_Port,SPIX_MOSI_Pin,GPIO_PIN_RESET);
#define SPIX_MISO_R HAL_GPIO_ReadPin(SPIX_MISO_GPIO_Port,SPIX_MISO_Pin)
#define SPIX_CLK_H HAL_GPIO_WritePin(SPIX_CLK_GPIO_Port,SPIX_CLK_Pin,GPIO_PIN_SET);
#define SPIX_CLK_L HAL_GPIO_WritePin(SPIX_CLK_GPIO_Port,SPIX_CLK_Pin,GPIO_PIN_RESET);
#define SPIX_CS_H HAL_GPIO_WritePin(SPIX_CS_GPIO_Port,SPIX_CS_Pin,GPIO_PIN_SET);
#define SPIX_CS_L HAL_GPIO_WritePin(SPIX_CS_GPIO_Port,SPIX_CS_Pin,GPIO_PIN_RESET);
typedef enum{
SPIX_MODE_1,
SPIX_MODE_2,
SPIX_MODE_3,
SPIX_MODE_4
}EN_SPIX_MODE;
typedef struct{
GPIO_TypeDef* GPIOx;
unsigned short GPIO_Pin_x;
}ST_SPIX_GPIO;
typedef struct{
EN_SPIX_MODE enSpiMode;
ST_SPIX_GPIO stSpiGpio_MOSI;
ST_SPIX_GPIO stSpiGpio_MISO;
ST_SPIX_GPIO stSpiGpio_CLK;
ST_SPIX_GPIO stSpiGpio_CS;
}ST_CLASS_SPIX;
bool SPIX_TransData(ST_CLASS_SPIX* stSpi,unsigned char* u8TxDataBuffer,unsigned short u16TxLength,unsigned char* u8RxDataBuffer,unsigned short u16RxLength);
bool SPIX_ReceiveData(ST_CLASS_SPIX* stSpi,unsigned char* u8DataBuffer,unsigned short u16Length);
bool SPIX_SendData(ST_CLASS_SPIX* stSpi,unsigned char* u8DataBuffer,unsigned short u16Length);
#endif /* APP_SPIX_SPIX_H_ */
这里套用别人初始化代码及MPU6500通讯代码,通讯没问题,如下图:
2.
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。