【STM32】STM32学习笔记-软件I2C读写MPU6050(33)

news2024/11/17 0:03:38

00. 目录

文章目录

    • 00. 目录
    • 01. I2C简介
    • 02. MPU6050参数
    • 03. 软件I2C接线图
    • 04. I2C模拟应答时序示例
    • 05. I2C读取MPU6050程序示例
    • 06. 程序下载
    • 07. 附录

01. I2C简介

I2C(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。

串行的 8 位双向数据传输位速率在标准模式下可达 100kbit/s,快速模式下可达 400kbit/s,高速模式下可达 3.4Mbit/s。

I2C是一个多主机的总线,每个设备既可以当主控器或被控器,又可作为发送器或接收器,一条总线上可以有多个主机,但同一时刻只允许一个主机工作。

02. MPU6050参数

  • 16位ADC采集传感器的模拟信号,量化范围:-32768~32767
  • 加速度计满量程选择:±2、±4、±8、±16(g)
  • 陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)
  • 可配置的数字低通滤波器
  • 可配置的时钟源
  • 可配置的采样分频
  • I2C从机地址:1101000(AD0=0) 1101001(AD0=1)

03. 软件I2C接线图

在这里插入图片描述

04. I2C模拟应答时序示例

i2c.h

#ifndef __I2C_H__

#define __I2C_H__

#include "stm32f10x.h"   


#include "i2c.h"
#include "delay.h"


void i2c_W_SCL(uint8_t value);
void i2c_W_SDA(uint8_t value);
uint8_t i2c_R_SDA(void);

//I2C初始化
void i2c_init(void);
//起始条件
void i2c_start(void);
//结束条件
void i2c_stop(void);
//发送一个字节
void i2c_send_byte(uint8_t value);
//接收一个字节
uint8_t i2c_recv_byte(void);
//发送ACK
void i2c_send_ACK(uint8_t ack);
//接收一个字节
uint8_t i2c_recv_ACK(void);


#endif /*__I2C_H__*/

i2c.c

#include "i2c.h"
#include "delay.h"


void i2c_W_SCL(uint8_t value)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)value);
	delay_us(10);
}

void i2c_W_SDA(uint8_t value)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)value);
	delay_us(10);
}

uint8_t i2c_R_SDA(void)
{
	uint8_t value;

	value = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	delay_us(10);
	
	return value;
}


//I2C初始化
void i2c_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	//SCL B10  SDA B11
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);

	//初始状态为高电平
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}


//起始条件
void i2c_start(void)
{
	i2c_W_SDA(1);
	i2c_W_SCL(1);
	i2c_W_SDA(0);	
	i2c_W_SCL(0);
}


//结束条件
void i2c_stop(void)
{
	i2c_W_SDA(0);
	i2c_W_SCL(1);
	i2c_W_SDA(1);
}

//发送一个字节
void i2c_send_byte(uint8_t value)
{
	uint8_t i = 0;

	for (i = 0; i < 8; i++)
	{
		i2c_W_SDA(value & (0x80 >> i));
		i2c_W_SCL(1);
		//delay_us(5);
		i2c_W_SCL(0);	
	}
}


//接收一个字节
uint8_t i2c_recv_byte(void)
{
	uint8_t i = 0;
	uint8_t value = 0;

	//主设备释放SDL
	i2c_W_SDA(1);

	for (i = 0; i < 8; i++)
	{
		i2c_W_SCL(1);
		if (i2c_R_SDA() == 1)
		{
			value = value | 0x80 >> i;
		}
		
		i2c_W_SCL(0);
	}

	return value;
}


//发送ACK
void i2c_send_ACK(uint8_t ack)
{
	i2c_W_SDA(ack);
	i2c_W_SCL(1);
	//delay_us(5);
	i2c_W_SCL(0);	
}


//接收一个字节
uint8_t i2c_recv_ACK(void)
{
	uint8_t value = 0;

	//主设备释放SDL
	i2c_W_SDA(1);

	i2c_W_SCL(1);
	value = i2c_R_SDA();
		
	i2c_W_SCL(0);

	return value;
}

main.c

#include "stm32f10x.h"

#include "delay.h"
#include "oled.h"
#include "i2c.h"


 int main(void)
 {	 
	 uint8_t ack;
	 //初始化
	 OLED_Init();
	 
	 i2c_init();

	 i2c_start();
	 i2c_send_byte(0xD0);
	 
	 ack = i2c_recv_ACK();
	 
	 i2c_stop();
	 
	 OLED_ShowNum(1, 1, ack, 2);
	 
 
	 while(1)
	 {
		 
	 }
	 
	 return 0;
 }


 

