stm32f4硬件IIC读取MPU6050数据

2024-02-19 06:10

本文主要是介绍stm32f4硬件IIC读取MPU6050数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

stm32f4硬件IIC读取MPU6050数据


** JY901B 串口10轴加速度计 MK695**


stm32f4“硬件协议”方式,STM32 的I2C 片上外设专门负责实现I2C 通讯协议,只要置好该外设,它就会自动
根据协议要求产生通讯信号,收发数据并缓存起来,CPU 只要检测该外设的状态和访问数据寄存器,就能完
成数据收发。这种由硬件外设处理I2C 协议的方式减轻了CPU 的工作,且使软件设计更加简单。不需要关心
底层的设计。
  1. I2C 通讯协议

I2C 通讯协议(Inter - Integrated Circuit) 是由Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC) 间的通讯。
通讯的起始和停止信号
在通讯的起始和停止信号
数据有效性
在这里插入图片描述
地址及数据方向
在这里插入图片描述
响应
在这里插入图片描述

2. 设备
在这里插入图片描述

**3. STM32的硬件IIC
由stm32f4xx的中文参考手册可得,f4在f1的基础上对iic的性能进行了加强,稳定性方面得到了很大的增强。
“硬件协议”方式,STM32 的I2C 片上外设专门负责实现I2C 通讯协议,只要配
置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,CPU 只要检测该
外设的状态和访问数据寄存器,就能完成数据收发。这种由硬件外设处理I2C 协议的方式减轻了
CPU 的工作,且使软件设计更加简单。不需要关心底层的库设计。
在这里插入图片描述

4.*** 程序设计****(最最干货)

STM32 标准库提供了I2C 初始化结构体及初始化函数来配置I2C 外设。初始
化结构体及函数定义在库文件“stm32f4xx_i2c.h”及“stm32f4xx_i2c.c”中,编程时我们可以结合
这两个文件内的注释使用或参考库帮助文档。了解初始化结构体后我们就能对I2C 外设运用自
如了。

4.1. 首先要对IIC总线的IO口和iic的结构体进行初始化

/*** @brief  初始化I2C总线,使用I2C前需要调用* @param  无* @retval 无*/
void I2cMaster_Init(void) 
{GPIO_InitTypeDef GPIO_InitStructure;I2C_InitTypeDef I2C_InitStructure;/* Enable I2Cx clock */RCC_APB1PeriphClockCmd(SENSORS_I2C_RCC_CLK, ENABLE);/* Enable I2C GPIO clock */RCC_AHB1PeriphClockCmd(SENSORS_I2C_SCL_GPIO_CLK | SENSORS_I2C_SDA_GPIO_CLK, ENABLE);/* Configure I2Cx pin: SCL ----------------------------------------*/GPIO_InitStructure.GPIO_Pin =  SENSORS_I2C_SCL_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;/* Connect pins to Periph */GPIO_PinAFConfig(SENSORS_I2C_SCL_GPIO_PORT, SENSORS_I2C_SCL_GPIO_PINSOURCE, SENSORS_I2C_AF);  GPIO_Init(SENSORS_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);/* Configure I2Cx pin: SDA ----------------------------------------*/GPIO_InitStructure.GPIO_Pin = SENSORS_I2C_SDA_GPIO_PIN; /* Connect pins to Periph */GPIO_PinAFConfig(SENSORS_I2C_SDA_GPIO_PORT, SENSORS_I2C_SDA_GPIO_PINSOURCE, SENSORS_I2C_AF);  GPIO_Init(SENSORS_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);  I2C_DeInit(SENSORS_I2C);I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;I2C_InitStructure.I2C_OwnAddress1 = I2C_OWN_ADDRESS;I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;/* Enable the I2C peripheral */I2C_Cmd(SENSORS_I2C, ENABLE);  /* Initialize the I2C peripheral */I2C_Init(SENSORS_I2C, &I2C_InitStructure);return;
}

这些结构体成员说明如下,其中括号内的文字是对应参数在STM32 标准库中定义的宏:

(1) I2C_ClockSpeed
本成员设置的是I2C 的传输速率,在调用初始化函数时,函数会根据我们输入的数值经过
运算后把时钟因子写入到I2C 的时钟控制寄存器CCR。而我们写入的这个参数值不得高于400KHz。由于CCR 寄存器不能写入小数类型的时钟因子,固件库计算CCR 值时会向下取
整,影响到SCL 的实际频率可能会低于本成员设置的参数值,这时除了通讯稍慢一点以外,
不会对I2C 的标准通讯造成其它影响。

