江协科技STM32学习- P33 实验-软件I2C读写MPU6050
🚀write in front🚀
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝💬本系列哔哩哔哩江科大STM32的视频为主以及自己的总结梳理📚
🚀Projeet source code🚀
💾工程代码放在了本人的Gitee仓库:iPickCan (iPickCan) - Gitee.com
引用:
STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili
Keil5 MDK版 下载与安装教程(STM32单片机编程软件)_mdk528-CSDN博客
STM32之Keil5 MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客
0. 江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客
【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客
江科大STM32学习笔记(上)_stm32博客-CSDN博客
STM32学习笔记一(基于标准库学习)_电平输出推免-CSDN博客
STM32 MCU学习资源-CSDN博客
stm32学习笔记-作者: Vera工程师养成记
stem32江科大自学笔记-CSDN博客
术语:
| 英文缩写 | 描述 |
| GPIO:General Purpose Input Onuput | 通用输入输出 |
| AFIO:Alternate Function Input Output | 复用输入输出 |
| AO:Analog Output | 模拟输出 |
| DO:Digital Output | 数字输出 |
| 内部时钟源 CK_INT:Clock Internal | 内部时钟源 |
| 外部时钟源 ETR:External Trigger | 时钟源 External 触发 |
| 外部时钟源 ETR:External Trigger mode 1 | 外部时钟源 External 触发 时钟模式1 |
| 外部时钟源 ETR:External Trigger mode 2 | 外部时钟源 External 触发 时钟模式2 |
| 外部时钟源 ITRx:Internal Trigger inputs | 外部时钟源,ITRx (Internal trigger inputs)内部触发输入 |
| 外部时钟源 TIx:exTernal Input pin | 外部时钟源 TIx (external input pin)外部输入引脚 |
| CCR:Capture/Comapre Register | 捕获/比较寄存器 |
| OC:Output Compare | 输出比较 |
| IC:Input Capture | 输入捕获 |
| TI1FP1:TI1 Filter Polarity 1 | Extern Input 1 Filter Polarity 1,外部输入1滤波极性1 |
| TI1FP2:TI1 Filter Polarity 2 | Extern Input 1 Filter Polarity 2,外部输入1滤波极性2 |
| DMA:Direct Memory Access | 直接存储器存取 |
正文:
0. 概述
从 2024/06/12 定下计划开始学习下江协科技STM32课程,接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32 开发,本文是视频教程 P2 STM32简介一讲的笔记。
1.🚚MP6050
本节我们来用软件I2C读写MPU6050
接线图:

由于我们这个代码使用的是软件I2C,就是用普通的GPIO口,手动翻转电平实现的协议。它并不需要STM32内部的外设资源支持。所以这里的端口其实可以任意指定,不局限于这两个端口,接在任意的两个普通的GPIO口就可以。
然后我们只需要在程序中配置并操作SCL和SDA对应的端口就行了。这算是软件I2C相比硬件I2C的一大优势,就是端口不受限,可以任意指定。
根据I2C协议的硬件规定,SCL和SDA都应该外挂一个上拉电阻,但是我们的接线这里并没有外挂上拉电阻。是因为上一节我们分析模块电路的时候提到过这个模块内部自带了上拉电阻,所以外部的上拉电阻就不需要接了。
目前这里STM32是主机,MPU6050是从机,是一主一从的模型,当然主机和从机的执行逻辑是完全不同的,我们程序中一般只关注主机端的程序。
这里由于模块内置了下拉电阻,所以引脚悬空的话就相当于接地。
MyI2C.c
由于我们本代码要使用软件I2C,所以I2C的库函数我们就不用看了。软件I2C只需要用GPIO的读写函数就行了。
初始化函数
然后初始化函数中,我们要做两个任务。第一个任务把SCL和SDA都初始化为开漏输出模式(开漏输出低电平+浮空输入也就是高阻态)。第二个任务把SCL和SDA置高电平。
⚠️⚠️⚠️注意:开漏输出并不只能输出,开漏输出模式仍然可以输入。
⚠️⚠️⚠️输入时先输出1,再直接读取输入数据寄存器就行了。

然后接下来我们就来完成I2C的六个时序基本单元。
起始条件
第一个基本单元是起始条件,这里对应写一个函数。
起始条件:SCL高电平期间,SDA从高电平切换到低电平
我们首先把SCL和SDA都确保释放,然后先拉低SDA,再拉低SCL,这样就能产生起始条件了。