05. I2C读取MPU6050程序示例

i2c.h

#ifndef __I2C_H__

#define __I2C_H__

#include "stm32f10x.h"   


#include "i2c.h"
#include "delay.h"


void i2c_W_SCL(uint8_t value);
void i2c_W_SDA(uint8_t value);
uint8_t i2c_R_SDA(void);

//I2C初始化
void i2c_init(void);
//起始条件
void i2c_start(void);
//结束条件
void i2c_stop(void);
//发送一个字节
void i2c_send_byte(uint8_t value);
//接收一个字节
uint8_t i2c_recv_byte(void);
//发送ACK
void i2c_send_ACK(uint8_t ack);
//接收一个字节
uint8_t i2c_recv_ACK(void);


#endif /*__I2C_H__*/

i2c.c

#include "i2c.h"
#include "delay.h"


void i2c_W_SCL(uint8_t value)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)value);
	delay_us(10);
}

void i2c_W_SDA(uint8_t value)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)value);
	delay_us(10);
}

uint8_t i2c_R_SDA(void)
{
	uint8_t value;

	value = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	delay_us(10);
	
	return value;
}


//I2C初始化
void i2c_init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	//SCL B10  SDA B11
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);

	//初始状态为高电平
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}


//起始条件
void i2c_start(void)
{
	i2c_W_SDA(1);
	i2c_W_SCL(1);
	i2c_W_SDA(0);	
	i2c_W_SCL(0);
}


//结束条件
void i2c_stop(void)
{
	i2c_W_SDA(0);
	i2c_W_SCL(1);
	i2c_W_SDA(1);
}

//发送一个字节
void i2c_send_byte(uint8_t value)
{
	uint8_t i = 0;

	for (i = 0; i < 8; i++)
	{
		i2c_W_SDA(value & (0x80 >> i));
		i2c_W_SCL(1);
		//delay_us(5);
		i2c_W_SCL(0);	
	}
}


//接收一个字节
uint8_t i2c_recv_byte(void)
{
	uint8_t i = 0;
	uint8_t value = 0;

	//主设备释放SDL
	i2c_W_SDA(1);

	for (i = 0; i < 8; i++)
	{
		i2c_W_SCL(1);
		if (i2c_R_SDA() == 1)
		{
			value = value | 0x80 >> i;
		}
		
		i2c_W_SCL(0);
	}

	return value;
}


//发送ACK
void i2c_send_ACK(uint8_t ack)
{
	i2c_W_SDA(ack);
	i2c_W_SCL(1);
	//delay_us(5);
	i2c_W_SCL(0);	
}


//接收一个字节
uint8_t i2c_recv_ACK(void)
{
	uint8_t value = 0;

	//主设备释放SDL
	i2c_W_SDA(1);

	i2c_W_SCL(1);
	value = i2c_R_SDA();
		
	i2c_W_SCL(0);

	return value;
}

MPU6050.h

#ifndef __MPU6050_H__

#define __MPU6050_H__


#include "mpu6050.h"
#include "i2c.h"


#define MPU6050_ADDRESS		    0xD0

#define	MPU6050_SMPLRT_DIV		0x19
#define	MPU6050_CONFIG			0x1A
#define	MPU6050_GYRO_CONFIG		0x1B
#define	MPU6050_ACCEL_CONFIG	0x1C

#define	MPU6050_ACCEL_XOUT_H	0x3B
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48

#define	MPU6050_PWR_MGMT_1		0x6B
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75




void MPU6050_WriteReg(uint8_t regAddr, uint8_t data);
uint8_t MPU6050_ReadReg(uint8_t regAddr);
void MPU6050_init(void);
uint8_t MPU6050_getId(void);
void MPU6050_getData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ);


#endif /*__MPU6050_H__*/

MPU6050.c

#include "mpu6050.h"
#include "i2c.h"


void MPU6050_WriteReg(uint8_t regAddr, uint8_t data)
{
	
	i2c_start();
	
	i2c_send_byte(MPU6050_ADDRESS);
	
	i2c_recv_ACK();
	
	i2c_send_byte(regAddr);
	i2c_recv_ACK();
	
	i2c_send_byte(data);
	i2c_recv_ACK();
	
	i2c_stop();
}

uint8_t MPU6050_ReadReg(uint8_t regAddr)
{
	uint8_t data = 0;
	
	i2c_start();
	
	i2c_send_byte(MPU6050_ADDRESS);
	
	i2c_recv_ACK();
	
	i2c_send_byte(regAddr);
	i2c_recv_ACK();

	i2c_start();
	
	i2c_send_byte(MPU6050_ADDRESS | 0x1);
	
	i2c_recv_ACK();
	
	data = i2c_recv_byte();
	i2c_send_ACK(1);
	
	i2c_stop();
	
	return data;
}