(2) I2C_Mode
本成员是选择I2C 的使用方式,有I2C 模式(I2C_Mode_I2C) 和SMBus 主、从模式
(I2C_Mode_SMBusHost、I2C_Mode_SMBusDevice ) 。I2C 不需要在此处区分主从模式,直接
设置I2C_Mode_I2C 即可。

(3) I2C_DutyCycle
本成员设置的是I2C 的SCL 线时钟的占空比。该配置有两个选择,分别为低电平时间比高
电平时间为2:1 ( I2C_DutyCycle_2) 和16:9 (I2C_DutyCycle_16_9)。其实这两个模式的比
例差别并不大,一般要求都不会如此严格,这里随便选就可以了。

(4) I2C_OwnAddress1
本成员配置的是STM32 的I2C 设备自己的地址,每个连接到I2C 总线上的设备
都要有一个自己的地址,作为主机也不例外。地址可设置为7 位或10 位(受下面
I2C_AcknowledgeAddress 成员决定),只要该地址是I2C 总线上唯一的即可。
STM32 的I2C 外设可同时使用两个地址,即同时对两个地址作出响应,这个结构成员
I2C_OwnAddress1 配置的是默认的、OAR1 寄存器存储的地址,若需要设置第二个地址寄存
器OAR2,可使用I2C_OwnAddress2Config 函数来配置,OAR2 不支持10 位地址。

(5) I2C_Ack_Enable
本成员是关于I2C 应答设置,设置为使能则可以发送响应信号。该成员值一般配置为允
许应答(I2C_Ack_Enable),这是绝大多数遵循I2C 标准的设备的通讯要求,改为禁止应答
(I2C_Ack_Disable) 往往会导致通讯错误。

(6) I2C_AcknowledgeAddress
本成员选择I2C 的寻址模式是7 位还是10 位地址。这需要根据实际连接到I2C 总线上设备
的地址进行选择,这个成员的配置也影响到I2C_OwnAddress1 成员,只有这里设置成10 位
模式时,I2C_OwnAddress1 才支持10 位地址。
配置完这些结构体成员值,调用库函数I2C_Init 即可把结构体的配置写入到寄存器中。

4.2 写一个字节

