文章目录
【实验目的】
- 掌握I2C协议的内容,了解I2C接口的特点。
- 了解陀螺仪MPU6050的用途及数据采集过程。
- 熟悉STM32F10xx系列微控制器的I2C配置,完成通过I2C读取陀螺仪MPU6050数据的实验。
【实验原理】
I2C (Inter-Integrated Circuit)协议是由Phiilps公司开发的,由于它具引脚少,硬件实现简单,可扩展性强,不需要如USART、CAN的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。
一、I2C总线协议:
I2C总线在传送数据过程中共有三种类型信号,它们分别是:开始信号、结束信号和应答信号。
- 开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
- 结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
- 应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。
二、I2C接口特性
- STM32的中等容量和大容量型号的芯片均有多达2个的I2C总线接口。
- 能够工作于多主模式或从模式,分别为主接收器,主发送器,从接收器及从发。
- 支持标准模式100Kbit/s和快速模式400Kbit/s,不支持高速模式。
- 支持7位或10位寻址。
- 内置了硬件CRC发生器/校验器。
- I2C的接收和发送都可以使用DMA操作。
- 支持系统管理总线(SMBus)总线2.0版。
三、MPU6050相关
MPU-6050为9轴运动处理传感器。它集成了3轴陀螺仪,3轴加速度计,以及一个可扩展的数字运动处理器DMP(Digital Motion Processor),可用I2C接口连接一个第三方的数字传感器,比如磁力计。MPU-6050对陀螺仪和加速度计分别用了三个16位的ADC,将其测量的模拟量转化为可输出的数字量。MPU-6050上所有设备寄存器之间的通信采用400kHz的I2C接口。另外,片上还内嵌了一个温度传感器和在工作环境下仅有±1%变动的振荡器。
四、硬件连接和库函数介绍
图1 硬件连接示意图
本实验中使用的库函数主要有unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr),其功能为读取指定设备,指定寄存器的一个值,其参数分别为:
I2C_Addr:目标设备地址,在我们的实验中为陀螺仪和加速度计的地址。
Addr:寄存器地址,即存放陀螺仪信息和加速度计信息的寄存器地址
五、软件流程图
本实验项目需要包涵oled.c显示屏库函数、MPU6050.c运动传感器库函数、delay.c延时库函数,本实验的实验流程图如图2所示:
图2 实验流程示意图
【实验环境】
硬件设备
双轮自平衡机器人。如图3所示,平衡车所搭载的电路板上已经搭载MPU6050芯片。
ST-Link下载器(包含USB线与下载线)。如图4所示。
操作系统
Windows7/8/10,32bit/64bit
图3 双轮自平衡机器人
图4 ST-Link下载器与下载线
软件环境
Keil 5
实验场地:
无
【实验步骤】
第一步 配置工程环境
打开已经建立好的工程模板,在新建立的工程模板中已经添加五个文件夹,分别命名为USER、HARDWARE、SYSTEM、CORE、FWLib文件夹,如图5所示。其中USER文件夹存放的是主函数,HARDWARE文件夹存放的是本实验对应的硬件设备函数,SYSTEM存放的是本课程所有实验通用的函数,CORE文件夹存放的是启动文件,FWLib文件夹存放的是底层驱动函数。
图5工程模板对应的文件夹
在HARDWARE文件夹下右键导入已存在文件IOI2C.c和IOI2C.h文件,这两个文件保存在工程目录下MiniBalance_HARDWARE文件夹中IIC文件夹内,如图6所示。
图6 在HARDWARE文件夹下导入IOI2C.c和IOI2C.h文件
第二步 编写IIC实现函数
打开刚刚导入程序中的IOI2C.h文件,可以发现文件里已经预定义了许多函数。
/*----------------------------------IIC的操作函数---------------------------------*/
void IIC_Init(void); //初始化IIC的IO口 int IIC_Start(void); //发送IIC 开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack); //IIC读取一个字节
int IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data); //将一个字节写入指定设备,指定寄存器
u8 IIC_Read_One_Byte(u8 daddr,u8 addr); //读取指定设备,指定寄存器中的一个字节
unsigned char I2C_Readkey(unsigned char I2C_Addr);
unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr);//读取指定设备,指定寄存器的一个值
unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data);// 写入指定设备,指定寄存器一个字节
u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8* data); //将多个字节写入指定设备,指定寄存器
u8 IICwriteBits(u8 dev,u8 reg,u8 bitStart,u8 length,u8 data);//读,修改,写指定设备,指定寄存器一个字节中的多个位
u8 IICwriteBit(u8 dev,u8 reg,u8 bitNum,u8 data);//读,修改,写指定设备,指定寄存器一个字节中的1个位
u8 IICreadBytes(u8 dev, u8 reg, u8 length, u8 *data);//读取指定设备,指定寄存器的 length个值
打开程序中的IOI2C.c文件,编写IIC的IO口初始化函数。
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//使能GPIOB端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
//推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//50M
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//根据设定的参数初始化GPIOB
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
在IOI2C.c文件中,编写IIC_Start函数,产出IIC起始信号
int IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
if(!READ_SDA) return 0;
IIC_SCL=1;
delay_us(1);
IIC_SDA=0; //开始:当CLK线即时钟线处于高电平时,数据线从高电平变为低电平
if(READ_SDA) return 0;
delay_us(1);
IIC_SCL=0; //钳住I2C总线,准备发送或接收数据
return 1;
}
在IOI2C.c文件中,编写IIC_Stop函数,产出IIC停止信号
void IIC_Stop(void)
{
SDA_OUT(); //sda线输出
IIC_SCL=0;
IIC_SDA=0; //停止:当CLK线即时钟线处于高电平时,数据线从低电平变为高电平
delay_us(1);
IIC_SCL=1;
IIC_SDA=1; //发送I2C总线结束信号
delay_us(1);
}
为了减轻任务量,其他IIC操作函数已经编写完成,并在IOI2C.c中给出。
表1 IOI2C.c中已编写函数
第三步 编写main.c文件
将工程编译需要用到的头文件包含进来,并且定义相关变量
#include "ioi2c.h" //IIC头文件
#include "sys.h" //包含体统头文件
#include "stm32f10x.h" //包含系统寄存器定义声明的头文件
float Accel_Y,Accel_Angle,Accel_Z,Gyro_X,Gyro_Z; //定义加速度计和陀螺仪变量
在主函数中调用延时函数、IIC初始化函数、MPU6050初始化函数、OLED屏幕初始化函数。
delay_init(); //调用延时函数
IIC_Init(); //调用IIC初始化函数
MPU6050_initialize(); //调用MPU6050初始化函数
OLED_Init(); //调用OLED初始化函数
在主函数中,加入主循环,并编写IIC读取程序,以读取陀螺仪加速度计信息。其中,使用的函数主要为
unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr),其功能为读取指定设备,指定寄存器的一个值,
I2C_Addr:目标设备地址,在我们的实验中为陀螺仪和加速度计的地址。
Addr:寄存器地址,即存放陀螺仪信息和加速度计信息的寄存器地址。
while(1) //进入主循环
{
/*----------------------------读取X轴陀螺仪信息-------------------------*/
// devAddr : MPU6050的设备地址
// MPU6050_RA_GYRO_XOUT_H :Gyro_X数值的寄存器地址
Gyro_X=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_XOUT_H)<<8)
+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_XOUT_L);
/*----------------------------读取Z轴陀螺仪信息-------------------------*/
Gyro_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)
+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L);
/*----------------------------读取Y轴加速度计信息-------------------------*/
Accel_Y=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_YOUT_H)<<8)
+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_YOUT_L);
/*----------------------------读取Z轴加速度计信息-------------------------*/
Accel_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_H)<<8)
+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_L);
/*----------------------------数据类型转换,-------------------------*/
if(Gyro_X>32768) Gyro_X-=65536;
if(Gyro_Z>32768) Gyro_Z-=65536;
if(Accel_Y>32768) Accel_Y-=65536;
if(Accel_Z>32768) Accel_Z-=65536;
}
在main.c中,编写显示函数oled_show(),并在主循环中调用oled_show()函数。
void oled_show(void)
{
OLED_ShowString(00,10,"Gyro_X");
OLED_ShowNumber(95,10,Gyro_X,5,12);
OLED_ShowString(00,20,"Gyro_Z");
OLED_ShowNumber(95,20,Gyro_Z,5,12);
OLED_ShowString(00,30,"Accel_Y");
OLED_ShowNumber(95,30,Accel_Y,5,12);
OLED_ShowString(00,40,"Accel_Z");
OLED_ShowNumber(95,40,Accel_Z,5,12);
OLED_Refresh_Gram();
}
第四步 编译并下载,观察实验现象
本实验采用仿真器为STLink V2,将仿真器与小车相连,注意正负极不要接反,如图7所示。
图7 仿真器与下载线连接图
编译程序:点击如图8所示的编译按键。
图8 Keil编译环境下的编译按键
当编译完成后,如果没有问题,Build Output栏会出现无错误、无警告的提示,如图9所示。
图9 编译通过后Build Output栏提示信息
下载程序:点击如图所示的下载按键,程序就会下载到STM32的芯片中。下载按键如图1.10所示。
图10 Keil编译环境下的下载按键
观察实验现象,在小车的OLED显示屏上能够实时的显示出小车当前采集到的陀螺仪加速度计信息,微微晃动小车,可以看到显示屏上的数值有明显变化。
图11 平衡车上OLED显示屏
【思考题】
1、选择题
题目1:下面哪个结构体是设置I2C传输速率(C)
A:I2C_AcknowledgeAddress
B:I2C_DutyCycle
C:I2C_ClockSpeed
D:I2C_OwnAddress1
题目2:在I2C协议中,起始信号后产生的信号是哪种信号?(A)
A:地址位
B:传输方向选择位
2、简答题
题目1:I2C有几种传输模式,速率分别是多少?
具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式下可达3.4Mbit/s,但目前大多I2C设备尚不支持高速模式。
附录:I2C 库函数