本文主要是介绍stm32f4硬件IIC读取MPU6050数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
stm32f4硬件IIC读取MPU6050数据
** JY901B 串口10轴加速度计 MK695**
stm32f4“硬件协议”方式,STM32 的I2C 片上外设专门负责实现I2C 通讯协议,只要置好该外设,它就会自动
根据协议要求产生通讯信号,收发数据并缓存起来,CPU 只要检测该外设的状态和访问数据寄存器,就能完
成数据收发。这种由硬件外设处理I2C 协议的方式减轻了CPU 的工作,且使软件设计更加简单。不需要关心
底层的设计。
- 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数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!