本次会尝试使用hal库软件模拟iic来读取mpu6050中的数据。
使用的核心板为stm32f407ZGT6。使用器件为mpu6050
会通过软件iic读取mpc6050中的数据
同时本次实验参考江协科技实验。
首先了解iic协议规则
iic协议特点:有两根通信线构成:SCL和SDA,同步半双工传输信息。带数据应答。
iic电路中,我们需要保证所有从机的SCL和SDA连接在一起,同时端口配置为开漏输出模式。并在在sda和scl各自添加一个上拉电阻。在通信中主机具有scl的绝对控制权,同时从机不可主动控制sda,除非在应答器件或者主机发送读取信号时,从机可以短暂获取sda控制权。
这里先对串口进行初始化,这里使用PB5.6两个口进行模拟,
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_RESET);/*Configure GPIO pins : PB5 PB6 */
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_SET);
}
这里将PB5,6设置为上拉,开漏输出模式。
同时我们将设置PB5,6的电平代码进行封装,这里我们根据江协科技所给案例进行封装
void myiicwscl(uint8_t bitvalue)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, (GPIO_PinState)(bitvalue));
HAL_Delay(20);
}void myiicwsda(uint8_t bitvalue)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, (GPIO_PinState)(bitvalue));
HAL_Delay(20);
}
这里注意,在hal库中我们要使用函数
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, (GPIO_PinState)(bitvalue));
来进行电平的翻转,这与标准库有所不同
下面是iic的通信步骤,这里我们根据逻辑时序图来进行代码的编写
通信协议:
通信开始
SCL在高电平器件检测到SDA由高电平转换为低电平,示意图
代码如下
void myiicstart()
{
myiicwsda(1);
myiicwscl(1);
myiicwsda(0);
myiicwscl(0);}
通信结束
SCL在低电平器件检测到SDA由低电平转换为高电平,示意图
代码如下
void myiicstop()
{
myiicwsda(0);
myiicwscl(1);
myiicwsda(1);}
发送数据
当SCL时钟线处于高电平时,在这一时刻,从机会读取SDA此时的电平,通俗来奖,就是数据应当在 SCL处于低电平时被放置在SDA线上,当SCL处于高电平时,该数据会被读取。
如图所示
代码示例
void myiicsent(uint8_t Byte)
{
uint8_t i;
for(i=0;i<8;i++)
{
myiicwsda(Byte & (0x80>>i));
myiicwscl(1);
myiicwscl(0);
}}
接收数据
接收数据与发送数据逻辑相同,都是在SCL高电平器件放置SDA 上的数据,随后当SCL转变为高电平时候读取SDA 数据。二者区别是,在接受中,要先释放主机对SDA线的主动权,将控制权下放给从机,由于我们将串口设置为开漏输出,且为上拉模式,因此我们只需要控制主机将SDA 置一就可以将控制权交给从机。从机会再随后的SCL低电平期间,进行数据的放置。
uint8_t myiicreceive(uint8_t Byte)
{
uint8_t i,byte = 0x00;
myiicwsda(1);
for(i=0;i<8;i++)
{
myiicwscl(1);
if(myiicread()==1)
{
byte|=(0x80>>i);}
myiicwscl(0);
}
return byte;
}
发送与接受应答信号
主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答
代码如下
void myiicsentack(uint8_t ackByte)
{myiicwsda(ackByte);
myiicwscl(1);
myiicwscl(0);}
uint8_t myiicreceiveack(void)
{
uint8_t ackByte = 0x00;
myiicwsda(1);
myiicwscl(1);
ackByte = myiicread();
myiicwscl(0);
return ackByte;}
截至至此,我们对iic的基础通信部分已经完成,下面我们先对mpu6050进行呼叫,看他是否对我们的信息产生应答
这里我们在我们的主函数中,调用我们的iic头文件,并写下下面语句
myiicstart();
myiicsent(0xD0);
uint8_t ack = myiicreceiveack();
myiicstop();uint8_t message = ack;
在写完之后我们编译运行烧录到我们的板子中,并根据线路连接到我们的mpu6050,随后我们开启硬件调试模式,进行查看message的数据是否为0x00.
数据正确,
这里我们再将地址进行更改进行检验
myiicstart();
myiicsent(0xA0);
uint8_t ack = myiicreceiveack();
myiicstop();uint8_t message = ack;
数据显示0x01,证明代码编写正确。
下一步我会综合mpu6050文档对mpu6050数据进行读取,需要代码的可以发送到我的邮箱。后续在考虑怎么把数据展示出来,是直接串口还是用oled显示出来。