使用 GD32F470ZGT6,手写 I2C 的实现

news2024/12/14 13:32:56

我的代码:https://gitee.com/a1422749310/gd32_-official_-code
I2C 具体代码位置:https://gitee.com/a1422749310/gd32_-official_-code/blob/master/Hardware/i2c/i2c.c
黑马 - I2C原理
官方 - IIC 协议介绍

个人学习过程中的理解,有错误,欢迎指出

移植

【I2C 具体代码位置】中,要更改代码的地方

#define SCL(bit) gpio_bit_write(GPIOB, GPIO_PIN_6, bit == 1 ? SET : RESET);
#define SDA(bit) gpio_bit_write(GPIOB, GPIO_PIN_7, bit == 1 ? SET : RESET);
#define DELAY()  delay_1us(5);

#define SDA_IN() gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
#define SDA_OUT() gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
#define SDA_STATE() gpio_input_bit_get(GPIOB, GPIO_PIN_7)

以及 
void I2C_Init()

其他地方,都是和平台无关的

写数据

SCL、SDA 数据的四种形式

在这里插入图片描述

在这里插入图片描述

SCL 和 SDA 的高低电平的持续时间是多少?

回答这个问题,需要涉及:I2C总线的时钟频率
I2C总线的时钟频率,通常在100kHz到400kHz之间,其中

  • 100kHz是标准模式(Standard Mode)
    • 1秒钟,就是 1 000 000us,100 000 个bit,相除,可得:10us 1bit
    • 👆 10us,才得到一个 bit,那么,睡眠的时候,就是 5us(一半,用于开始、停止的变化)
  • 400kHz是快速模式(Fast Mode)
    • 1秒钟,就是 1 000 000us,400 000 个bit,相除,可得:2.5us 1bit
      此外,I2C总线还支持更高速度
  • 高速模式(High Speed Mode):1MHz
  • 超高速模式(Ultra-Fast Mode):5MHz

因此,SCL 和 SDA 的高低电平的持续时间是多少?要看具体使用的 I2C 的外设的 datasheet
比如,如果某个 datasheet 上面写了 100kHz,那么,就是 10us 1bit,就 #define DELAY() delay_1us(5);

开始、结束、发送、等待响应总结

  • 开始(Start):正弦函数
  • 结束(Stop):左边有 1 竖(都是低电平)的【凹函数】
  • 发送(Send):SDA准备 🏃‍,持续3个delay;SCL 从暴富到破产(或者理解为跳水,但是,跳水,SDA 用了。 所以,可以这么理解:SCL,老板,指挥官,与财富相关,SDA,员工,行动派,与行为相关)
  • 等待响应(Wait ACK):SCL、SDA 亲亲😘;SCL 从暴富到破产,SDA 控制权转移
    👆 很奇怪,之前用【亲亲】,感觉不好意思🥵,于是改成【靠近】,后来发现,还是亲亲好,上头😓
    👇 可以看到,只有【开始】(绿点)和【结束】(橙点),有比较长的 SCL(上面的信号是 SCL)(也印证了SCL 连续高两次)
    在这里插入图片描述

懒得复制图片了,直接看这个链接吧 黑马 - IIC

1、开始 Start:【正弦函数】

[图片]

  • 1:SCL 之前,SDA,一定是高的,不然没法下落
  • 2:SCL,暴富,站起来了(起作用了)
  • 3:将 SDA 拉低
  • 4:SCL,破产,没落了,代表之后不起作用了(虎落平阳被犬欺)

买的淘宝链接(👈 LIXIN 给的链接,买贵了。。。)19.5 USB逻辑分析仪
黑马 - 逻辑分析仪
下载:逻辑分析仪Logic-2.4.9-windows-x64.exe

[图片]
[图片]

I2C 要进行配置 👇
[图片]
[图片]
[图片]

最终 👇,注意采样率,不要太低,我之前设置为 100kS/s,采样的波形,是错误的(当时没理解概念,将 100kS/s 和之前的 100kHz是标准模式 那个联系在一起了🤡。。。)
[图片]

2、结束 Stop:左边有 1 竖的【凹函数】