void MPU6050_init(void)
{
	i2c_init();
	
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
	MPU6050_WriteReg(MPU6050_CONFIG, 0x06);
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}

uint8_t MPU6050_getId(void)
{
	return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}

void MPU6050_getData(int16_t *AccX, int16_t *AccY, int16_t *AccZ, 
						int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
	uint8_t DataH, DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
	DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}

main.c

#include "stm32f10x.h"

#include "delay.h"
#include "oled.h"
#include "mpu6050.h"


 int main(void)
 {	 
	 uint8_t data = 0;
	 int16_t AX, AY, AZ, GX, GY, GZ;

	 //初始化
	 OLED_Init();
	 MPU6050_init();
	 
	 data = MPU6050_getId();
	 OLED_ShowString(1, 1, "ID: ");
	 OLED_ShowHexNum(1, 5, data, 3);
	 
 
	 while(1)
	 {
		MPU6050_getData(&AX, &AY, &AZ, &GX, &GY, &GZ);
		OLED_ShowSignedNum(2, 1, AX, 5);
		OLED_ShowSignedNum(3, 1, AY, 5);
		OLED_ShowSignedNum(4, 1, AZ, 5);
		OLED_ShowSignedNum(2, 8, GX, 5);
		OLED_ShowSignedNum(3, 8, GY, 5);
		OLED_ShowSignedNum(4, 8, GZ, 5);
		 
		 delay_ms(100);
		 
	 }
	 
	 return 0;
 }


 

06. 程序下载

27-软件I2C时序模拟.rar

28-软件I2C.rar

07. 附录

参考: 【STM32】江科大STM32学习笔记汇总

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1390689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DeepSecrets:一款能够理解代码语义的代码敏感信息扫描工具

关于DeepSecrets DeepSecrets是一款能够理解代码语义的代码敏感信息扫描工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员将能够更有效地扫描和分析代码中的敏感信息。 社区中很多现有的代码分析工具其实并不能够真正地“理解”代码&#xff0c;而是直接解析代码文…

(亲测可行)关于提高IDEA运行速度的方案

1.作者IDEA软件版本和计算机内存 Ultimate 2022.1.2版IDEA&#xff0c;计算机内存为12GB 2.修改配置以提高IDEA运行速度的误区-调高堆内存 很多文章会教调配置的内存&#xff0c;但大多是让你调高堆内存&#xff0c;比如会让你调高-Xms -Xmx &#xff0c;这两种对应的是最…

Linux:理解磁盘与文件系统

文章目录 前面基础的总结文件系统文件的管理目的问题文件的管理内容问题 磁盘磁盘的结构和基本原理磁盘的分区磁盘的索引原理磁盘的逻辑抽象写入 本篇主要对于磁盘进行深入的理解&#xff0c;从而对于文件系统有一个基本的认识 前面基础的总结 在开始对文件系统做理解前&…

【PostgreSQL】安装和常用命令教程

PostgreSQL window安装教程 window安装PostgreSQL 建表语句&#xff1a; DROP TABLE IF EXISTS student; CREATE TABLE student (id serial NOT NULL,name varchar(100) NOT NULL,sex varchar(5) NOT NULL,PRIMARY KEY (id) );INSERT INTO student (id, name, sex) VALUES (…

Ubuntu 22.04安装使用easyconnect

EasyConnect 百度百科&#xff0c;EasyConnect能够帮助您在办公室之外使用公司内网的所有系统及应用。在您的公司部署深信服远程应用发布解决方案后&#xff0c;您的公司所有业务系统及应用都可以轻松迁移至移动互联网上。您可以通过手机、PAD等智能移动终端随时随地开展您的业…

程序员接私活还不知道这几个平台?那你真的亏了!

程序员接私活现在已经是一个老生常谈的话题了&#xff0c;现在市面上各种程序员接单平台层出不穷&#xff0c;也参差不齐&#xff0c;有比较老牌的知名平台&#xff0c;也有比较好的新兴平台&#xff0c;如此多的平台就容易让人眼花缭乱&#xff0c;不知道该如何选择。 这期文…

CSS3背景样式详解(图像大小,图像位置等)

背景样式 在CSS3中&#xff0c;新增了3个背景属性 属性说明background-size背景大小background-origin背景位置background-clip背景剪切 background-size属性 概念&#xff1a;在CSS3之前&#xff0c;我们是不能用CSS来控制背景图片大小的&#xff0c;背景图片的大小都是由…