在这里我们可以不断的调用SetBits和RetsetBits手动翻转高低电平。但是这样做的话,会在后面的程序中出现非常多的地方来指定这个GPIO端口号。一方面这样做语义并不是很明显,另一方面,如果我们之后需要换一个端口,就需要改动非常多的地方。所以这时我们就需要在上面做个定义,把这个端口号统一替换一个名字,这样无论是语义,还是端口的修改,都会非常方便。给端口号换一个名字,有很多方法都能实现功能。在51单片机中,我们一般使用sbit来定义端口的名称,但是sbit并不是标准C语言的语法,STM32也不支持这样做。这里一种简单的替换方法就是宏定义define。

修改引脚的时候,直接在上面修改一下宏定义,这是一种简单可行的方法,在STM32程序中也是挺常见的一个操作。
进一步的,如果觉得每次都需要定义port和pin比较麻烦,还可以把这整个函数用宏定义进行替换,并且用宏定义替换的函数还可以有参数,叫有参宏。
以我们之前讲过的OLED的程序为例:

在宏定义后面加一个括号,里面写入形参,在实际引用的时候,传入实参。
这样实际上OLED_W_SCL(1)就等价于GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(1));
补充:BitAction是什么意思?
在STM32中,用于强制将特定的操作数转换为一个位值,将一个非零值转换为逻辑高电平(1),将零值转换为逻辑低电平(0)。
在GPI0操作中,可以使用"BitAction"宏定义来设置引脚的状态,例如通过调用GPI0 writeBit()函数来设置引脚的输出状态。
GPI0x表示GPIO端口,GPI0 Pin表示具体的引脚位,而BitAction表示要设置的引脚状态。
但是这种方法在移植到其他库或者其他种类单片机时,很多人都不知道怎么修改。另外还有这种宏定义的方法,如果换到一个主频很高的单片机中,需要对软件的时序进行延时操作的时候也不太方便进一步修改。
所以综合以上缺点,在这里我们就直接一点干脆再套个函数。如果单片机主频比较快,也非常方便加一些延时,比如每次操作引脚之后,都要延时10us。

后面再调用这个W_SCL,参数给1或0就可以释放或拉低SCL了。
对于STM32F1系列,这里即使不加任何延时,这个引脚翻转速度,MPU6050也能跟得上。但是保险起见,还是延时个十微秒。
如果要把这个程序移植到别的单片机,就可以把这个函数里的操作替换为其他单片机对应的操作。比如SCL是51单片机的P10口,就可以把GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);这句替换为P10=BitValue。
操作SDA的函数
接下来封装一下操作SDA的函数:

读和写不是同一个寄存器,再定义一个函数

有了这三个函数的分装,我们就实现了函数名称、端口号的替换。同时也可以很方便的修改时序的延时。当我们需要替换端口,或者把这个程序移植到别的单片机中时,就只需要对这前四个函数里的操作对应更改。
我们回到这个函数,开始调用以上四个函数。
我们需要先把SCL和SDA都释放,也就是都输出1,然后先拉低SDA。再拉低SCL,这就是起始条件的执行逻辑。
📌📌注意:我们最好把释放SDA的放在前面。
如果起始条件之前,SCL和SDA已经是高电平了,先释放哪一个是一样的效果。

📌📌但是后面start还要兼容这里的重复起始条件sr。
如果sr最开始SCL是低电平,SDA电平不敢确定,所以保险起见,趁SCL是低电平时,先确保释放SDA再释放SCL,这时SDA和SCL都是高电平。然后再拉低SDA拉低SCL,这样start就可以兼容起始条件和重复起始条件了。

接下来继续终止条件
终止条件
终止条件:SCL高电平期间,SDA从低电平切换到高电平

果stop开始时SCL和SDA都已经是低电平了,就先释放SCL,再释放SDA就行了。但是在这个时序单元开始时,SDA并不一定是低电平。

所以为了确保之后释放SDA,能产生上升沿,我们要在时序单元开始时先拉低SDA,然后再释放SCL,释放SDA。

然后是发送一个字节
发送一个字节
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

实际上除了终止条件SCL以高电平结束,所有的单元我们都会保证SCL以低电平结束,这样方便各个单元的拼接。

SCL低电平变换数据,高电平保持数据稳定,由于是高位先行,所以变换数据的时候,按照先放最高位再放次高位,依次把一个字节的每一位放在SDA线上,每放完一位后执行释放SCL拉低SCL的操作,驱动时钟运转。
Byte & 0x80 就是保留字节的高位,对其他位清0,假设Byte是xxxx xxxxx

由于调用的这个函数中的参数最后会被强制转换成bitAction类型,所以非0即1,所以最终MyI2C_W_SDA(Byte & (0x80 >> i))也相当于传了一个1