[图片]
[图片]
👆,这里,开始的 4 和结束的 1,共了

  • 1:SCL、SDA 同时变低,方便 SCL 站起来

  • 2:SCL,暴富,站起来了(起作用了)

  • 3:SDA,上岸(游泳🏊‍结束)
    static void stop() {
    SCL(0);
    SDA(0);
    DELAY(); // <— 视频中没有加 delay

    SCL(1);
    DELAY();

    SDA(1);
    DELAY();
    }

2.1、结束代码,有问题

👆 视频中代码有问题,没有加 delay
[图片]
[图片]
测试代码如下 👇,对应波形 👆
可以看到,stop 中,SCL(0)、SDA(0) 后,立马 SCL(1),在波形上,显示的是,是很窄的一个波形(👆 右图中,绿色,1、1 的框框)
另外,注意上面图片中,中间的区域,我将其设置为 11、00、11,目的是为了对比(之后 2.2 中,有关于对这个波形的讨论)
static void stop()
{
SDA_OUT(); // SDA 重新获得控制权,SDA 变成输出

SCL(0);
SDA(0);
// DELAY(); 未加 delay

SCL(1);
DELAY();

SDA(1);
DELAY();

}

void test_wave()
{
start();

// 中间
SCL(1);    SDA(1);    DELAY();

SCL(0);    SDA(0);    DELAY();

SCL(1);    SDA(1);    DELAY();

stop();

}
加上 delay 之后的波形 👇
[图片]
[图片]
所以我认为,虽然效果是一样,但是,还是加下好些

2.2、结束代码,有问题例子中,中间波形分析

// 中间
SCL(1); SDA(1); DELAY();

SCL(0); SDA(0); DELAY();

SCL(1); SDA(1); DELAY();
[图片]
[图片]
👆,并不是我之前认为的,SCL(1) 、SDA(1),波形就同时变高,而是有一个偏移(SDA,向右偏一点)
并且,SCL(1)、SDA(1),宽度也是不一样的

那么,如果我先设置 SDA 呢?
// 中间
SDA(1); SCL(1); DELAY();

SDA(0); SCL(0); DELAY();

SDA(1); SCL(1); DELAY();
[图片]

[图片]
👆 右图,因为 SDA 提前设置,所以,在 SCL 之前,变低(图中显示,红色在黄色,内部)

但是,之后,第 3 个 SDA(1); SCL(1);,预想中,应该是 SDA 先拉高,SCL 在拉高(可实际上,是 SCL 先拉高)
一种解释,是程序编译的时候,SDA(1); SCL(1); 交换了位置???那为什么 SDA(0); SCL(0); 没有交换?
所以,应该不是这个原因
另一种解释:SDA(1),SDA 拉高的时候,相比于 SCL(1) ,比较耗时,我认为这个是比较合理一点的解释

问下 ChatGPT
你的分析非常到位!让我们一起深入探讨你提出的两个可能的解释:

  1. 程序编译时的代码顺序
    这种解释是比较不太可能的原因。在编译阶段,SDA(1) 和 SCL(1) 的顺序应该是严格按照程序中写的顺序执行的,编译器并不会自动交换这些信号的顺序,除非有特别的宏或硬件抽象层对这些函数做了特殊的处理。所以,SDA(1) 和 SCL(1) 顺序交换的问题,可以排除。
  2. SDA 拉高的耗时问题
    这个解释是比较合理的。
  • SDA 拉高时的时间问题:由于 I2C 总线的物理特性,SDA 线上的信号变化相对较慢,尤其是在高电平拉升时。如果你直接将 SDA 设置为高电平,可能需要一点时间来使 SDA 线达到稳定的高电平状态。而 SCL 线在此时是由外部的时钟拉升的,这意味着如果没有延时,SCL 会很快拉高,但 SDA 可能还没有达到稳定的高电平,导致了信号的不稳定或者错误。
  • SCL 的变化时间较短:SCL 线的状态变化通常由外部时钟控制,所以其变化速度通常比较快。而 SDA 由于是由主设备控制,并且存在内部拉升电阻或者其他电路因素,所以 SDA 的拉高通常会稍微慢一些,尤其是在低电平拉升到高电平时,可能会有延迟。
    为什么 SDA(0); SCL(0); 没有问题?
    当你将 SDA 和 SCL 都拉低时,情况就简单了。因为 I2C 的标准定义在 SDA 和 SCL 都为低电平时,它们处于稳定状态,几乎没有信号的延迟或时序问题。所以 SDA(0); SCL(0); 不会引起问题。
    总结:
    更可能的原因是 SDA 拉高时的时间延迟。 由于 SDA 拉高的过程相较于 SCL 更加耗时,可能会导致在 SDA(1) 和 SCL(1) 同时设置时,SCL 先拉高了,而 SDA 还没有完全稳定。
    3、发送 Send:SDA准备,持续3个delay;SCL 从暴富到破产
    [图片]
    [图片]
  • 1:SDA 准备了
  • 2:SCL,暴富,站起来了(起作用了)
  • 3:SCL,破产,没落了,代表之后不起作用了(虎落平阳被犬欺)
    👆,可以看到,起作用的传输数据,持续了 3 的 delay(准备前、SCL 变高时、SCL 变低时)

