96SEO 2026-02-19 16:30 0
下载与安装教程STM32单片机编程软件_mdk528-CSDN博客

MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客
江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客
【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客
STM32学习笔记一基于标准库学习_电平输出推免-CSDN博客
定下计划开始学习下江协科技STM32课程接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32
事先说明在看本节之前最好要有51的基础因为本节很多内容都会省略不写没有51基础的学习者可以先去看看我之前在51单片机专栏介绍的I2C协议。
单片机学习笔记---AT24C02I2C总线_i2c应答-CSDN博客
在学I2C之前我们已经学习了串口通信。
串口通信就是从TX引脚向RX引脚发送数据流。
数据流以字节为单位我们可以组合多个字节变成多字节的数据包传输。
另外串口通信的设计是一条发送线一条接收线没有时钟线的异步全双工的协议这是我们学习串口通信的时候了解到的。
现在假如有个大公司找到了出资一千万要求给他设计一个通讯协议这个通讯协议是用来干什么的
大概是这样这个公司开发出来一款芯片可以干很多事情比如AD转换温湿度测量姿态测量等等。
像我们单片机一样这个芯片里的众多外设也都是通过读写寄存器来控制运行的。
寄存器本身也是存储器的一种这个芯片所有的寄存器也都是被分配到了一个线性的存储空间。
如果我们想要读写寄存器来控制硬件电路我们就至少需要定义两个字节数据。
一个字节是我们要读写哪个寄存器也就是指定寄存器的地址。
另一个字节就是这个地址下存储器存的内容。
写入内容就是控制电路读出内容就是获取电路状态。
这整个流程和我们单片机CPU操作外设的原理是一样的。
现在问题来了单片机读写自己的寄存器可以直接通过内部的数据总线来实现直接用指针操作就行不需要我们操心。
但是现在这个模块的寄存器在单片机的外面要是直接把单片机内部的数据总线拽出来把两个芯片合为一体可能不太现实。
所以现在这个大公司就找到了你要求给他设计一种通讯协议在单片机和外部模块连接少量的几根线实现单片机读写外部模块寄存器的功能。
这时你可能会想我们就用这个串口的数据包通信就可以完成任务。
比如我们就用Hex数据包定义一个三个字节的数据包从单片机向外挂模块发过去。
第一个字节表示读写发送0表示这是一个写数据包发送1表示这是一个读数据包。
第二个字节表示读写的地址。
第三个字节表示写入的数据。
0xAA。
这就表示在0x06地址下写入0xAA模块收到之后就执行这个写入操作。
如果发送数据包为0x010x060x00这就表示要读取0x06地址下的数据注意这个读的数据包第三个字节无效。
模块收到之后就要再给我发送一个字节返回0x06地址下的数据这样就行了是不是完成任
你认为这一千万已经到手了但是这个大公司对这个通讯协议的要求非常多。
第一个要求目前串口这个设计是一个需要两根通信线的全双工协议但是可以明显发现我们这个操作流程是一种基于对话的形式来进行的。
我们在整个过程中并不需要同时进行发送和接收发送的时候就不需要接收接收的时候就不需要发送这样就会导致始终存在一根信号线处于空闲状态这就是资源的浪费。
所以要求就是删掉一根通讯线只能在同一根线上进行发送和接收也就是把全双工变成半双工。
第二个要求我们这个协议并没有一个应答机制也就是单片机发送了一个数据对方有没有收到单片机是完全不了解的。
所以为了安全起见大公司要求增加应答机制要求每发送一个字节对方都要给个应答每接收一个字节也要给对方一个应答。
第三个要求大公司说这一根线只能接一个模块不太行他要求这一根线上能同时接多个模块。
单片机可以指定和任意一个模块通信同时单片机在跟某个模块进行通信时其他模块不能对正常的通信产生干扰。
第四个要求这个串口是异步的时序。
也就是发送方和接收方约定的传输速率是非常严格的时钟不能有过大的偏差也不能说是在传输过程中单片机有点事儿进中断了这个时序能不能暂停一下对于异步时序来说这是不行的。
单片机一个字节发一半暂停了接收方不知道他仍然会按照原来个约定的速率读取这就会导致传输出错。
必须要有USART电路才能方便地使用。
如果没有USART硬件电路的支持串口是很难用软件来模拟的。
虽然说软件模拟串口通信也是行得通的但是由于异步时序对时间要求很严格一般我们很少用软件来模拟串口通信。
所以这个大公司的要求是要把这个协议改成同步的协议另外加一条时钟线来指导对方读写。
由于存在时钟线对传输的时间要求就不高了。
单片机也可以随时暂停传输去处理其他事情。
因为暂停传输的同时时钟线也暂停了所以传输双方都能定格在暂停的时刻可以过一段时间再来继续不会对传输造成影响。
这就是同步时序的好处使用同步时序就可以极大的降低单片机对硬件电路的依赖。
即使没有硬件电路的支持也可以很方便的用软件手动翻转电平来实现通信。
比如我们之前51单片机里就没有I2C的硬件外设。
但是同样不影响51单片机进行软件模拟的I2C通信。
异步时序的好处就是省一根时钟线节省资源缺点就是对时间要求严格对硬件电路的依赖比较严重。
同步时序的好处就是反过来对时间要求不严格对硬件电路不怎么依赖。
在一些低端单片积没有硬件资源的情况下也很容易使用软件来模拟时序。
缺点就是多一根时钟线。
本节我们最基本的任务是通过通信线实现单片机读写外挂模块寄存器的功能。
其中至少要实现在指定的位置写寄存器和在指定的位置读寄存器这两个功能。
实现了读写寄存器就实现了对这个外挂模块的完全控制。
Data串行数据线满足设计要求一同步半双工满足设计要求一带数据应答满足设计要求二支持总线挂载多设备一主多从、多主多从满足设计要求三
挂载在I2C总线的所有外部模块都是从机从机只有被主机点名之后才能控制I2C总线不能在未经允许的情况下去碰I2C总线防止冲突。
多主多从的模型即在总线上任何一个模块都可以主动跳出来说接下来我就是主机你们都得听我的就像是在教室里老师正在讲课突然一个学生站出来说老师打断一下接下来让我来说所有同学听我指挥。
但是同一个时间只能有一个人说话这时就相当于发生了总线冲突。
在总线冲突时I2C协议会进行仲裁仲裁胜利的一方取得总线控制权失败的一方自动变回从机。
当然由于时钟线也是由主机控制的所以在多主机的模型下还要进行时钟同步。
多主机的情况下协议是比较复杂的大家感兴趣的可以自己去了解。
我们本课程仅使用一主多从的模型多主多从的部分不做要求。
之前学习51单片机时我们用的是AT24C02存储器模块来学习I2C现在STM32我们是用MPU6050模块来学习I2C协议的。
上图第一个图片就是我们套件里的MPU6050模块可以进行姿态测量使用了I2C通信协议。
第二个图片是我们套件里的OLED模块可以显示字符图片等信息也是I2C协议。
还有很多模块都支持I2C通信使用了这个通信协议对于开发者来说非常方便。
同样的协议在不同的硬件上操作方法都是极为相似的。
学会了其中一个硬件再学其他的硬件就很容易了
SCL应该好规定因为现在是一主多从主机拥有SCL的绝对控制权所以主机的SCL可以配置成推挽输出所有从机的SCL都配置成浮空输入或者上拉输入。
数据流向是主机发送所有从机接收这没问题但是到SDA线这里就比较麻烦了因为这是半双工的协议所以主机的SDA在发送的时候是输出在接收的时候是输入。
同样从机的SDA也会在输入和输出之间反复切换。
如果能协调好输入输出的切换时机其实也没问题。
但这样做如果总线时序没协调好极有可能发生两个引脚同时处于输出的状态。
如果这时又正好是一个输出高电平一个输出低电平这个状态就是电源短路板。
这个状态是要极力避免的。
所以为了避免总线没协调好导致电源短路这个问题。
I2C的设计是禁止所有设备输出强上拉的高电平采用外置弱上拉电阻加开漏输出的电路结构。
左边这一块是SCL的结构这里SCLK就是SCL的意思。
右边这一块是SDA的结构这里Data就是SDA的意思。
首先引脚的信号进来都可以通过一个数据缓冲器或者是斯密特触发器进行输入。
因为输入对电路没有任何影响所以任何设备在任何时刻都是可以输入的。
正常的推挽输出是这样的上面一个开关管接到正极下面一个开关管接到负极。
上面导通输出高电平下面导通输出低电平。
因为这是通过开关管直接接到正极和负极的所以这个是强上拉和强下拉的模式。
而开漏输出就是去掉这个强上拉的开关管输出低电平时下管导通是强下拉。
输出高电平时下管断开但是没有上管了此时引脚处于浮空的状态这就是开漏输出。
和上图示是一样的输出低电平这个开关管导通引脚直接接地是强下拉。
这样的话所有的设备都只能输出低电平而不能输出高电平。
为了避免高电平造成的引脚浮空这时就需要在总线外面SCL和SDA各外置一个上拉电阻这是通过一个电阻拉到高电平的所以这是一个弱上拉。
用我们之前的弹簧和杆子的模型来解释就是SCL或SDA就是一根杆子。
为了防止有人向上推杆子有人向下拉杆子造成冲突我们就规定所有的人不准向上推杆子只能选择向下拉或者放手。
然后我们再外置一根弹簧向上拉要输出低电平就往下拽这根弹簧肯定拽不赢你所以弹簧被拉伸杆子处于低电平状态。
要输出高电平就放手杆子在弹簧的拉力下回弹到高电平这就是一个弱上拉的高电平但是完全不影响数据传输。
第一完全杜绝了电源短路现象保证电路的安全。
所有人无论怎么拉杆子或者放手杆子都不会处于一个被同时强拉和强推的状态。
即使有多个人同时向下拉杆子也没问题。
第二避免了引脚模式的频繁切换。
开漏加弱上拉的模式同时兼具了输入和输出的功能。
要是想输出就去拉杆子或者放手操作杆子变化就行了。
要是想输入就直接放手然后观察杆子高低就行了。
因为开漏模式下输出高电平就相当于断开引脚所以在输入之前可以直接输出高电平不需要再切换成输入模式。
就是这个模式会有个“线与”的现象就是只要有任意一个或多个设备输出了低电平总线就处于低电平只有所有的设备都输出高电平总线才处于高电平。
I2C可以利用这个电路特征执行多主机模式下的时钟同步和总线仲裁。
所以这里SCL虽然在一组多从模式下可以用推挽输出但是它仍然采用了开漏加上拉输出的模式因为在多主机模式下会利用到这个特征。
SCL全程都是有主机控制的。
SCL低电平时主机或者从机SDA变换数据SCL高电平时从机或者主机读取数据。
起始和终止都是有主机产生的从机不允许产生起始和终止。
所以在总线空闲状态时从机必须始终双手放开不允许主动跳出来去碰总线。
如果允许的话就是多主机模型了我们暂时不讲多主机模型。
在发送一个字节的时候之前学的串口的时序是低位先行I2C是高位先行。
所有设备包括主机都始终处于输入模式当主机需要发送的时候就可以主动去拉低SDA。
而主机在被动接收的时候就必须先释放SDA不要去动它以免影响别人发送。
因为总线是线与的特征任何一个设备拉低的总线就是低电平如果接收的时候还拽着SDA不放手别人无论发什么数据总线都始终是低电平。
从流程上来看接收一个字节和发送一个字节是非常相似的。
区别就是发送一个字节是低电平主机放数据高电平从机读数据而接收一个字节是低电平从机放数据高电平主机读数据。
从机设备地址在I2C协议标准里分为七位地址和十位地址我们目前只讲七位地址的模式因为七位地址比较简单而且应用范围最广。
在每个I2C设备出厂时厂商都会为它分配一个七位的地址。
这个地址具体是什么可以在芯片手册里找到。
比如我们MPU6050这个芯片的七位地址是1101000。
之前我们学习AT24C02的七位地址是1010000。
一般不同型号的芯片地址都是不同的相同型号的芯片地址都是一样的。
如果有相同的芯片挂载在同一条总线怎么办这需要用到地址中的可变部分。
一般器件地址的最后几位是可以在电路中改变的比如MPU6050地址的最后一位就可以由这个板子上的AD0引脚确定这个引脚接低电平那它的地址就是1101
再比如AT24C02地址的最后三位都可以分别由这个板子上的A0、A1、A2引脚确定。
比如A0引脚接低电平地址对应的位就是0接高电平地址对应的位就是1。
A1、A2也同理。
一般I2C的从机设备地址的高位都是由厂商确定的低位可以由引脚来灵活切换。
这样即使相同型号的芯片挂载在同一个总线上也可以通过切换地址低位的方式保证每个设备的地址都不一样这就是I2C设备的从机地址。
从机地址是七位读写位是一位加起来是一个字节八位。
发送从机地址就是确定通信的对象发送读写位就是确认接下来是要写入还是要读出。
我们看到在读的时序中I2C协议的规定是主机进行寻址时一旦读写标志位给1了那下一个字节就要立马转为读的时序所以主机还来不及指定想要读哪个寄存器就得开始接收了。
所以这里就没有指定地址这个环节。
主机并没有指定寄存器的地址从机到底该发哪个寄存器的数据
这需要用到我们上面说的当前地址指针。
在从机中所有的寄存器被分配到了一个线性区域中。
并且会有个单独的指针变量指示着其中一个寄存器。
这个指针上电默认一般指向零地址。
并且每写入一个字节和读出一个字节后这个指针就会自动自增一次移动到下一个位置。
在调用当前地址读的时序时主机没有指定要读哪个地址从机就会返回当前指针指向的寄存器的值。
比如假设刚刚调用了这个指定地址写的时序在0x19的位置写入了0xAA那么指针就会加1移动到0x1A的位置接下来再调用这个当前地址读的时序返回的就是0x1A地址下的值。
如果再调用一次返回的就是0x1B地址下的值以此类推。
这就是当前地址读时序的操作逻辑由于当前地址读并不能指定读的地址所以这个时序用的不是很多。
指定地址读这个时序的目的就是对于指定设备在指定地址下读取从机数据。
我们看一下指定就是写在这前面一部分就是指定地址的时序。
我们把最后面的写数据的这一部分给去掉
然后把前面这一段设置地址还没有指定写什么数据的时序给它追加到这个当前地址读时序的前面
后面的部分是当前地址读因为我们刚指定的地址所以再调用当前地址读两者加在一起就是指定地址读了。
首先最开始仍然是启动条件然后发送一个字节进行寻址。
这里指定从机地址是1101000读写标志位是0代表要进行写的操作。
经过从机应答之后再发送一个字节第二个字节用来指定地址这个数据就写入到了从机的地址指针里了。
也就是说从机接收到这个数据之后它的寄存器指针就指向了ox19这个位置。
之后我们要写入的数据不给它发而是直接再来个起始条件。
SR的意思就是重复起始条件Start
Repeat相当于另起一个时序。
因为指定读写标志位只能是跟着起始条件的第一个字节所以如果想切换读写方向只能再来个起始条件然后起始条件后重新寻址并且指定读写标志位此时读写标志位是1代表要开始读了。
接着主机接收一个字节这个字节就是0x19地址下的数据这就是指定地址读。
因为写入的地址会存在地址指针里面所以这个地址并不会因为时序的停止而消失我们就可以再起始读当前位置停止这样两条时序也可以完成任务但是I2C协议官方规定的复合格式是一整个数据帧相当于把两条时序拼接成一条。
除了以上三个时序I2C还有这些时序的进阶版本。
目前指定地址写只是写一个字节当前地址读和指定地址读也都是读一个字节。
进阶版本就是指定地址写多个字节当前地址读多个字节和指定地址读多个字节时序上和以上三个时序都非常相似只需要增加一些小细节就行。
比如在这里指定地址然后写入一个字节如果只想写一个字节就停止就行了
比如重复三遍发送一个字节和接收应答。
这样第一个数据就写入到了指定地址0x19的位置写入一个数据后地址指针会自动加1变成0x1A所以这第二个数据就写入到了0x1A的位置。
同理第三个数据就写入的是0x1B的地址。
以此类推这样这个时序就进阶为在指定的位置开始按顺序连续写入多个字节。
比如需要连续写入多个寄存器就可以考虑这样来操作。
这样在一条数据帧就可以同时写入多个字节执行效率就会比较高。
然后同理当前位置读和指定位置读也可以多次执行这最后一部分时序由于地址指针在读后也会自增所以这样就可以连续读出一片区域的寄存器效率也会非常高。
⚠️⚠️⚠️⚠️注意如果只想读一个字节就停止的话在读完一个字节之后一定要给从机发个非应答。
非应答就是该主机应答的时候主机不把SDA拉低从机读到SDA为1就代表主机没有应答。
从机收到非应答之后就知道主机不想要继续了从机就会释放总线把SDA的控制权交还给主机。
如果主机读完仍然给从机应答了从机就会认为主机还想要数据就会继续发送下一个数据。
而这时主机如果想产生停止条件SDA可能就会因为被从机拽住了而不能正常弹回高电平。
如果主机想连续读取多个字节就需要在最后一个字节给非应答而之前的所有字节都要给应答。
我们可以按照硬件规定来连接线路用软件规定来操作总线依次实现指定位置写寄存器和指定位置读寄存器。
有了这两个功能主机就可以完全掌控外挂模块的运行了也就实现了我们设计这个协议的目的。
下节我们来了解MPU6050这个芯片看看它是怎样工作的有哪些寄存器以及如何利用寄存器控制硬件电路的运行。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback