硬件I2C读MPU6050
拿到小红板研究了一段时间,我的方案是做空中飞鼠的实验,那就要使用MPU6050来读取重取X和Y轴的重力加速度,MPU6050模块提供I2C通讯接口。I2C在STM32F1系列MCU上硬件使用上有诸多的问题,所以很多人都使用软件I2C。大家都知道GD32系列MCU是“山寨”STM32,所以可能也会存在同要的问题。但是我想即便是GD32“山寨”STM32,也可能是硬件寄存器和寄存器地址和STM32定义的一样,是为了大家从STM32更容易过渡到GD32上来做开发(这是不是在偷STM32的普及成果!),其硬件实现肯定是不一样的。既然硬件实现不一样,那GD32的硬件I2C就可能比STM32要好用。好了废话不多说,开始吧。
我们使用GD32的I2C1来读MPU6050,查下数据手册pin定义:
PB8,PB9复用I2C1的SCL,SDA
原理图上PB8,PB9在CN5上引出
实际接线图:
为了调试I2C,使用logic8来分析I2C的波形。
I2C逻辑电平
花了好几天时间终于调试通过。其实很简单,使用起来了很方便,只是GD没有I2C的例子,走了不少的弯路。特分享给大家,希望对其它人有用,代码我就只贴关键代码,明白人应该一看就知道了。
- //配置I2C
- void I2cConfig(void)
- {
- GPIO_InitPara GPIO_InitStructure;
- I2C_InitPara I2C_InitStructure;
-
- RCC_AHBPeriphClock_Enable(RCC_AHBPERIPH_GPIOB,ENABLE);
- RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_I2C1,ENABLE);
-
- GPIO_DeInit(GPIOB);
- /* Connect pin to Periph */
- GPIO_PinAFConfig(GPIOB,GPIO_PINSOURCE8,GPIO_AF_1);
- GPIO_PinAFConfig(GPIOB,GPIO_PINSOURCE9,GPIO_AF_1);
-
- /* Configure pins as AF pushpull */
- GPIO_InitStructure.GPIO_Pin = SCL|SDA;
- GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF;
- GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
- GPIO_InitStructure.GPIO_OType = GPIO_OTYPE_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PUPD_PULLUP;
- GPIO_Init( GPIOB , &GPIO_InitStructure);
- I2C_DeInit(I2C1);
- I2C_InitStructure.I2C_AddressingMode = I2C_ADDRESSING_MODE_7BIT;
- I2C_InitStructure.I2C_BitRate = 100000;
- I2C_InitStructure.I2C_DeviceAddress = 0x08;
- I2C_InitStructure.I2C_DutyCycle = I2C_DUTYCYCLE_2;
- I2C_InitStructure.I2C_Protocol = I2C_PROTOCOL_I2C;
- I2C_Init(I2C1,&I2C_InitStructure);
- I2C_Enable(I2C1,ENABLE);
- }
复制代码 上面的代码是配置I2C,不用太多的解释。下面的就是关键代码了- //**************************************
- //向I2C设备写入一个字节数据
- //**************************************
- void Single_WriteI2C(uint8_t REG_Address,uint8_t REG_data)
- {
- I2C_StartOnBus_Enable(I2C1,ENABLE);
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_SBSEND) == ERROR);//不能用I2C_GetBitState(I2C1,I2C_FLAG_SBSEND)
-
- //发送从设备地址到i2c总线上
- //I2C_AddressingDevice_7bit(I2C1,0xD0,I2C_DIRECTION_TRANSMITTER);
- I2C_SendData(I2C1,SlaveAddress);
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND) == ERROR);
- I2C_SendData(I2C1,REG_Address);
- I2C_SendData(I2C1,REG_data);
-
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_BYTE_TRANSMITTED) == ERROR);
- //while(!I2C_GetBitState(I2C1,I2C_FLAG_BTC));
- I2C_StopOnBus_Enable(I2C1,ENABLE);
- }
- //**************************************
- //从I2C设备读取一个字节数据
- //**************************************
- uint8_t Single_ReadI2C(uint8_t REG_Address)
- {
- uint8_t data;
- //起始信号
- I2C_StartOnBus_Enable(I2C1,ENABLE);
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_SBSEND) == ERROR);
-
- //发送从设备地址到i2c总线上
- I2C_AddressingDevice_7bit(I2C1,SlaveAddress,I2C_DIRECTION_TRANSMITTER);
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_TRANSMITTER_ADDSEND) == ERROR);
- //发送读地址
- I2C_SendData(I2C1,REG_Address);
-
- //再次发送起始信号
- I2C_StartOnBus_Enable(I2C1,ENABLE);
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_SBSEND) == ERROR);
- //发送读设备信号
- I2C_SendData(I2C1,SlaveAddress+1);
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_RECEIVER_ADDSEND) == ERROR);
-
- while(I2C_StateDetect(I2C1,I2C_PROGRAMMINGMODE_MASTER_BYTE_RECEIVED) == ERROR);
- data = I2C_ReceiveData(I2C1);
-
- I2C_StopOnBus_Enable(I2C1,ENABLE);
- return data;
- }
复制代码 刚开始的时候一切安照参考手册上的I2C通讯流程,但总线状态我一直使用I2C_GetBitState来取I2C总线状态,i2c总线上始终只出现一次数据,再写数据已经没有任何反应了,调试了好几天都一样,把参考手册i2c通讯流程都看了好几遍,最后把gd32f1x0_i2c.c文件打开,一个函数一个函数细细看下。看到I2C_StateDetect这个函数,而且注释上有@brief Detect I2Cx State Machine.想想以前在新唐上的I2C就是用状态机检测,就试试这个来检测状态,大功告成。太坑爹了,在这里真希望官为真的应该出一本函数手册,配以用例,让俺们也少走些变路。。。
|