4、等待响应 Wait ACK:SCL、SDA 亲亲😘;SCL 从暴富到破产,SDA 控制权转移
[图片]
[图片]

  • 1:SCL、SDA 亲亲😘:SDA 变高,期望跳水;;;SCL 变低,破产,期望暴富,起作用,站起来
  • 2:SCL 高电平,站起来了(起作用了),此时,SDA,已经让出控制权了,然后,观察 SDA
    • SDA:低电平,代表应答
    • SDA:高电平,代表不应答
    • SDA,代表了,主动权
  • 3:SCL,没落了,代表之后不起作用了(虎落平阳被犬欺)

模拟下成功,然后看看波形
模拟的时候,不要开 SDA_IN,会影响波形
static void wait_ack()
{
SDA(1);
SCL(0);
DELAY();

#if MOCK_WAIT_ACK_SUCCESS == 0
// SDA 交出控制权,SDA 变为输入
SDA_IN();
#endif

SCL(1);

#if MOCK_WAIT_ACK_SUCCESS
// 模拟从机,将 SDA 置 1,代表成功响应主机
SDA(0);
#endif
DELAY();

if (RESET == SDA_STATE() || 1 == MOCK_WAIT_ACK_SUCCESS)
{
   // 成功
   SCL(0);
   SDA_OUT();  // SDA 重新获得控制权,SDA 变成输出
}
else
{
   stop();
}

}
最终波形如下 👇
[图片]

[图片]


read
rece 和 send 通讯信号都是一样的,但是区别:SDA 的信号来源,来自:从设备
[图片]

发送响应:SCL、SDA 开始:ACK 不亲亲🫸,NACK 亲亲😘;SCL 从暴富到破产;最后都亲亲😘
[图片]
[图片]

最后,I2C_Read(0x01, 0x02, &data, 1);(后面 len 改为 2,可以分析 ACK) 输出波形如下
[图片]

[图片]
[图片]
[图片]
可以看到,接收,只有 1、2 —— 设置,是在 SCL(0) 的时候,设置的

模拟代码如下 👇,1011 0010 = 0xB2,和波形一致
#define MOCK_READ_DATA 1

static uint8_t recv()
{
#if MOCK_READ_DATA == 0
// SDA 交给从设备,主设备,应该是输入状态
SDA_IN();
#endif

#if MOCK_READ_DATA
// 1011 0010 = 0xB2
uint8_t mock_bit_array[8] = {1, 0, 1, 1, 0, 0, 1, 0};
#endif

uint8_t data = 0;
for (uint8_t i = 0; i < 8; i++)
{
   // 给机会,给从设备,准备数据
   SCL(0);

#if MOCK_READ_DATA
SDA(mock_bit_array[i]); // <— 设置,是在 SCL(0) 的时候,设置的
#endif
DELAY();

   // 开始设置数据有效性
   SCL(1);

#if MOCK_READ_DATA
data |= mock_bit_array[i] << (7 - i);
#else
data |= SDA_STATE() << (7 - i);
#endif

   DELAY();

   // SCL(0); 因为下一个循环,还是低电平,这里可以省略
}
// 最后一次,是高电平,不会循环回来,所以,要加上低电平,代表 SCL 没落了
SCL(0);

return data;

}

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

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