/*** @brief   写一个字节到I2C EE中* @param    @param  slave_addr, 外设地址*		@arg pBuffer:缓冲区指针*		@arg WriteAddr:写地址 * @retval  无*/
u8 I2C_ByteWrite(u8 slave_addr,u8* pBuffer, u8 WriteAddr)
{u16 I2CTimeout;/* Send STRAT condition */I2C_GenerateSTART(SENSORS_I2C, ENABLE);I2CTimeout = ((uint32_t)0x1000);/* Test on EV5 and clear it */while(!I2C_CheckEvent(SENSORS_I2C, I2C_EVENT_MASTER_MODE_SELECT)){if((I2CTimeout--) == 0) printf("I2C 等待超时!errorCode = 0 \r\n");}    /* Send EE address for write */I2C_Send7bitAddress(SENSORS_I2C, slave_addr, I2C_Direction_Transmitter);I2CTimeout = ((uint32_t)0x1000);/* Test on EV6 and clear it */while(!I2C_CheckEvent(SENSORS_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){if((I2CTimeout--) == 0)   printf("I2C 等待超时!errorCode = 1 \r\n");}    /* Send the EE's internal address to write to */I2C_SendData(SENSORS_I2C, WriteAddr);I2CTimeout = ((uint32_t)0x1000);/* Test on EV8 and clear it */while(!I2C_CheckEvent(SENSORS_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))  {if((I2CTimeout--) == 0)  printf("I2C 等待超时!errorCode = 2 \r\n");} /* Send the byte to be written */I2C_SendData(SENSORS_I2C, *pBuffer); I2CTimeout = ((uint32_t)0x1000);/* Test on EV8 and clear it */while(!I2C_CheckEvent(SENSORS_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if((I2CTimeout--) == 0) printf("I2C 等待超时!errorCode = 3 \r\n");} /* Send STOP condition */I2C_GenerateSTOP(SENSORS_I2C, ENABLE);return 1;
}

先来分析I2C_TIMEOUT_UserCallback 函数,它的函数体里只调用了宏EEPROM_ERROR,这个
宏封装了printf 函数,方便使用串口向上位机打印调试信息,阅读代码时把它当成printf 函数即
可。在I2C 通讯的很多过程,都需要检测事件,当检测到某事件后才能继续下一步的操作,但有
时通讯错误或者I2C 总线被占用,我们不能无休止地等待下去,所以我们设定每个事件检测都有
等待的时间上限,若超过这个时间,我们就调用I2C_TIMEOUT_UserCallback 函数输出调试信息
(或可以自己加其它操作),并终止I2C 通讯。
了解了这个机制,再来分析I2C_EE_ByteWrite 函数,这个函数实现了前面讲的I2C 主发送器通
讯流程

(1) 使用库函数I2C_GenerateSTART 产生I2C 起始信号,其中的EEPROM_I2C 宏是前面硬件定义相关的I2C 编号;

(2) 对I2CTimeout 变量赋值为宏I2CT_FLAG_TIMEOUT,这个I2CTimeout 变量在下面的while 循
环中每次循环减1,该循环通过调用库函数I2C_CheckEvent 检测事件,若检测到事件,则进入通
讯的下一阶段,若未检测到事件则停留在此处一直检测,当检测I2CT_FLAG_TIMEOUT 次都还
没等待到事件则认为通讯失败,调用前面的I2C_TIMEOUT_UserCallback 输出调试信息,并退出
通讯;

(3) 调用库函数I2C_Send7bitAddress 发送EEPROM 的设备地址,并把数据传输方向设置为
I2C_Direction_Transmitter(即发送方向),这个数据传输方向就是通过设置I2C 通讯中紧跟地址后
面的R/W 位实现的。发送地址后以同样的方式检测EV6 标志;

(4) 调用库函数I2C_SendData 向EEPROM 发送要写入的内部地址,该地址是I2C_EE_ByteWrite
函数的输入参数,发送完毕后等待EV8 事件。要注意这个内部地址跟上面的EEPROM 地址不一
样,上面的是指I2C 总线设备的独立地址,而此处的内部地址是指EEPROM 内数据组织的地址,
也可理解为EEPROM 内存的地址或I2C 设备的寄存器地址;

(5) 调用库函数I2C_SendData 向EEPROM 发送要写入的数据,该数据是I2C_EE_ByteWrite 函数
的输入参数,发送完毕后等待EV8 事件;

(6) 一个I2C 通讯过程完毕,调用I2C_GenerateSTOP 发送停止信号。

4.3对读写函数的封装
封装后的函数主要是增加了错误重试机制,若读写出现错误,则会进行多次尝试,多次尝试均失
败后会返回错误代码。这个函数作为I2C 驱动对外的接口,其它使用I2C 的传感器调用这个函数
进行读写寄存器。
封装后的函数主要是增加了错误重试机制,若读写出现错误,则会进行多次尝试,多次尝试均失
败后会返回错误代码。这个函数作为I2C 驱动对外的接口,其它使用I2C 的传感器调用这个函数
进行读写寄存器。
封装后的函数主要是增加了错误重试机制,若读写出现错误,则会进行多次尝试,多次尝试均失
败后会返回错误代码。这个函数作为I2C 驱动对外的接口,其它使用I2C 的传感器调用这个函数
进行读写寄存器。

/*** @brief  写寄存器(多次尝试),这是提供给上层的接口* @param  slave_addr: 从机地址* @param 	reg_addr:寄存器地址* @param len:写入的长度*	@param data_ptr:指向要写入的数据* @retval 正常为0,不正常为非0*/
u8 Sensors_I2C_WriteRegister(unsigned char slave_addr,unsigned char reg_addr,unsigned short len, const unsigned char *data_ptr)
{char retries=0;int ret = 0;unsigned short retry_in_mlsec = Get_I2C_Retry();tryWriteAgain:  ret = 0;ret = ST_Sensors_I2C_WriteRegister( slave_addr, reg_addr, len, data_ptr); if(ret && retry_in_mlsec){if( retries++ > 4 )return ret;Delay(retry_in_mlsec);goto tryWriteAgain;}return ret;  
}/*** @brief  读寄存器(多次尝试),这是提供给上层的接口* @param  slave_addr: 从机地址* @param 	reg_addr:寄存器地址* @param len:要读取的长度*	@param data_ptr:指向要存储数据的指针* @retval 正常为0,不正常为非0*/
u8 Sensors_I2C_ReadRegister(unsigned char slave_addr,unsigned char reg_addr,unsigned short len, unsigned char *data_ptr)
{char retries=0;int ret = 0;unsigned short retry_in_mlsec = Get_I2C_Retry();tryReadAgain:  ret = 0;ret = ST_Sensors_I2C_ReadRegister( slave_addr, reg_addr, len, data_ptr);if(ret && retry_in_mlsec){if( retries++ > 4 )return ret;Delay(retry_in_mlsec);goto tryReadAgain;} return ret;
}/*** @brief  写寄存器(单次尝试),这是底层I2C接口* @param  slave_addr: 从机地址* @param 	reg_addr:寄存器地址* @param len:写入的长度*	@param data_ptr:指向要写入的数据* @retval 正常为0,不正常为非0*/
static unsigned long ST_Sensors_I2C_WriteRegister(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, const unsigned char *RegisterValue)
{uint32_t  result = 0;uint32_t  i = 0; // i = RegisterLen;__IO uint32_t  I2CTimeout = I2Cx_LONG_TIMEOUT;//  RegisterValue = RegisterValue + (RegisterLen - 1);/* Wait for the busy flag to be cleared */WAIT_FOR_FLAG (I2C_FLAG_BUSY, RESET, I2Cx_LONG_TIMEOUT, 1);/* Start the config sequence */I2C_GenerateSTART(SENSORS_I2C, ENABLE);/* Wait for the start bit to be set */WAIT_FOR_FLAG (I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 2);/* Transmit the slave address and enable writing operation */I2C_Send7bitAddress(SENSORS_I2C, (Address<<1), I2C_Direction_Transmitter);/* Wait for address bit to be set */WAIT_FOR_FLAG (I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 3);/* clear the ADDR interrupt bit  - this is done by reading SR1 and SR2*/CLEAR_ADDR_BIT/* Wait for address bit to be set */WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 4);/* Transmit the first address for write operation */I2C_SendData(SENSORS_I2C, RegisterAddr);for(i=0; i<(RegisterLen); i++){/* Wait for address bit to be set */WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 5);/* Prepare the register value to be sent */I2C_SendData(SENSORS_I2C, RegisterValue[i]);}  /* Wait for address bit to be set */WAIT_FOR_FLAG (I2C_FLAG_BTF, SET, I2Cx_FLAG_TIMEOUT, 6);/* End the configuration sequence */I2C_GenerateSTOP(SENSORS_I2C, ENABLE);  /* Return the verifying value: 0 (Passed) or 1 (Failed) */return result;  
}/*** @brief  读寄存器(单次尝试),这是底层I2C接口* @param  slave_addr: 从机地址* @param 	reg_addr:寄存器地址* @param len:要读取的长度*	@param data_ptr:指向要存储数据的指针* @retval 正常为0,不正常为非0*/
static unsigned long ST_Sensors_I2C_ReadRegister(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, unsigned char *RegisterValue)
{uint32_t i=0, result = 0;__IO uint32_t  I2CTimeout = I2Cx_LONG_TIMEOUT;/* Wait for the busy flag to be cleared */WAIT_FOR_FLAG (I2C_FLAG_BUSY, RESET, I2Cx_LONG_TIMEOUT, 7);/* Start the config sequence */I2C_GenerateSTART(SENSORS_I2C, ENABLE);/* Wait for the start bit to be set */WAIT_FOR_FLAG (I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 8);/* Transmit the slave address and enable writing operation */I2C_Send7bitAddress(SENSORS_I2C, (Address<<1), I2C_Direction_Transmitter);/* Wait for the start bit to be set */WAIT_FOR_FLAG (I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 9);/* clear the ADDR interrupt bit  - this is done by reading SR1 and SR2*/CLEAR_ADDR_BIT;/* Wait for address bit to be set */WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 10);/* Transmit the register address to be read */I2C_SendData(SENSORS_I2C, RegisterAddr);/* Wait for address bit to be set */WAIT_FOR_FLAG (I2C_FLAG_TXE, SET, I2Cx_FLAG_TIMEOUT, 11);  /*!< Send START condition a second time */  I2C_GenerateSTART(SENSORS_I2C, ENABLE);/* Wait for the start bit to be set */WAIT_FOR_FLAG (I2C_FLAG_SB, SET, I2Cx_FLAG_TIMEOUT, 12);/*!< Send address for read */I2C_Send7bitAddress(SENSORS_I2C, (Address<<1), I2C_Direction_Receiver);  /* Wait for the start bit to be set */WAIT_FOR_FLAG (I2C_FLAG_ADDR, SET, I2Cx_FLAG_TIMEOUT, 13);if (RegisterLen == 1) {/*!< Disable Acknowledgment */I2C_AcknowledgeConfig(SENSORS_I2C, DISABLE);/* clear the ADDR interrupt bit  - this is done by reading SR1 and SR2*/CLEAR_ADDR_BIT;/*!< Send STOP Condition */I2C_GenerateSTOP(SENSORS_I2C, ENABLE);/* Wait for the RXNE bit to be set */WAIT_FOR_FLAG (I2C_FLAG_RXNE, SET, I2Cx_FLAG_TIMEOUT, 14);RegisterValue[0] = I2C_ReceiveData(SENSORS_I2C);} else if( RegisterLen == 2) {/*!< Disable Acknowledgment */I2C_AcknowledgeConfig(SENSORS_I2C, DISABLE);/* Set POS bit */ SENSORS_I2C->CR1 |= I2C_CR1_POS;/* clear the ADDR interrupt bit  - this is done by reading SR1 and SR2*/CLEAR_ADDR_BIT; /* Wait for the buffer full bit to be set */WAIT_FOR_FLAG (I2C_FLAG_BTF, SET, I2Cx_FLAG_TIMEOUT, 15);/*!< Send STOP Condition */I2C_GenerateSTOP(SENSORS_I2C, ENABLE);/* Read 2 bytes */RegisterValue[0] = I2C_ReceiveData(SENSORS_I2C);RegisterValue[1] = I2C_ReceiveData(SENSORS_I2C);} else if( RegisterLen == 3){CLEAR_ADDR_BIT;/* Wait for the buffer full bit to be set */WAIT_FOR_FLAG (I2C_FLAG_BTF, SET, I2Cx_FLAG_TIMEOUT, 16);/*!< Disable Acknowledgment */I2C_AcknowledgeConfig(SENSORS_I2C, DISABLE);/* Read 1 bytes */RegisterValue[0] = I2C_ReceiveData(SENSORS_I2C);/*!< Send STOP Condition */I2C_GenerateSTOP(SENSORS_I2C, ENABLE);        /* Read 1 bytes */RegisterValue[1] = I2C_ReceiveData(SENSORS_I2C);/* Wait for the buffer full bit to be set */WAIT_FOR_FLAG (I2C_FLAG_RXNE, SET, I2Cx_FLAG_TIMEOUT, 17);/* Read 1 bytes */RegisterValue[2] = I2C_ReceiveData(SENSORS_I2C);  }  else /* more than 2 bytes */{ /* clear the ADDR interrupt bit  - this is done by reading SR1 and SR2*/CLEAR_ADDR_BIT;for(i=0; i<(RegisterLen); i++){if(i==(RegisterLen-3)){/* Wait for the buffer full bit to be set */WAIT_FOR_FLAG (I2C_FLAG_BTF, SET, I2Cx_FLAG_TIMEOUT, 16);/*!< Disable Acknowledgment */I2C_AcknowledgeConfig(SENSORS_I2C, DISABLE);/* Read 1 bytes */RegisterValue[i++] = I2C_ReceiveData(SENSORS_I2C);/*!< Send STOP Condition */I2C_GenerateSTOP(SENSORS_I2C, ENABLE);        /* Read 1 bytes */RegisterValue[i++] = I2C_ReceiveData(SENSORS_I2C);/* Wait for the buffer full bit to be set */WAIT_FOR_FLAG (I2C_FLAG_RXNE, SET, I2Cx_FLAG_TIMEOUT, 17);/* Read 1 bytes */RegisterValue[i++] = I2C_ReceiveData(SENSORS_I2C);  goto endReadLoop;}/* Wait for the RXNE bit to be set */WAIT_FOR_FLAG (I2C_FLAG_RXNE, SET, I2Cx_FLAG_TIMEOUT, 18);RegisterValue[i] = I2C_ReceiveData(SENSORS_I2C); }   } endReadLoop:  /* Clear BTF flag */I2C_ClearFlag(SENSORS_I2C, I2C_FLAG_BTF);/* Wait for the busy flag to be cleared */WAIT_FOR_FLAG (I2C_FLAG_BUSY, RESET, I2Cx_LONG_TIMEOUT, 19);  /*!< Re-Enable Acknowledgment to be ready for another reception */I2C_AcknowledgeConfig(SENSORS_I2C, ENABLE);//Disable POS -- TODOSENSORS_I2C->CR1 &= ~I2C_CR1_POS;  /* Return the byte read from sensor */return result;
}

4.3宏定义

#include "sys.h" 
#include "delay.h"
#include "usart.h"/****************************** Defines *******************************/#define I2C_SPEED                 400000
#define I2C_OWN_ADDRESS           0x00//毫秒级延时(需要定时器支持),或者重写Delay宏
#define Delay 		delay_ms
#define I2Cx_FLAG_TIMEOUT             ((uint32_t) 900) //0x1100
#define I2Cx_LONG_TIMEOUT             ((uint32_t) (300 * I2Cx_FLAG_TIMEOUT)) //was300/*引脚定义*/ 
#define SENSORS_I2C_SCL_GPIO_PORT         GPIOB
#define SENSORS_I2C_SCL_GPIO_CLK          RCC_AHB1Periph_GPIOB
#define SENSORS_I2C_SCL_GPIO_PIN          GPIO_Pin_8
#define SENSORS_I2C_SCL_GPIO_PINSOURCE    GPIO_PinSource8#define SENSORS_I2C_SDA_GPIO_PORT         GPIOB
#define SENSORS_I2C_SDA_GPIO_CLK          RCC_AHB1Periph_GPIOB
#define SENSORS_I2C_SDA_GPIO_PIN          GPIO_Pin_9
#define SENSORS_I2C_SDA_GPIO_PINSOURCE    GPIO_PinSource9#define SENSORS_I2C_AF                    GPIO_AF_I2C1#define SENSORS_I2C              					 I2C1
#define SENSORS_I2C_RCC_CLK               RCC_APB1Periph_I2C1
/*信息输出*/
#define I2C_DEBUG_ON         1
#define I2C_DEBUG_FUNC_ON    0#define I2C_INFO(fmt,arg...)           printf("<<-I2C-INFO->> "fmt"\n",##arg)
#define I2C_ERROR(fmt,arg...)          printf("<<-I2C-ERROR->> "fmt"\n",##arg)
#define I2C_DEBUG(fmt,arg...)          do{\if(I2C_DEBUG_ON)\printf("<<-I2C-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\}while(0)#define I2C_DEBUG_FUNC()               do{\if(I2C_DEBUG_FUNC_ON)\printf("<<-I2C-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\}while(0)/*函数定义*/
#define I2C_Config() I2cMaster_Init();void I2cMaster_Init(void);
void Set_I2C_Retry(unsigned short ml_sec);
unsigned short Get_I2C_Retry(void);//写一个字节,这是提供给上层的接口		
u8 I2C_ByteWrite(u8 slave_addr,u8* pBuffer, u8 WriteAddr);									   
//读寄存器(多次尝试),这是提供给上层的接口																			 
u8 Sensors_I2C_ReadRegister(unsigned char slave_addr,unsigned char reg_addr,unsigned short len, unsigned char *data_ptr);
//写寄存器(多次尝试),这是提供给上层的接口
u8 Sensors_I2C_WriteRegister(unsigned char slave_addr,unsigned char reg_addr,unsigned short len, const unsigned char *data_ptr);

4.5 读取JY901B 串口10轴加速度计 MK695**
在这里插入图片描述
可通过iic总线直接读取内部数据,数据已经经过dmp姿态解读和卡尔曼滤波
直接读取 直接读取 直接读取
附带mian函数

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h" 
#include "myiic.h"void ShortToChar(short sData,unsigned char cData[])
{cData[0]=sData&0xff;cData[1]=sData>>8;
}
short CharToShort(unsigned char cData[])
{return ((short)cData[1]<<8)|cData[0];
}int main(void)
{ unsigned char chrTemp[30];
//	unsigned char str[100];float a[3],w[3],h[3],Angle[3];NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2delay_init(168);    //初始化延时函数uart_init(115200);	//初始化串口波特率为115200LED_Init();					//初始化LED KEY_Init(); 				//按键初始化  I2cMaster_Init();while(1){//IICreadBytes(0x50, AX, 24,&chrTemp[0]);//IICreadBytes(u8 dev, u8 reg, u8 length, u8 *data);//I2C_BufferRead(u8 slave_addr,u8* pBuffer, u8 ReadAddr, u8 NumByteToRead);Sensors_I2C_ReadRegister(0x50,AX,24,&chrTemp[0]);a[0] = (float)CharToShort(&chrTemp[0])/32768*16;a[1] = (float)CharToShort(&chrTemp[2])/32768*16;a[2] = (float)CharToShort(&chrTemp[4])/32768*16;w[0] = (float)CharToShort(&chrTemp[6])/32768*2000;w[1] = (float)CharToShort(&chrTemp[8])/32768*2000;w[2] = (float)CharToShort(&chrTemp[10])/32768*2000;h[0] = CharToShort(&chrTemp[12]);h[1] = CharToShort(&chrTemp[14]);h[2] = CharToShort(&chrTemp[16]);Angle[0] = (float)CharToShort(&chrTemp[18])/32768*180;Angle[1] = (float)CharToShort(&chrTemp[20])/32768*180;Angle[2] = (float)CharToShort(&chrTemp[22])/32768*180;printf("0x50:  a:%.3f %.3f %.3f w:%.3f %.3f %.3f  h:%.0f %.0f %.0f  Angle:%.3f %.3f %.3f \r\n",a[0],a[1],a[2],w[0],w[1],w[2],h[0],h[1],h[2],Angle[0],Angle[1],Angle[2]);//  printf("%s\n",str);//UART1_Put_String(str);		//USB_TxWrite(str, strlen((char*)str));} 	    
}

其中AX为内部数据存放的首地址

#define YYMM				0x30
#define DDHH				0x31
#define MMSS				0x32
#define MS					0x33
#define AX					0x34
#define AY					0x35
#define AZ					0x36
#define GX					0x37
#define GY					0x38
#define GZ					0x39
#define HX					0x3a
#define HY					0x3b
#define HZ					0x3c			
#define Roll				0x3d
#define Pitch				0x3e
#define Yaw					0x3f
#define TEMP				0x40

尾言
感谢大家能够看到这里,我会后期上传这个工程代码,以方便大家学习,也希望每一位嵌入式工程师能够不断前行。

这篇关于stm32f4硬件IIC读取MPU6050数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/723729

相关文章

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

Redis 中的热点键和数据倾斜示例详解

《Redis中的热点键和数据倾斜示例详解》热点键是指在Redis中被频繁访问的特定键,这些键由于其高访问频率,可能导致Redis服务器的性能问题,尤其是在高并发场景下,本文给大家介绍Redis中的热... 目录Redis 中的热点键和数据倾斜热点键(Hot Key)定义特点应对策略示例数据倾斜(Data S

Python实现将MySQL中所有表的数据都导出为CSV文件并压缩

《Python实现将MySQL中所有表的数据都导出为CSV文件并压缩》这篇文章主要为大家详细介绍了如何使用Python将MySQL数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到... python将mysql数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到另一个

SpringBoot整合jasypt实现重要数据加密

《SpringBoot整合jasypt实现重要数据加密》Jasypt是一个专注于简化Java加密操作的开源工具,:本文主要介绍详细介绍了如何使用jasypt实现重要数据加密,感兴趣的小伙伴可... 目录jasypt简介 jasypt的优点SpringBoot使用jasypt创建mapper接口配置文件加密

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

解决Java中基于GeoTools的Shapefile读取乱码的问题

《解决Java中基于GeoTools的Shapefile读取乱码的问题》本文主要讨论了在使用Java编程语言进行地理信息数据解析时遇到的Shapefile属性信息乱码问题,以及根据不同的编码设置进行属... 目录前言1、Shapefile属性字段编码的情况:一、Shp文件常见的字符集编码1、System编码

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.