接着继续写接收一个字节
接收一个字节
接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

主机需要先释放SDA,释放SDA也相当于切换为输入模式。
SCL低电平变换数据,高电平读取数据,实际上就是一种读写分离的设计,低电平时间定义为写的时间,高电平时间定义为读的时间。
SCL高电平时,SDA下降沿为起始条件,SDA上升沿为终止条件。这个设计也保证了起始和终止的特异性,能够让我们在连续不断的波形中快速的定位起始和终止。因为起始终止和数据传输的波形有本质区别。数据传输时SCL高电平不许动SDA,起始终止条件下是SCL高电平必须动SDA

📌📌注意:I2C是在进行通信,通信是有从机的,当主机不断驱动SCL时钟时,从机就有义务去改变SDA的电平。所以主机每次循环读取SDA的时候,这个读取到的数据是从机控制的,这个数据也正是从机想要给我们发送的数据。
发送应答
然后发送应答和接收应答只要复制发送一个字节和接收一个字节的函数修改一下就可以了。
发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答


接收应答
接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)


📌📌注意:I2C的引脚都是开漏输出+弱上拉的配置。主机输出1并不是强制SDA为高电平,而是释放SDA;I2C通信时,主机释放了SDA,从机在此时把SDA再拉低的。所以这里即使之前主机把SDA置1再读取SDA,读到的值也可能是0,读到0代表从机给了应答,读到1代表从机没给应答。
测试应答功能
想要测试应答功能时主函数可以这样调用

这样就可以测试从机给不给应答的时序
1101 000是从机的地址,可以理解为是从机的名字,最低位的0是表示“写入操作”
这样运行后显示从机可以给我们应答

我们接下来讲一下通过AD0引脚改名的功能。
通过AD0引脚改名的功能
我们可以把一根飞线连接AD0引脚和VCC, 这时MPU6050的从机地址就是1101 001了。

这个时候运行就发现从机没有给我们应答了,因为它刚刚改名成1101 001了。
这个时候把飞线拔掉,再次运行发现它又可以应答了。

这就是改名的实验现象。目前我们这个芯片只有AD0一个引脚,它就只能拥有两个名字。如果有AD0和AD1两个引脚,就可以拥有总共四个名字。如果有更多的可配置引脚,就有更多的改名机会。当我们需要一条总件挂载多个相同型号的设备时,就可以利用这个改名的功能,避免名字也就是从机地址的重复。
相关文章:
江协科技STM32学习- P33 实验-软件I2C读写MPU6050
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...
BusHound工具的使用-调试USB
12 1.Capture(捕捉按钮)、2.Save(保存按钮)、3.Setting(设置要监听的,输入输出)、4.Device(选择要监听的设备)、5.Help(帮助按钮)、6.Exit(退出按钮)。 一、Capture页面 1.Device 表示是29设备端口,打印机。 2.Phase,各类协议,…...
Hadoop生态圈框架部署(四)- Hadoop完全分布式部署
文章目录 前言一、Hadoop完全分布式部署(手动部署)1. 下载hadoop2. 上传安装包2. 解压hadoop安装包3. 配置hadoop配置文件3.1 虚拟机hadoop1修改hadoop配置文件3.1.1 修改 hadoop-env.sh 配置文件3.3.2 修改 core-site.xml 配置文件3.3.3 修改 hdfs-site…...
Spring Boot 与 Vue 共铸卓越采购管理新平台
作者介绍:✌️大厂全栈码农|毕设实战开发,专注于大学生项目实战开发、讲解和毕业答疑辅导。 🍅获取源码联系方式请查看文末🍅 推荐订阅精彩专栏 👇🏻 避免错过下次更新 Springboot项目精选实战案例 更多项目…...
leetcode3. Longest Substring Without Repeating Characters
Given a string s, find the length of the longest substring without repeating characters. Example 1: Input: s “abcabcbb” Output: 3 Explanation: The answer is “abc”, with the length of 3. Example 2: Input: s “bbbbb” Output: 1 Explanation: The ans…...
Mongodb使用视图连接两个集合
您可以使用 $lookup 为两个集合创建一个视图,然后对该视图运行查询。应用程序可以查询视图,而无需构建或维护复杂的管道。 例子 创建两个样本集合 inventory 和 orders: db.inventory.insertMany( [{ prodId: 100, price: 20, quantity: 1…...
SIP是什么?
SIP(Session Initiation Protocol,会话启动协议)是一个用于建立、更改和终止多媒体会话的应用层控制协议,其中的会话可以是IP电话、多媒体会话或多媒体会议。 SIP是IETF多媒体数据和控制体系结构的核心协议(最新RFC文档…...
Day 39 || 01背包、416. 分割等和子集
01背包 题目链接:卡码网第46题 二维解题思路:需要建立一个i行k列的dp数组,i表示每个物品,k代表容量,初始化数组子一列为0,第一行从背包开始能够放入起始为价值,其他都为0。for双循环先背包后物…...
调用detr-resnet-50进行目标检测
from transformers import DetrImageProcessor, DetrForObjectDetection import torch from PIL import Imageimage = Image.open("1.jpg") torch.set_default_device("cuda"...
Chromium 中chrome.fontSettings扩展接口定义c++
一、chrome.fontSettings 使用 chrome.fontSettings API 管理 Chrome 的字体设置。 权限 fontSettings 要使用 Font Settings API,您必须在扩展程序中声明 "fontSettings" 权限 清单。例如: {"name": "My Font Settings E…...
在Unity游戏开发在面试时会面试哪些内容?
1、请描述游戏动画有几种,以及其原理。 关键帧动画:每一帧动画序列当中包含了顶点的空间位置信息以及改变量,然后通过插值运算,得出动画效果。选中某一游戏对象,创建animation,添加属性Transform࿰…...
刘艳兵-DBA022-以下关于Oracle半连接的描述,哪些是正确的?
以下关于Oracle半连接的描述,哪些是正确的? A SQL中的NOT EXISTS子查询,通常会被转换为对应的半连接。 B SQL中的IN子查询,通常会被转换为对应的半连接。 C 半连接会去重 D SQL中的EXISTS子查询,通常会被转…...
人工智能与伦理:我们应该如何平衡科技与人性?
内容概要 在这个瞬息万变的时代,人工智能的迅猛发展让我们面对前所未有的伦理困境。科技进步带来了便利,但同时也亟需我们反思如何对待人性。尤其是在实现算法透明性时,我们要确保每一个决策背后都能被理解与追溯,这不仅是对技术…...
CRON组件一个复杂的一个简单的
CRON组件一个复杂的一个简单的 一个是复杂点的一个是简单点。 1.以简单的为例使用: 父组件 import CronSimple from "/views/xxx/components/cron-simple/index.vue";components: {CronSimple}<el-dialog title"调度CRON"v-if"cronV…...
自定义日志打成jar包引入项目后不生效
背景:写了一个请求响应日志包,打包后在另一个项目使用pom引入后不生效 package com.example.qqllog.aspect;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean;…...
RK3568平台开发系列讲解(中断篇)延迟工作实验
🚀返回专栏总目录 文章目录 一、什么是延迟工作二、 struct delayed_work三、延迟工作相关接口函数3.1、初始化延迟工作函数3.2、调度/取消调度 延迟工作函数四、驱动程序编写沉淀、分享、成长,让自己和他人都能有所收获!😄 一、什么是延迟工作 延迟工作是一种将工作的执…...
RabbitMQ 的集群
大家好,我是锋哥。今天分享关于【RabbitMQ 的集群】面试题?希望对大家有帮助; RabbitMQ 的集群 RabbitMQ 是一种流行的开源消息代理,广泛用于构建分布式系统中的消息队列。随着应用程序规模的扩大,单一的 RabbitMQ 实…...
整车功能架构 --- 智能座舱
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧…...
java stream流的使用
Java中的Stream API是Java 8引入的一个重要特性,它提供了对集合对象进行各种非常便利、高效的聚合操作(aggregate operation)或大批量数据操作(bulk data operation)。Stream API借助于Lambda表达式,极大地…...
(JVM)带你一起研究JVM的语法糖功能 和 JVM的即时编译器
1. 语法糖 所谓的语法糖,其实就是指java编译器把*.java源码编译为*.class字节码的过程中,自动生成和转换的一些代码,主要是为了减轻程序员的负担,算是java编译器给我们第一个额外福利 以下代码的分析,借助了javap工具…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
[拓扑优化] 1.概述
常见的拓扑优化方法有:均匀化法、变密度法、渐进结构优化法、水平集法、移动可变形组件法等。 常见的数值计算方法有:有限元法、有限差分法、边界元法、离散元法、无网格法、扩展有限元法、等几何分析等。 将上述数值计算方法与拓扑优化方法结合&#…...
PydanticAI快速入门示例
参考链接:https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...
职坐标物联网全栈开发全流程解析
物联网全栈开发涵盖从物理设备到上层应用的完整技术链路,其核心流程可归纳为四大模块:感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性,例如传感器选型需平衡精度与…...