相关文章

【Unity踩坑】Unity生成iOS的XCode项目时提示错误:xcrun: error: SDK “iphoneos“ cannot be located

问题描述&#xff1a; Unity生成iOS的Xcode项目时&#xff0c;出现错误&#xff1a;xcrun: error: SDK “iphoneos” cannot be located 解决方法&#xff1a; 运行Xcode, 打开设置-Locations&#xff0c;将Command Line Tools里下拉项再选择一下。&#xff08;不管之前有没有…

用前端html如何实现2024烟花效果

用HTML、CSS和JavaScript编写的网页&#xff0c;主要用于展示“2024新年快乐&#xff01;”的文字形式烟花效果。下面是对代码主要部分的分析&#xff1a; HTML结构 包含三个<canvas>元素&#xff0c;用于绘制动画。引入百度统计的脚本。 CSS样式 设置body的背景为黑…

React的状态管理库-Redux

核心思想&#xff1a;单一数据源、状态是只读的、以及使用纯函数更新状态。 组成部分 Store&#xff08;存储&#xff09; 应用的唯一状态容器&#xff0c;存储整个应用的状态树,使用 createStore() 创建。 getState()&#xff1a;获取当前状态。dispatch(action)&#xff…

Unity WebGL 编译和打包说明(官方文档翻译校正)

目录 Unity WebGL 编译和打包说明WebGL 简介WebGL 浏览器兼容性 (WebGL Browser Compatibility)平台支持 (Platform Support)多线程支持限制多线程支持的因素安装 Unity Hub 并添加所需模块WebGL 开发WebGL Player 设置Resolution and PresentationResolutionWebGL TemplateSpl…

论文概览 |《IJGIS》2024.11 Vol.38 issue11

本次给大家整理的是《International Journal of Geographical Information Science》杂志2024年第38卷第11期的论文的题目和摘要&#xff0c;一共包括9篇SCI论文&#xff01; 论文1 A review of crowdsourced geographic information for land-use and land-cover mapping: cur…

Linux系统编程——进程间通信

目录 一、前言 二、进程间通信的目的 三、进程通信的方法 四、管道 通信 1、进程如何通信 2、管道概念 3、匿名管道 1&#xff09;理解 2&#xff09;匿名管道的创建 3&#xff09;匿名管道用途——控制进程 4&#xff09;匿名管道对多个进程的控制 5&#xff09;总…

Ensembl数据库下载参考基因组(常见模式植物)bioinfomatics 工具37

拟南芥参考基因组_拟南芥数据库-CSDN博客 1 Ensembl数据库网址 http://plants.ensembl.org/index.html #官网 如拟南芥等 那么问题来了&#xff0c;基因组fa文件和gff文件在哪里&#xff1f; 2 参考案例 拟南芥基因组fa在这里 注释gff文件在这里

linux-16 关于shell(十五)date,clock,hwclock,man,时间管理,命令帮助

想显示一下当前系统上的时间该怎么显示&#xff1f;有一个命令叫做date&#xff0c;来看date命令&#xff0c;如下图&#xff0c; 第一个星期几对吧&#xff1f;然后是月日小时分钟秒&#xff0c;最后一个是年对吧&#xff1f;CST指的是它的时间格式&#xff0c;我这个可以先姑…

SMMU软件指南SMMU编程之寄存器

安全之安全(security)博客目录导读 本博客介绍了SMMUv3的编程接口&#xff1a; • SMMU寄存器 • 流表&#xff08;Stream table&#xff09; • CD&#xff08;Context Descriptor&#xff09; • 事件队列&#xff08;Event queue&#xff09; • 命令队列&#xff08;…

Windows环境基于ecplise的spring boot框架新建spring start project

