版权归如下公司,禁止非授权转载:
I2C (Inter-Integrated Circuit)协议是由Phiilps公司开发的,由于它具引脚少,硬件实现简单,可扩展性强,不需要如USART、CAN的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。
I2C总线在传送数据过程中共有三种类型信号,它们分别是:开始信号、结束信号和应答信号。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。
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
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文件
打开刚刚导入程序中的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中已编写函数
将工程编译需要用到的头文件包含进来,并且定义相关变量
#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:下面哪个结构体是设置I2C传输速率(C)
A:I2C_AcknowledgeAddress
B:I2C_DutyCycle
C:I2C_ClockSpeed
D:I2C_OwnAddress1
题目2:在I2C协议中,起始信号后产生的信号是哪种信号?(A)
A:地址位
B:传输方向选择位
题目1:I2C有几种传输模式,速率分别是多少?
具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式下可达3.4Mbit/s,但目前大多I2C设备尚不支持高速模式。