【stm32】软件I2C读写MPU6050

软件I2C读写MPU6050(文章最后附上源码)

编码

概况

  1. 首先建立通信层的.c和.h模块

  2. 在通信层里写好I2C底层的GPIO初始化

  3. 以及6个时序基本单元

    1. 起始、终值、发送一个字节、接收一个字节、发送应答、接收应答
  4. 写好I2C通信层之后,再建立MPU6050的.c和.h模块

    1. 基于I2C通信的模块,来实现指定地址读、指定地址写

    2. 再实现写寄存器对芯片进行配置

    3. 都寄存器得到传感器数据

  5. 最终在main.c里调用MPU6050的模块

    1. 初始化

    2. 拿到数据

    3. 显示数据

  6. 这就是程序的基本架构

步骤

  1. 初始化GPIO

    1. 引脚都要配置成开漏输出的模式

    2. 开漏输出模式仍然可以输入

    3. 输入时先输出1,再直接读取数据寄存器就行了

  2. 调用Setbits,把pin10和pin11都置高电平

  3. 这也初始化就完成了

  4. 调用MyI2C_Init函数

    1. pb10和pb11两个端口就被初始化为开漏输出模式

    2. 然后释放总线

    3. SCL和SDA处于高电平

    4. 此时I2C总线处于空闲状态

  5. 接下来就根据ppt时序波形来完成6个时序单元

  6. 初始化函数之前,定义函数,对操作端口的函数进行封装

    1. void MyI2C_w_SCL(uint8_t BitValue)

    2. 函数里面调用WriteBit函数

    3. 后面再调用MyI2C_w_SCL函数,参数给1或0

    4. 就可以释放或拉低SCL

  7. 复制函数,定义SDA函数

  8. 再写一个读SDA函数uint8_t MyI2C_R_SDA(void)

  9. 写六个时序单元

    1. 开始的函数

      1. 在前面最好先释放SDA,这样保险一些

      2. 如果起始条件之前,SCL和SDA已经是高电平了,先释放哪个都无所谓

      3. 但是在图示在这里插入图片描述
        还要兼容这里的重复起始条件Sr

      4. Sr开始,SCl是低电平,SDA电平不敢确定

      5. 所以保险起见,我们趁SCL是低电平,先确保释放SDA,再释放SCL,这是SDA和SCL都是高电平

      6. 然后再拉低SDA拉低SCl

      7. 这样这个Start可以兼容起始条件和重复起始条件

    2. 结束的函数

      1. 为了确保再SCL高电平期间,SDA产生上升沿,先把SDA拉低
    3. 发送一个字节数据

    4. 接收一个字节数据

      1. 防止主机干扰从机写入数据

      2. 主机需要先释放SDA,释放SDA也相当于切换为输入模式

      3. 再释放SCL

      4. 在SCL低电平时,从机会把数据已经放到SDA上

      5. 如果从机想发1,就释放SDA,如果从机想发0,就拉低SDA

      6. 主机释放SCL,在SCL高电平期间,读取SDA

      7. 再拉低SCL,从机把下一位数据放在SDA上

    5. 发送应答

    6. 接收应答

编写MPU6050模块

  1. 调用MyI2C.h函数

  2. 初始化MPU6050,调用I2C_Init

  3. 之后在上面 先封装指定地址写和指定地址读 的时序

    1. MPU6050_WriteReg指定地址写寄存器 参数是8位的指定地址(指定读写哪个寄存器,就是要读写寄存器的地址),另一个参数是要写入的数据

    2. 为了方便修改MyI2C_SendByte()的参数,并且突出它是从机地址,可以用宏定义替换一下这个数据

  4. MyI2C_ReceiveAck应答位是可以不处理的

  5. 在接收一个字节函数里uint8_t MPU6050_ReadReg(uint8_t RegAdress)

    1. 如果只接受一个字节,应答位给1(非应答)

    2. 如果想继续接收数据,就要给0(应答)

    3. 如果想进阶为指定地址读多个字节,可以用for循环套起来,重读读取多次,最后一个应答给非应答1

写寄存器注意事项
  • 首先解除芯片的睡眠模式

    • 睡眠模式是电源管理寄存器1的SLEEP位在这里插入图片描述

    • 直接写入0x00 这样就可以解除睡眠模式了

在MPU初始化函数里配置电源管理寄存器
  1. 先用宏定义把寄存器的地址用一个字符串来表示

  2. 寄存器比较少的话可以直接在上面进行宏定义

    1. 如果比较多的话,可以再新建一个单独的头文件进行存放

    2. 再添加一个.h文件 MPU6050_Reg 存放宏定义

  3. 配置电源管理寄存器1 0x01

  4. 配置电源管理寄存器2 0x00

  5. 配置头文件里上面四个寄存器

  6. 配置完之后陀螺仪内部就在连续不断的进行数据转换了

  7. 输出的数据就存放在数据寄存器里

    1. 接下来想获取数据的话

    2. 只需要再写一个获取数据寄存器的函数

  8. 在初始化下面编写一个获取数据寄存器数据的函数

    1. 根据任务要求,函数需要返回6个int16_t数据

    2. 分别表示xyz的加速度值和陀螺仪值

    3. 但是c语言中,函数的返回值只能有一个

      1. 使用指针,进行变量的地址传递来实现多返回值

      2. 高8位左移8位或上低8位

MyI2C.c程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"void MyI2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_2, (BitAction)BitValue);Delay_us(10);
}void MyI2C_W_SDA(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_3, (BitAction)BitValue);Delay_us(10);
}uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3);Delay_us(10);return BitValue;
}void MyI2C_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//	GPIO_SetBits(GPIOA, GPIO_Pin_2 | GPIO_Pin_3);
}void MyI2C_Start(void)
{MyI2C_W_SDA(1);MyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);
}void MyI2C_Stop(void)
{MyI2C_W_SDA(0);MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}void MyI2C_SendByte(uint8_t Byte)
{uint8_t i;for (i = 0; i < 8; i ++){MyI2C_W_SDA(Byte & (0x80 >> i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}uint8_t MyI2C_ReceiveByte(void)
{uint8_t i, Byte = 0x00;MyI2C_W_SDA(1);for (i = 0; i < 8; i ++){MyI2C_W_SCL(1);if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}MyI2C_W_SCL(0);}return Byte;
}void MyI2C_SendAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;MyI2C_W_SDA(1);MyI2C_W_SCL(1);AckBit = MyI2C_R_SDA();MyI2C_W_SCL(0);return AckBit;
}

MyI2C.h程序

#ifndef __MYI2C_H
#define __MYI2C_Hvoid MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);#endif

MPU6050.c程序

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"#define MPU6050_ADDRESS		0xD0void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);MyI2C_ReceiveAck();MyI2C_SendByte(RegAddress);MyI2C_ReceiveAck();MyI2C_SendByte(Data);MyI2C_ReceiveAck();MyI2C_Stop();
}uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);MyI2C_ReceiveAck();MyI2C_SendByte(RegAddress);MyI2C_ReceiveAck();MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS | 0x01);MyI2C_ReceiveAck();Data = MyI2C_ReceiveByte();MyI2C_SendAck(1);MyI2C_Stop();return Data;
}void MPU6050_Init(void)
{MyI2C_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;
}

MPU6050.h程序

#ifndef __MPU6050_H
#define __MPU6050_Hvoid MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);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

main.c程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;
uint32_t light;int main(void)
{OLED_Init();MPU6050_Init();OLED_ShowString(1, 1, "ID:");ID = MPU6050_GetID();OLED_ShowHexNum(1, 4, ID, 2);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);}
}

如果发现错误或者需要改进的地方请私信或者评论

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

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

相关文章

Python基于深度学习的屋内烟雾检测系统的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【原创】springboot+vue校园座位预约管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

RankLLM:RAG架构下通过重排序实现精准信息检索

一、前言 在检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;的框架下&#xff0c;重排序&#xff08;Re-Rank&#xff09;阶段扮演着至关重要的角色。该阶段的目标是对初步检索得到的大量文档进行再次筛选和排序&#xff0c;以确保生成阶段能够优先…

特征融合篇 | RTDETR引入基于内容引导的特征融合方法 | IEEE TIP 2024

本改进已集成到 RT-DETR-Magic 框架。 摘要—单幅图像去雾是一个具有挑战性的不适定问题,它从观察到的雾化图像中估计潜在的无雾图像。一些现有的基于深度学习的方法致力于通过增加卷积的深度或宽度来改善模型性能。卷积神经网络(CNN)结构的学习能力仍然未被充分探索。本文提…

一周年纪念

文章目录 机缘&#xff1a;命运之门收获---知识之心日常---灵魂之窗成就 — 自我之光憧憬 — 未来之路 机缘&#xff1a;命运之门 “人生是由一连串的选择组成&#xff0c;而真正的成长&#xff0c;往往始于最具挑战性的决定。” —— 这句话恰如其分地概括了我选择跨考计算机的…

【C++】map set 底层刨析

文章目录 1. 红黑树的迭代器2. 改造红黑树3. map 的模拟实现4. set 的模拟实现 在 C STL 库中&#xff0c;map 与 set 的底层为红黑树&#xff0c;那么在不写冗余代码的情况下使用红黑树同时实现 map 与 set 便是本文的重点。 1. 红黑树的迭代器 迭代器的好处是可以方便遍历&…

数据结构--树和二叉树

树和二叉树 1.树概念及结构树的概念树的相关概念树的表示 2.二叉树概念及结构概念特殊的二叉树二叉树的性质 3.二叉树顺序结构及实现4.二叉树链式结构及实现二叉树的顺序结构二叉树的前&#xff0c;中&#xff0c;后序遍历层序遍历 1.树概念及结构 树的概念 树是一种非线性的…

SSL协议是什么?有什么作用?

SSL协议是一种让互联网上的数据传输变得更安全的技术。它的主要作用是&#xff1a; 保密性&#xff1a; 使用加密手段&#xff0c;让别人偷看不了你在网上发的信息&#xff08;比如密码、聊天内容、银行卡号等&#xff09;。完整性&#xff1a;防止你的信息在传输途中被偷偷修…

九州金榜|孩子叛逆,家长应该怎么办?

孩子是父母的宝贝&#xff0c;孩子快乐&#xff0c;作为父母就会快乐&#xff0c;每位家长都希望自己的孩子健康快乐长大。孩子在成长的过程中&#xff0c;随着年龄以及阅历的增长&#xff0c;都会出现叛逆&#xff0c;孩子出现叛逆&#xff0c;对于父母来说是一种挑战&#xf…

恶劣条件下GNSS定位的鲁棒统计

全球导航卫星系统&#xff08;GNSS&#xff09;作为定位信息的主要来源&#xff0c;在智慧工厂、智慧能源、智慧交通的未来应用中发挥着重要作用。此外&#xff0c;GNSS为电网或股市等关键应用提供定时同步功能。然而&#xff0c;GNSS的性能很容易因自然现象和信号反射而降低。…

【THM】Exploit Vulnerabilities(利用漏洞)-

介绍 在这个房间里,我们将讨论一些识别漏洞的方法,并结合我们的研究技能来了解这些漏洞是如何被滥用的。 此外,您还会发现一些公开可用的资源,这些资源是您在执行漏洞研究和利用时的技能和工具的重要补充。然后,您将在房间的最后将所有这些应用到实际挑战中。 自动化与…

HTML5.Canvas简介

1. Canvas.getContext getContext(“2d”)是Canvas元素的方法&#xff0c;用于获取一个用于绘制2D图形的绘图上下文对象。在给定的代码中&#xff0c;首先通过getElementById方法获取id为"myCanvas"的Canvas元素&#xff0c;然后使用getContext(“2d”)方法获取该Ca…

STM3定时器输入捕获、超声波测距

1、超声波测距模块介绍 1、HC-SR04共四个引脚&#xff1a;VCC、GND、Trig、Echo&#xff0c;如下图 2、使用 1、通过gpio口向Trig引脚发送一个脉冲信号。 2、HC-SR04接收到脉冲信号后&#xff0c;就会向外发送一段超声波&#xff0c;模块会将echo拉高。 …

rpm、yum和编译安装软件

一、rpm 1.rpm包管理工具 建立统一的数据库文件&#xff08;一张对应表将信息写入&#xff09; 详细记录软件包安装、卸载等变化信息&#xff0c;自动分析软件包依赖关系 2.rpm一般命令格式 bash-4.1.2-15.el6_4.x86_64.rpm bash&#xff08;shell软件名称&#xff09; …

STM32CubeIDE基础学习-定时器PWM实验

STM32CubeIDE基础学习-定时器PWM实验 文章目录 STM32CubeIDE基础学习-定时器PWM实验前言第1章 硬件介绍第2章 工程配置2.1 基础工程配置部分2.2 生成工程代码部分 第3章 代码编写3.1 查看PWM波3.2 设置单个比较值3.3 呼吸灯 第4章 实验现象总结 前言 在平时单片机开发时&#…

JQuery(一)---【JQuery简介、安装、初步使用、各种事件】

零.前言 在学习JQuery前&#xff0c;您需要具备以下知识&#xff1a; HTML相关知识(DOM)CSS相关知识JavaScript相关知识 一.JQuery 1.1JQuery简介 JQuery是一个JavaScript的“函数库”&#xff0c;不是JavaScript的一个框架&#xff0c;与“VUE、REACT”有本质区别&#x…

IPSEC VPN双机热备份的配置讲解一

IPSEC VPN双机热备份的配置讲解一 VPN 是一种专用网络&#xff0c;可使用公共网络连接两个或两个以上的远程站点。VPN 可使用通过公共网络路由&#xff08;以隧道方式发送&#xff09;的虚拟连接&#xff0c;而非网络之间的专用连接。IPsec VPN 是一项协议&#xff0c;由建立 …

DHCP-PXE

Dynamic Host Configuration Protocol 动态主机配置协议 1.Selinux 调试为Permission 防火墙配置 搭建DHCP的主机必须有一个静态地址&#xff0c;提前配置好 安装DHCP软件 服务名为dhcpd DHCP地址分配四次会话&#xff0c; DISCOVERY发现 OFFER 提供 REQUEST 回应 A…

代码随想录算法训练营第42天| 背包问题、416. 分割等和子集

01 背包 题目描述&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 二维dp数组01背包&#xff1a; 确定dp数组以及下标的含义 …

实景三维技术也是一种新质生产力

实景三维技术作为一种新兴的技术手段&#xff0c;正在逐渐被认为是一种新质生产力。它通过高精度的数据采集、处理和可视化&#xff0c;为多个行业领域提供了全新的工作方式和解决方案&#xff0c;从而推动了生产力的发展和创新。以下是实景三维技术作为新质生产力在不同方面的…