SpringToolSuite4 新建项目实例 前言Windows基于ecplise 工具的spring boot 架构 前言 使用Spring boot 框架向前端传输数据 Windows基于ecplise 工具的spring boot 架构 spring-tool-suite-4官网下载链接spring tool&#xff0c;下载太慢的话可以使用迅雷加速&#xff0c;右…

26. Three.js案例-自定义多面体

26. Three.js案例-自定义多面体 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染场景的主要类。它支持 WebGL 渲染&#xff0c;并提供了多种配置选项。 构造器 new THREE.WebGLRenderer(parameters) 参数类型描述parametersObject可选参数对象&…

OSCP - Proving Grounds - DC-4

主要知识点 密码爆破潜在的包含密码的文件搜索在/etc/passwd 插入新用户提权 具体步骤 首先执行nmap 扫描&#xff0c;比较直接&#xff0c;80和22端口&#xff0c;22端口虽然有vulnerability,但是对咱们目前的情况来讲没有太大的帮助&#xff0c;主要关注一下80端口 Start…

【ubuntu24.04】PDFMathTranslate 本地PDF翻译GPU部署

https://huggingface.co/spaces/reycn/PDFMathTranslate-Docker排不上号官方都是要安装包,感觉可以本地试着源码部署一下, http://localhost:7860/官方是这个端口,但是我本地启动是:5000IDEA 里本地 backend启动效果 GUI 是监听7860的

汽车零部件设计之——发动机曲轴预应力模态分析仿真APP

汽车零部件是汽车工业的基石&#xff0c;是构成车辆的基础元素。一辆汽车通常由上万件零部件组成&#xff0c;包括发动机系统、传动系统、制动系统、电子控制系统等&#xff0c;它们共同确保了汽车的安全、可靠性及高效运行。在汽车产业快速发展的今天&#xff0c;汽车零部件需…

基于Llamaindex的网页内容爬取实战

目的 本文不关注如何解析网页 html 元素和各种 python 爬虫技术&#xff0c;仅作为一种网页数据的预处理手段进行研究。Llamaindex 也并不是爬虫技术的集大成者&#xff0c;使用它是为了后续的存查一体化。 安装依赖 pip install llama-index-readers-web # pip install llam…

CityEngine实践——常用cga文件解析系列(2)

上回书说到了&#xff1a; 3、RULES/COMPONENTS/MASSING/SUBURBAN_BLOCK DETACHED_HOUSES.CGA ROWHOUSES.CGA SEMI_DETACHED_HOUSES.CGA 4、RULES/COMPONENTS/MASSING/URBAN_BLOCK MONOBLOCK.CGA PERIMETER_8_SHAPE.CGA PERIMETER_MULTIPART.CGA 这个cga挺有意思&#xff0c…

[64]最小路径和⭐

[64]最小路径和⭐ 题目描述 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 **说明&#xff1a;**每次只能向下或者向右移动一步。 示例输入 示例 1&#xff1a; 输入&#xff1a;grid …

MATLAB中circshift函数的原理分析——psf2otf函数的核心

之所以讲到MATLAB中circshift函数&#xff0c;也是源于Rafael Gonzalez的这个图&#xff0c;作为前几篇答廖老师问的blog的基础。 Rafael Gonzalez的这个图无论从哪幅图到哪幅图都不是直接的傅里叶变换或傅里叶逆变换&#xff0c;需要循环移位&#xff0c;即circshift函数。 这…

LightningChart JS助力德国医疗设备商打造高精度肺功能诊断软件

项目背景&#xff1a; GANSHORN Medizin Electronic GmbH公司在德国开发、生产和销售肺功能诊断设备已有 40 多年历史&#xff0c;该公司专注于肺功能的可视化&#xff0c;其创新医疗技术通过开发先进的肺量测定测试、肺扩散分析和人体肺量测定测试解决方案取得了突破。GANSHO…

ssm-springmvc-学习笔记

简介 简单的来说&#xff0c;就是一个在表述层负责和前端数据进行交互的框架 帮我们简化了许多从前端获取数据的步骤 springmvc基本流程 用户在原本的没有框架的时候请求会直接调用到controller这个类&#xff0c;但是其步骤非常繁琐 所以我们就使用springmvc进行简化 当用…