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 -- TODO
SENSORS_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);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_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
尾言
感谢大家能够看到这里,我会后期上传这个工程代码,以方便大家学习,也希望每一位嵌入式工程师能够不断前行。