【HarmonyOS】消息通知场景的实现

从今天开始&#xff0c;博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”&#xff0c;对于刚接触这项技术的小伙伴在学习鸿蒙开发之前&#xff0c;有必要先了解一下鸿蒙&#xff0c;从你的角度来讲&#xff0c;你认为什么是鸿蒙呢&#xff1f;它出现的意义又是…

(N-139)基于springboot,vue宠物领养系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vue3element-plus 服务端技术&#xff1a;springbootmybatis-plusr…

C练习——杨辉三角

题目&#xff1a; 打印近似杨辉三角&#xff0c;行数n自选 百度找的杨辉三角&#xff0c;参考一下&#xff1a; 解析&#xff1a; 把它的全部元素左对齐&#xff0c;就可以看成近似杨辉三角的样子 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 …… 每个数等于它上方两数…

C++基础1

一、形参带默认值的函数 二、inline内联函数 内联函数是一种在编译器处理时&#xff0c;将函数的实际代码插入到调用处的方法。通常&#xff0c;函数调用涉及一定的开销&#xff0c;包括保存和恢复调用现场、跳转到函数的代码位置等。而内联函数通过在调用处直接插入函数的代码…

十五.流程控制与游标

流程控制与游标 1.流程控制1.1分支结构之IF1.2分支结构值CASE1.3循环结构之LOOP1.4循环结构之WHILE1.5循环结构之REPEAT1.6跳转语句之LEAVE语句1.7跳转语句之ITERATE语句 2.游标2.1什么是游标2.2使用游标步骤4.3举例4.5小结 1.流程控制 解决复杂问题不可能通过一个 SQL 语句完…

智慧校园大数据平台架构

平台架构 基础硬件层 基础硬件层是由一组低廉的PC或服务器组合构建而成。基础硬件层主要承载着数据的存储、运算、容错、调度和通信等任务,对基础应用层下达的指令进行执行和反馈。 数据集成 大数据特征表现在实时、交互、海量等方面,并且以半结构化、非结构化数据为主,价…

SpringBoot中 如何优雅的 重试调用 第三方API?

引言 在实际的应用中&#xff0c;我们经常需要调用第三方API来获取数据或执行某些操作。然而&#xff0c;由于网络不稳定、第三方服务异常等原因&#xff0c;API调用可能会失败。为了提高系统的稳定性和可靠性&#xff0c;我们通常会考虑实现重试机制。 本文将深入探讨如何在…

基于JAVA的固始鹅块销售系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 鹅块类型模块2.3 固始鹅块模块2.4 鹅块订单模块2.5 评论管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 鹅块类型表3.2.2 鹅块表3.2.3 鹅块订单表3.2.4 鹅块评论表 四、系统展示五、核心代码5.…

vue前端开发自学,祖孙多层级组件嵌套关系数据传输

vue前端开发自学,祖孙多层级组件嵌套关系数据传输&#xff01;官方提供了一个解决方案&#xff0c;就是&#xff0c;在根组件内使用provide,哪个子孙组件想调用这个数据&#xff0c;就可以inject接收就行了。虽然是方便了&#xff0c;但是这个有点要求&#xff0c;就是只能自上…

重新认识Word——页眉页脚

重新认识Word——页眉页脚 节设置页脚第X页&#xff0c;共Y页 奇偶页不同页眉包含章节号清除页眉横线 我们之前已经全面的构建了我们的文章&#xff0c;现在我们来了解一下&#xff0c;我们毕业论文的页眉&#xff08;页面信息&#xff09;页脚&#xff08;页码&#xff09;的设…

JVM运行时数据区(下篇)

紧接上篇&#xff1a;JVM运行时数据区&#xff08;上篇&#xff09;-CSDN博客 堆 一般Java程序中堆内存是空间最大的一块内存区域。创建出来的对象都存在于堆上。 栈上的局部变量表中&#xff0c;可以存放堆上对象的引用。静态变量也可以存放堆对象的引用&#xff0c;通过静态…

Java中的Servlet你了解吗?

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

《数据结构》实验报告-实验一 线性结构及其应用

《数据结构》实验报告-实验一 线性结构及其应用 一、问题分析 题目要求收集两个班的学生成绩信息并按降序排列&#xff0c;其中每个学生的数据包括班级&#xff0c;学号和成绩信息&#xff0c;需要用一个结构体作为整体存储。并且数据是可以不断添加进来的&#xff0c;可以用…